As an Agile Coach, Miško is responsible for teaching his co-workers to maintain the highest level of automated testing culture, allowing frequent releases of applications with high quality. He is very involved in Open Source community and an author of several open source projects. Recently his interest in Test Driven Developement turned into http://TestabilityExplorer.org with which he hopes will change the testing culture of the open source community. Misko is a DZone MVB and is not an employee of DZone and has posted 38 posts at DZone. You can read more from them at their website. View Full User Profile

How to do Everything Wrong With Servlets

04.09.2009
| 7896 views |
  • submit to reddit

When I interview people I often ask them what an evil developer would do to make his code hard to test. Servlets are a great example of what to do if you want it to be hard to test

Lets start with constructor. Constructor is the first thing I look at since it tells me about my dependencies. In the case of servlets the spec asks for no-argument constructor so that the container can control the instantiation process. This is all fine but how is my Servlet supposed to get a hold of its dependencies such as database connection or any other object which needs to be shared between multiple servlets? There is no good way! The only thing which I can do is to use global state and singletons for inter servlet communication (which we have covered in detailed here, here, and here).

Initialization process is no help here. Yes the container will call a init method, but the only thing I can get a hold of in the initialization process is the strings which I have placed in my XML. What I really want is to share instances of objects between servlets so that I can configure my collaborators. Again I am forced to result to global state and singletons. But there is something worse about this. Mainly the single responsibility principle. Each class is responsible for exactly one thing. But in our case the servlet is responsible for the logic, the wiring of itself to the collaborators and initialization of the collaborators. Now, I like to place my initialization in a single place so that I can control the order of initialization. But servlets make this difficult since the servlet container does not guarantee any order of initialization for your code. This means that each servlet is a potential source of initialization. Which again forces you to the singleton and lazy initialization model.

In Java you have single inheritance hierarchy, (which is a good thing) but Servlets take that away from you by forcing you to inherit from their class in essence giving you no inheritance choice at all. Inheritance should be used when we need to take advantage of polymorphism, but there is no polymorphism going on within servlets. What passible purpose does inheriting from HttpServlet serve which could not be addressed with an interface. Code reuse through inheritance is quite possibly the worst offense in software engineering. Composition over inheritance should always be the goal. The worse thing about this is it sets a precedence which is followed on most projects. Most web apps have deep inheritance hierarchies with Servlet at the top which seem to serve no other purpose than code reuse. Testing collaborators is easy since I can test each collaborator in isolation, but if collaboration is replaced with inheritance now my tests have to test the full inheritance hierarchy at once. Inheritance is all or nothing proposition.

OK, if you managed to survive the constructor, initialization, and inheritance, there are other subtle surprises waiting for you. We are building web apps, therefor the most common object lifetime should be equal to the duration of HTTP request. Instead we have servlets whose lifetime is lifetime of the JVM. This creates a huge problem since all of the HTTP request information/data now has to travel through the stack rather than being a part of the object. In other words we have static code-base and we push the data around through the method arguments. Sounds like procedural code to me. I don’t want to get into debate over OO vs Procedural, but I do want to point out that Java is OO, use it in that way. If you want to write rocedural code, use a procedural language. Play to the strengths of the language no to its weakness.

Surely there is nothing else which servlets do wrong. Ohh, but there is, let me introduce you to the Service Locators anty-pattern. The HttpServletRequest and HttpServletResponse are two huge service locators. They themselves hove nothing of interest, but they do have getter methods which have things which I need. Well actually, I don’t need that either. What I want is a User for example. What I have is request. Let’s see does this look familiar?

String cookie = request.getCookie();
long userId = cookieParser.parse(cookie).getUserId();
User user = userRepository.find(userId);

What I want is user but what I got is worthy of a Sherlock-Holms detective story as I try to piece together the identity of the user. If I had to do this in one location, I would not complain so much but I have to do this in every single servlet. Please, just give me the user, or whatever else which I need to get my work done. The thing is that request has cookie, but it is not the cookie I want, it is the user id which is embedded in the cookie. But it is not the user id, but the user i really want. This Law of Demeter violation is the direct result of two things: (1) service locator nature of the request / response and (2) the wrong lifetime of the servlet.

Now imagine trying to test this thing. First I have to call new, great that is easy as I have no argument constructor, but how do I get all of my mock dependencies into the servelet as collaborators? My only hope is setting some global state. But, wait the servlet is also responsible for initialization which means it is loaded with new operators, and those suck from the testability point of view. (see here) Now I really want to test the home page but the home page servlet inherits from the AuthorizedServlet which talks to the database to authenticate. Great now my every test needs to mock out the authentication even if it is not testing it. So if I change my authentication all my test are broken. Now I really just want to create a new User to test the home page but I have to place my user into a Mock Repository and assign a mock id. I than have to create a mock cookie and place it into a mock http request all the while hoping that I will be able to give you a mock UserRepesitory through some global state.  I wish I was making this up, but Servlets are untestable in their current form.

