Saturday, December 09, 2006
The YAGNI Application Server
Everybody knows about the You Ain't Gonna Need It principle, aka YAGNI, in software development. When developing some component one should never add methods that you don't need right now in another component that depends on the component under development. Although it's very tempting to start elaborating on the EJB3 entities and data access objects (DAOs) since it's a direct mapping from your beautiful domain model to Java, one should save its gun powder until the real battle pops up. This implies a top-down approach when adding a new feature to your application. You start from your user interface's view component (hopefully for you a Facelets JSF page) and add some methods to the connected control component (again, hopefully for you a Seam EJB3 bean). From within this bean you enter other EJB3 components representing the domain model in one way or another. Of course during development you always keep your domain model in mind and try to evolve the current implemented model towards your ultimate theoretical domain model, but always respect the twists that reality imposes on the theoretical domain model by means of your walking skeleton application.
YAGNI makes sense when applied to software development, i.e., when applied to code you write yourself. Never apply YAGNI to the selected frameworks on which your application will be build. If you need to shoot down a fly, take the cannon. Of course you just put enough gun powder in the cannon to shoot down the fly. But make sure that it's a cannon that you're learning to control, since you never know what will show up next on the radar screen.
Applied to software development, run enterprise applications in enterprise containers like JBoss Application Server. Else you end up in a situation that I could witness a few years ago. On this project the lead developer also applied YAGNI to the framework selection. So at the beginning of the project (that was about developing a highly distributed SOA product) there was no need for a container at all since there was only one component, x.y.z.Main with one method called main. So plain J2SE could do the trick. Of course after a while dependency injection would be a nice framework feature to have, since manual injection was boring. So Nanocontainer was introduced into the project. It worked, and was perfectly inline with the YAGNI-principle. After a while we needed role-based access control (RBAC). No problem here, via DynAOP that would be used with Nanocontainer, we would write our own security aspect, which was doing something similar to @RolesAllowed("user"). Believe me, this was really cool to write. And then after a while we needed transaction support. No problem here, again we would write our own transaction aspect, which was emulating @TransactionAttribute(TransactionAttributeType.REQUIRED). A little later in the project we also needed some of the other TransactionAttributeType semantics (TransactionAttributeType.REQUIRES_NEW), and we also needed to make the messaging part of the transaction (something like JMS using a ConnectionFactory field annotated with @Resource(mappedName="java:/JmsXA")) to prevent certain data races. At that point we already had something I call the YAGNI Application Server that was hosting our application. Basically we could, besides selling our application, also start selling our YAGNI Application Server. This was a great team of developers since, for the price of one product, we achieved to construct two products. Of course the YAGNI Application Server was missing some features like elaborate transaction support and transacted messaging and was not really according to some standard specifications. Another big missing feature was J2EE deployability. Because different technologies were mixed and glued together that were not designed to fit together in the first place, we had to write endless scripts to deploy and start the YAGNI Application Server. Initially relative simple Bash scripts were used for this, together with a Groovy script to manage the configuration of the application. But since the proxy-client also wanted our application to run on Windows, the lead developer then introduced a hugh amount of Ruby scripts into the project. He started to model the entire deployment domain in Ruby. After a while the Ruby deployment and integration test framework was as complex as the application itself. To keep focussed on the application itself, and not on the YAGNI Application Server product, we decided to switch over to the JBoss Application Server that has all of these features out of the box.
Now here the lead developer came up with an even more funny proposal. We were not going to rewrite the components out of which our application consisted, oh no, we were going to make the YAGNI Application Server to run within the JBoss Application Server. This was called phase one. As it was a highly Agile project the goal was to always have a "working" system. Heh, this reminds me of a one-liner of one of our fellow developers: Agile software development, it's like fuck first, then think about it. Although I strongly believe in an Agile approach, one should consume it with certain moderation, like with beer or women. Now, during the second phase we were going to rewrite every aspect of the YAGNI Application Server, like for example the transaction aspect, to use the JBoss Application Server transaction manager. The 3th phase would be a rewrite of the YAGNI Application Server aspect interface to look exaclty like the JBoss Application Server aspect from a point of view of the application components. And during the last phase we would remove the YAGNI aspect components from between the application components and the JBoss Application Server. This is where I learned to argue against bad ideas.
This project is where I also learned to appreciate the JBoss Application Server. Besides being a J2EE container, it also offers a nice JMX-based architecture which allows you to manage deployability of your applications over JMX and this all from within Java itself. So there was no longer a need to mix Bash, Ruby, Groovy, Jelly and Java. We could now drive the entire build (Maven2) and deployment process (JMX) from within one language: Java. This is a principle they even already understood at Microsoft: use one language for everything.
I own a lot to this lead developer. This guy learned me all about how to organize projects. The company for which we were developing this product was at that time unfortunately in a situation that had a big impact on some of us. Never leave behind a broken window, I guess.
YAGNI makes sense when applied to software development, i.e., when applied to code you write yourself. Never apply YAGNI to the selected frameworks on which your application will be build. If you need to shoot down a fly, take the cannon. Of course you just put enough gun powder in the cannon to shoot down the fly. But make sure that it's a cannon that you're learning to control, since you never know what will show up next on the radar screen.
Applied to software development, run enterprise applications in enterprise containers like JBoss Application Server. Else you end up in a situation that I could witness a few years ago. On this project the lead developer also applied YAGNI to the framework selection. So at the beginning of the project (that was about developing a highly distributed SOA product) there was no need for a container at all since there was only one component, x.y.z.Main with one method called main. So plain J2SE could do the trick. Of course after a while dependency injection would be a nice framework feature to have, since manual injection was boring. So Nanocontainer was introduced into the project. It worked, and was perfectly inline with the YAGNI-principle. After a while we needed role-based access control (RBAC). No problem here, via DynAOP that would be used with Nanocontainer, we would write our own security aspect, which was doing something similar to @RolesAllowed("user"). Believe me, this was really cool to write. And then after a while we needed transaction support. No problem here, again we would write our own transaction aspect, which was emulating @TransactionAttribute(TransactionAttributeType.REQUIRED). A little later in the project we also needed some of the other TransactionAttributeType semantics (TransactionAttributeType.REQUIRES_NEW), and we also needed to make the messaging part of the transaction (something like JMS using a ConnectionFactory field annotated with @Resource(mappedName="java:/JmsXA")) to prevent certain data races. At that point we already had something I call the YAGNI Application Server that was hosting our application. Basically we could, besides selling our application, also start selling our YAGNI Application Server. This was a great team of developers since, for the price of one product, we achieved to construct two products. Of course the YAGNI Application Server was missing some features like elaborate transaction support and transacted messaging and was not really according to some standard specifications. Another big missing feature was J2EE deployability. Because different technologies were mixed and glued together that were not designed to fit together in the first place, we had to write endless scripts to deploy and start the YAGNI Application Server. Initially relative simple Bash scripts were used for this, together with a Groovy script to manage the configuration of the application. But since the proxy-client also wanted our application to run on Windows, the lead developer then introduced a hugh amount of Ruby scripts into the project. He started to model the entire deployment domain in Ruby. After a while the Ruby deployment and integration test framework was as complex as the application itself. To keep focussed on the application itself, and not on the YAGNI Application Server product, we decided to switch over to the JBoss Application Server that has all of these features out of the box.
Now here the lead developer came up with an even more funny proposal. We were not going to rewrite the components out of which our application consisted, oh no, we were going to make the YAGNI Application Server to run within the JBoss Application Server. This was called phase one. As it was a highly Agile project the goal was to always have a "working" system. Heh, this reminds me of a one-liner of one of our fellow developers: Agile software development, it's like fuck first, then think about it. Although I strongly believe in an Agile approach, one should consume it with certain moderation, like with beer or women. Now, during the second phase we were going to rewrite every aspect of the YAGNI Application Server, like for example the transaction aspect, to use the JBoss Application Server transaction manager. The 3th phase would be a rewrite of the YAGNI Application Server aspect interface to look exaclty like the JBoss Application Server aspect from a point of view of the application components. And during the last phase we would remove the YAGNI aspect components from between the application components and the JBoss Application Server. This is where I learned to argue against bad ideas.
This project is where I also learned to appreciate the JBoss Application Server. Besides being a J2EE container, it also offers a nice JMX-based architecture which allows you to manage deployability of your applications over JMX and this all from within Java itself. So there was no longer a need to mix Bash, Ruby, Groovy, Jelly and Java. We could now drive the entire build (Maven2) and deployment process (JMX) from within one language: Java. This is a principle they even already understood at Microsoft: use one language for everything.
I own a lot to this lead developer. This guy learned me all about how to organize projects. The company for which we were developing this product was at that time unfortunately in a situation that had a big impact on some of us. Never leave behind a broken window, I guess.