Achieving better object oriented design and ability to use TDD by using Lightweight containers.
by Igor Stoyanov.
Many J2EE web applications contain too much code in the web tier. There are various reasons for this, but I think the most important are:
- Too few books emphasize the importance of a thin web tier. There are many books discussing MVC frameworks, emphasizing on the importance of properly designed web tier, separating control logic from presentation logic but much less of how the web tier should related to the rest of the application.
- There are many web frameworks but there’s no framework for business objects.
- Putting business logic in the web tier is often perceived as the quickest path to a solution. The previous point helps to understand the cause of this common misconception. However, it is a misconception, as working with a more sophisticated architecture will quickly show.
Until recently, the only framework that addresses partially some of these issues was EJB. Although, there are many problems and complexity related to using EJB, this was the primary framework for managing business tier objects. There are many nice thing specified in EJB such as declarative transaction in container management of business object, scalable remote architecture, very fine grained declarative security. However, the complexity of implementation, problems with performs in some cases, difficulties to test and too much overhead form majority of J2EE applications cause the emergence of lightweight container for managing business transaction.
The most popular lightweight containers are Spring framework, Pico container and HaveMind. These lightweight containers take some of the successful ideas from EJB to bring a greater level of sophistication to non-EJB architectures. They are similar to EJB arhcitecures in being centered around a layer of managed business service object. However, this is where the similarity ends. Instead of running inside an EJB container, business objects run inside a lightweight container. Lightweight containers aren’t tied to J2EE, have negligible startup cost and eliminate the deployment step of EJB.
The beauty of lightweight containers is that the business objects that they manage are POJO running inside of the containers. They are managed via AOP interception to deliver enterprise services. Unlike EJBs, they don’t usually need to depend on container APIs, meaning that they are also usable outside any container.
All these factors make lightweight containers the preferable choice if using Agile Methodologies together with TDD. According to agile, the design and implementation should be driven by the business requirements not by unnecessary complex specifications that have to be implemented. According to TDD, this is currently the only choice in order to achieve superior design and quality of the software application. This is of course if you have the freedom to choose technologies to work with.
I will look more closely at the currently most advanced lightweight container – Spring Framework. There are so many things that Spring Frameworks provides to make development easier that it is very hard to be described or summarized. I will talk about the most important of ones:
- Interface-implementation Separation
EJB enforces a separation between interface (component interface of business methods interface) and implementation (bean implementation class). This is actually one of the best things in EJB, as programming against interfaces rather than classes is a best practice with many beneficial consequences, such as “pluggability”.
Most lightweight containers do not enforce such a separation. However, they do recommend doing it, but in my experience, giving more freedom to developers doesn’t always provide better results. At least in this situation, I would rather prefer EJB approach of enforcing implementation against interfaces.
- Inversion of Control (IoC)
Most business objects have dependencies, such as other business objects, data access objects and resource. Because of that, there is a need to look up other managed object and resource, and therefore must dependent on a container to satisfy that. In satisfying this look up services lies the major difference between EJBs and lightweight containers as Spring framework. Both architectures achieve this look up service by Inversion of Control (IoC). The difference is that EJB architecture implements IoC with Dependency Lookup opposed to Spring framework, which implements IoC with Dependency Injection.
- Declarative Transaction Management
This is almost similar to EJBs architecture. The difference is that Spring frameworks provides much finer grained transaction management and much more flexibility in specifying transaction strategy.
The next diagram illustrates a typical Spring framework web application architecture. The Spring architecture is conceptually similar to the “local EJB architecture”. However, it tends to work out very differently in Practice.
Reference:
Example application using Strust and Spring could be found at:
http://www.onjava.com/pub/a/onjava/excerpt/BFLJava_chap8/
Explanation of how Spring handles multithreading at (very good):
http://www.javalobby.org/articles/thread-safe/index.jsp
Example simple application using Strust+Spring+Hibernate(should probably start from here):
http://www.onjava.com/pub/a/onjava/2004/04/07/wiringwebapps.html?page=1
Many useful materials can be found at AppFuse project:
http://raibledesigns.com/wiki/Wiki.jsp?page=AppFuse
Of course, there are lots of materials and examples at www.springframework.org
Impact of Test Driven Development together with test automation on the software design.
I have already mentioned test driven development (TDD) in previous post on this blog. This is often also referred to as test first development.I am TDD practitioner myself, and recommend it highly. Although, some of the other XP techniques can be strongly debatable, I believe that TDD development and continues integrations are mandatory methodologies for the success of a software project today. From being the poor cousin of development, the unit testing - has become welcomed as the heart of the software development.
It is not the most intuitive thing to test something that doesn’t exist. In order to become comfortable with TDD you should start practicing with full believe and fully apply this methodology. Very soon, the benefit would be very obvious. It is simple concept, but I need some working example in order to fully realize the power of TDD approach.
I will briefly summarize the most important steps in TDD development and demonstrate a very simple example.
The most important characteristic in TDD are:
Before a demonstration of TDD with a simple test case, I want to mention here that in order for TDD to have the desired effect, developers should create pure unit test. The most popular and sufficient Java framework is JUnit. The design and the decision for technologies that will be used should be strongly impact by the fact whether it is easily testable and in some cases, if it is testable at all. I want to add immediately here that no test can prove full coverage and suffice by itself for good testing approach to a particular application. A TDD development implies that developers are mainly involved in unit testing, also known as white testing. Continues integration testing and rigorous functional testing are invaluable testing approaches but they should not be primarily responsibility of developers.
As a practitioner of TDD I wouldn’t choice working with EJB technology if I have other valuable alternatives. EJB are managed during runtime by EJB container. Its development is not only very complex but it very hard, and in some cases (Entity Beans) it is almost impossible to test, not to mention that TDD is unthinkable. Attempts are made to solve this problem with EJB mocks, which is not very successful and using in container testing frameworks as Cactus. Although, using Cactus is irreplaceable for integration in container testing of EJB, it can not be used for pure unit testing. As I mentioned before, unit testing should provide very fast feedback to a developer in order to be useful. Using cactus as unit testing implies that for testing of even single method, we should wait for deployment and very complex initializing operations of the targeted container before we have a feedback. Not to mention the complexity of setting up Cactus framework on the firs place.
TDD demonstration:
Requirements:
Business functionality: Withdrawal
Can anticipate: - Refusing access to data storage
- Insufficient Funds in the account
Prerequisites: - There is an existing account (I am really hoping for. J.)
- The account can accept deposits.
- The account knows the current balance.
Targeted test code:
public class BankAccountTest extends TestCase {
private BankAccount account;
protected void setUp() throws Exception {
account = new BankAccount();
}
public void testValidWithdrawalSuccedsWithinLimit() throws DataAccessException,
InsuffiecientFundsException {
account.setBalance(45.0);
account.withdrawal(20.0);
assertEquals(25.0, account.getBalance());
}
public void testNotValidWithdrawalFailOutsideLimit() throws DataAccessException{
try {
account.setBalance(45.0);
account.withdrawal(46.0);
fail("Bank should have rethrown InsufficientFundsExcepiton");
}catch(InsuffiecientFundsException ex) {
assertEquals("Correctly calcualted amount fo unapproved overdraft",1.0, ex.getShorfail());
}
}
}
Agile methodologies are alternative approach to the traditional Engineering Methodologies. The most immediate difference is that they are less document-oriented, usually emphasizing a smaller amount of documentation for a given task. In many ways they are rather code-oriented: following a route that says that the key part of documentation is source code. However, a more precise picture could be drawn with a short excerpt from the article “The New Methodology” written by one of the founders of Agile Manifesto, Martin Fowler:
The rest of this article is invaluable information about Agile Methodologies and there are many references to related links and materials. I will strongly suggest reading this article if you are interested in Agile Methodologies.
Agile development is characterized mainly by using two to four weeks iterations. In the beginning of every iteration, the team commits to deliver some number of story cards. A story card is similar to the user cases defined in traditional software engineering process. The main and very essential difference that story cards has limited set of functionality so that the team can deliver it at the end of the iteration. Furthermore, everything in the story card should be driven by the business requirements.
A strong principle of eXtreme Programming (XP) is the continuous integration aspect (see the Continuous Integration article by Martin Fowler). The traditional approach to the development of complex software has been to separate the development process into phases of coding, testing and integration. The continuous integration principle is to basically code, test and integrate at the same time, so that at almost any point in time, you have a working product.
In order to achieve this, you need to be able to automatically build your entire application, including running the unit and acceptance tests. Thus, tools such as Ant or Maven are the foundation for continuous integration.
Certainly, you need an actual unit testing framework to start with. I would not surprise anybody by choosing JUnit test framework for my unit testing frame work. It is so widely known and used that everything that I could say would be redundant. The only thing that I would like to add, although it is said by many other is that this framework is really very easy to understand and to use it.
The elegance comes when JUnit is integrated with Ant. This is the first step of achieving continuous integration. Actually, the fundamental benefit of continuous integration is that it removes situations where we are looking for bugs which could not be found during unit testing but would show up when we integrate the different parts in one whole system. These bugs are some of the hardest ones to find and only continuous integration testing could save us from a lot of headache in later phases of a project development. The integration of JUnit with Ant does exactly that.
Furthermore, because my project is a server-side application, I needed some framework for unit testing server-side code. I choose Cactus because it uses JUnit and could be integrated with Ant. The intent of Cactus is to lower the cost of writing tests for server-side code .Cactus implements an in-container strategy. I haven’t work with other testing frameworks for server-side code, but this was the framework that I had the most problems with from all other that I had used in my project until now. There were moments when I was very close to give up on it. I had so many problems only with configuring HSql database on JBoss server, but once I figured it out, I was wondering what took me so long. This wasn’t the case with Cactus framework. After been stacked with it for a long time, finally I succeed to make it work on both Tomcat and JBoss servers. Actually, most of the problems were on JBoss, but Tomcat wasn’t easy either. However, I am hoping for not having any problems with Cactus framework because I have no idea how I made it work. I am taking “once you made it work, just don’t touch anything anymore” approach with Cactus.
One of the problems was that there wasn’t implemented property in “cactus” task for JBoss.4.0.0 yet, so that I had to use the more complicated “runservertest” task. When this task is being used, it should be provided tasks for stopping and starting the current server.
However, I was very satisfied at the end. Although, Cactus framework was very difficult for me to configure and make it run, I found two very important bugs with Cactus testing that I would have very, very hard time finding. One of them was a bug that I had made. It was related to setup test data in the database. I had exchanged the roles for administrator and regular user. The strange thing was that when I tested via a web browser, everything worked fine, but Cactus find this data inconsistency. Otherwise, it would have shown up much later in the development of the project and would have created a lot of troubles for me. Just the thought about how much time I was going to spend on debugging for some minor bug like this, made me appreciate in-container unit testing as well as the continuous integration testing.
The second bug wasn’t mine! While cactus tests worked perfectly well on Tomcat server, they didn’t work on JBoss.4.0.0. It was very strange. The problem was in the statement:
request.isUserInRole(“user”);
JBoss.4.0.0 always returned false. After a lot of debugging and with the argument that this works on Tomcat, I started wondering about JBoss handling of “request.isUserInRole()”. I started searching the web and surprise, JBoss.4.0.0, which was released in this September (2004) has a bug and the statement above always returns false. Fortunately for me, somebody else found this bug, described in this post one week before me. There has been a patch released for this bug that could be found here.
Finding these two bugs convinced me very strongly for the need of in-container unit testing combined with continuous integration testing and for Test Driven Development as a whole. I will try to apply this kind of development very consciously and strictly in this as well as any future projects.