Wednesday, August 10, 2011

Premature Optimization is not Agile or should I say it is Evil

The team was having an issue after introducing JPASecurity in the project. Some feature suddenly broke so it must be JPASecurity which is buggy, still in its early phase, ...

Come on, this was working before so ...

Well the fact that your code is working does not mean it is correct. An Abstract class cannot be instantiated but with so much Dependency Injection and Inversion Of Control sometimes we lose control LOL.

An Abstract class is not to be used by any other than implementing classes. But what happens if the developer declares the class abstract and after that uses it as a JPA Entity? Of course this is a mistake, a common mistake I would say where the engineer thinks he is comming up with a great design that will save our lifes in the future, some kind of generalization up front that will address all details in the future, the silver bullet or a synonym (not about performance but about feature implementation) of what the Industry knows as Premature Optimization.

The class is declared Abstract and there is not a single implementation of it but somehow JPA Hibernate EntityManager.merge(Entity) will not complain (Probably because after all it uses a proxy and not the actual class). All goes "good" until one day when you actually try to use reflection on the entity for example if you introduce JPASecurity to provide ACL in your JPA entities.

At this point you will end up with exceptions like:
java.lang.SecurityException: java.lang.InstantiationException
 at net.sf.jpasecurity.util.ReflectionUtils.throwThrowable(ReflectionUtils.java:109)
 at net.sf.jpasecurity.util.ReflectionUtils.newInstance(ReflectionUtils.java:38)
 at net.sf.jpasecurity.mapping.DefaultClassMappingInformation.newInstance(DefaultClassMappingInformation.java:216)
 at net.sf.jpasecurity.entity.EntityPersister.createUnsecureObject(EntityPersister.java:250)
 at net.sf.jpasecurity.entity.AbstractSecureObjectManager.getUnsecureObject(AbstractSecureObjectManager.java:140)
 at net.sf.jpasecurity.entity.EntityPersister.getUnsecureObject(EntityPersister.java:240)
 at net.sf.jpasecurity.entity.EntityPersister.merge(EntityPersister.java:73)
 at net.sf.jpasecurity.persistence.DefaultSecureEntityManager.merge(DefaultSecureEntityManager.java:130)
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
 at java.lang.reflect.Method.invoke(Method.java:597)
 at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:365)
 at $Proxy1122.merge(Unknown Source)
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
 at java.lang.reflect.Method.invoke(Method.java:597)
 at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:240)
 at $Proxy1013.merge(Unknown Source)
 at com.nestorurquiza.dao.CrudDaoImpl.update(CrudDaoImpl.java:105)
 at com.nestorurquiza.service.impl.CrudServiceImpl.update(CrudServiceImpl.java:45)
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
 at java.lang.reflect.Method.invoke(Method.java:597)
 at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:309)
 at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
 at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
 at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)
 at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
 at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
 at $Proxy1037.update(Unknown Source)

This is most likely because the proxy does not implement the default contructor in which case the Abstract class is the one attempted to be instantiated originating the Exception.

But the bottom line of this post is to serve as a little bit of education to those young fellas who are catching up with programming and those experienced ones that love over bloated Enterprise Design up front.

Please guys, try to keep it simple and do not fear refactoring. Embrace change and hard work. You will find yourself applying patterns as a result of pragmatism rather than as a result of that new cool design you learned from GOF alike book on Patterns.

No comments:

Followers