Charles says Struts and similar web frameworks should be thrown away. He writes:
Give a reasonably good OO developer the task of building a web framework, their first attempt will probably be something resembling Struts. which I suppose gives good support to the “Build one to throw away” theory.
Call me a l33t PHP programmer, but I don’t think Struts is the thing that needs throwing away. The problem runs deeper than that.
In the late 90s, Sun, fresh from their success with Applets, charged their Distinguished Engineers with defining a common standard for web frameworks. The Distinguished Engineers drew on the rush-to-market, look-at-us-we’ve-got-one-of-them-too mentality of the dot-com era, and gave us Servlets and JSPs.
The Servlet and JSP standard is a good first attempt. But, like all first attempts, it should have been thrown away once the world had learnt some lessons from it.
These are some of the lessons I learnt from Servlets and JSPs:
The Servlets and JSP approach is so widely and thoroughly accepted by the Java community that it can’t be thrown away anytime soon. However, until it is thrown away, Java web frameworks will be building on crooked foundations.
Comments
Yeah, Webware has some of these same problems, as its structure was modeled off of Java. At the same time, if you pay more attention to the methods and less to the metaphors, it's really not as restricting as it seems. The methods are very minimal -- it's the structures we build based on the metaphors we infer that seem to be the problem.
I'm sorry, but if you really believe "Creating objects is not expensive. SingleThreadModel should be the default.", then you have no idea what you are talking about. Or, I'm really misunderstanding what you're saying. Because single or multi threaded has nothing to do with object creation. And NO ONE has a single threaded model - even php and perl are multi-process (rather than multithreaded). It's done that way for a good reason.
Webwork addresses points 2 and 3. Webwork actions are constructed for each request and do not have to extend anything in particular.
Velocity templates are not servlets, and you can write a Velocity resource-loader that grabs templates from anywhere you care to put them. This is how we implemented Confluence's per-space customiseable templates.
OSUser/Seraph takes a good stab at 5, but not as well as I'd like it to, I intend to fix this at some point. When I'm not so busy. Hahaha.
1 is still a challenge.
Will,
I had an idea that I was talking about Servlets :). Perhaps I should exand that point further...
Non-SingleThreadModel is there only to allow extremely high performance for requests that do not require much 'thought' on the sever's part. It is not a bad idea, it just should not be the default.
SingleThreadModel is an interface with no methods. If a servlet implements SingleThreadModel then it means no two threads will share an instance of that Servlet.
By default a container creates one instance of each servlet. If more than one request is received contemporaneously, all are sent, in separate threads, to the same servlet instance, where they share the servlet's instance variables. Because the instance variables are shared between threads, programmers devise all kinds of coding travesties, including creative ThreadLocal usage.
If a Servlet inherits SingleThreadModel then the container will create a new instance of the servlet per simultaneous incoming request. Each instance has its own variables. Programming is much simpler.
From memory, the Servlet specification doesn't particularly speak to when Servlet instances are created or how many are created, so your container may behave slightly differently.
The spec is actually pretty specific. For non-SingleThreadModel servlets, you're allowed exactly one instance per servlet declaration, or instance one per VM in distributable applications (Servlet spec s2.2). Servlets are either instantiated when the container is started, or when the first request arrives that the servlet is required to service (Servlet spec s2.3.1).
Neither of these rules are applied to SingleThreadModel servlets, though.
I don't understand why people would find it desirable to give instance variables to servlets anyway? Functionally, a servlet is nothing more than a HTTP event handler. The servlet should then delegate the important bits of the request message to the domain objects (for instance, POJOs or Actions, etc), and then allow the domain objects to deliver an appropriate response message (which the servlet puts into the HttpResponse). It shouldn't be doing any of the work, which means it shouldn't need to make use of instance variables. Nor should the class hierarchy of HttpServlet be all that important.
Am I off base here?
Charles,
Thanks for adding that. My memory was faulty.
Erik,
No I don't think you're off base. Functionally, a servlet is little more than an HTTP event handler.
However, for all but the simplest kinds applications, I find SingleThreadedModel servlets easier to work with. In the default, multi-threaded type of servlet I end up either a) passing around huge parameter lists, b) creating additional classes to hold the data that would otherwise be in parameters lists or c) using a framework (like Struts) that layers a more sensible event handler over the top of a Servlet.
Any way I look at it, Sun could do better.
Alan,
I agree: Sun could do better. While it's nice to have access to work at the servlet level for apps that might need it, you would think Sun would have come up with Struts, or another framework for working at an easier layer, on their own. (Which is interesting, because McClanahan is a Sun employee IIRC.)
Erik