Let’s see if we can solve these problems. First forget servlets and create your own classes which have your own minimal inheritance with preference for composition with object lifetime which equals that of the HTTP request so that your collaborators can ask for objects such as User directly in the constructor. This way testing your code is easy. Now for the servlet part, Since our code is HTTP servlet, request and response free it is both easy to test and incompatible. Therefor the job of the servlet is to call the new operators to build the object graph of collaborators with the right lifetime and to delegate the execution to our code. In essence the servlet becomes one big factory and object look up. It is still untestable as ever, but at least there is no logic to test there. Since the nature of the factories is that they either work or they blow up spectacularly.

From http://misko.hevery.com/

Published at DZone with permission of Misko Hevery, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Dmitry Polyakov replied on Thu, 2009/04/09 - 6:32am

crap

Silvio Bierman replied on Thu, 2009/04/09 - 8:56am

Sounds like the title of your post is an accurate description of how you use servlets.

You should look at ServletContext for sharing state between servlets. You should also consider creating a delegation model where requests are handled by implementations of some generic interface GenericRequestHandler. Then decide for each request how you want to delegate it to some handler at the context, servlet, session or request level. That is all the servlet itself should do.

Creating deep inheritance trees under HttpServlet is stupid. The only reason to inherit from a HttpServlet is to create an identifying class for the servlet so you typically inherit one level only.

Silvio

Adam Davis replied on Thu, 2009/04/09 - 9:19am

... First forget servlets and create your own classes which have your own minimal inheritance with preference for composition with object lifetime which equals that of the HTTP request so that your collaborators can ask for objects such as User directly in the constructor. ... Since our code is HTTP servlet, request and response free it is both easy to test and incompatible. Therefor the job of the servlet is to call the new operators to build the object graph of collaborators with the right lifetime and to delegate the execution to our code. In essence the servlet becomes one big factory and object look up. It is still untestable as ever, but at least there is no logic to test there. ...

I wouldn't mind seeing an example of this. Is there some code you can show us which illustrates this technique?

Alessandro Santini replied on Thu, 2009/04/09 - 12:33pm

Please do not take it too personal - this article seems written 10 years ago. Many of the testability and inheritance problems have been resolved a long time ago by many web frameworks.

Ran Biron replied on Thu, 2009/04/09 - 3:14pm

Uh... ever heard about a tiny little framework called Spring?

Jeroen Wenting replied on Mon, 2009/04/13 - 7:04am

probably not, just as he has never heard about not sharing database connections between requests (let alone servlet instances).

Charles Chow replied on Tue, 2009/04/14 - 2:54am

fully agree with Silvio and Alessandro Santini.

 

Why we will write Servlet? Cause it is running on the J2EE application server! Servlet just base on per request calling, why it can write any share code in here?

 

Servlet lifecycle was managing in application server, how to ensure every calling is call on same servlet?

 

I am sorry about that must understanding what servlet is.  

 

 

 

jame jack replied on Mon, 2009/06/29 - 4:31pm

تحميل برامج برامج جوالات العاب بنات برامج تكنولوجيا كتب تعليم UltraSurf العاب برامج نت Internet Download Manager ProgDVB برامج مجانية أفضل المواقع العربية دليل مواقع مشاهدة محطات مشفرة Online TV Player 3.0.0.940 Internet Download Manager 5.17 Build 4 رقص شرقي anyTV Pro 4.32 OnLineLive 7.1.1 هزي يانواعم ProgDVB 6.06.2 SopCast 3.0.3 منتدى برامج نت Falco Image Studio 3.6 لعبة تزلج على الجليد UltraSurf 9.4 كاثرين هيغل Katherine Heigl محطة غنوة FreeZ Online TV 1.0 Free Video to Mp3 Converter 3.1.3.51 Advanced MP3 Converter 2.10 Xilisoft Video to Audio Converter 5.1.23.0515 Blaze Media Pro 8.02 AKRAM Media Creator 1.11 DVD Audio Extractor 4.5.4 Free WMA to MP3 Converter 1.16 لعبة نينجا المتقدم لعبة قذف كرة لعبة دراجات البهلوانية لعبة اعداء الغابة تحميل برامج Download DivX Subtitles 2.0 BullGuard 8.5 Google Chrome 2.0.181.1 Dev Dell Studio XPS Desktop 435T Intel Matrix Storage Manager A00 Gigabyte GA-EP45-UD3P Bios F9 Ambush HDConvertToX 1.1.229.1764 MSI Wind Nettop CS 120 Realtek Audio Driver 5.10.0.5618 Biostar T41-A7 6.x Realtek On-Board Audio Driver 5.10.0.5735 for 2000/2003/XP TweakNow RegCleaner 4.1.1 SpeedItup Free 4.97 برامج العاب - Internet Download Manager - برامج جوالات - العاب - محطة غنوة - قنوات فضائية - بنات - تكنولوجيا - كتب تعليم - UltraSurf - ق ذ -0

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.