Criticisms of Web4j, Spring, PHP, and Rails
The most common of all follies is to believe passionately in the palpably not true. It is the chief occupation of mankind.
All tools have drawbacks and trade-offs.
How many times have you become disillusioned with a tool, but only after you have invested a lot of time and effort in it?
The purpose of this section is to make sure that doesn't happen to you with WEB4J, by listing items you should know about.
Tools that don't make an effort to clearly state their own drawbacks and trade-offs
up front don't have your best interests in mind. Clearly, what they have in mind is their best
interests, not yours.
WEB4J's philosophy is one of deep minimalism.
Thus, WEB4J may not include things which you might feel should be there:
- it has no library of fancy user interface widgets.
- it has no items related to Ajax, Web Services, Messaging, or Dependency Injection.
- it doesn't have a CAPTCHA mechanism.
- it has no components, events, listeners, and so on (as in desktop programming).
- it uses JSP/JSTL, and alternative tools such as Velocity aren't supported.
- it uses HTML, not XHTML.
- its form population mechanism doesn't include a way of changing the appearance of controls containing erroneous user input, nor for associating specific error messages with specific controls.
- for spreadsheet-style forms, no parsing of request parameter names to extract numeric row identifiers is performed.
- its data layer is most suited to simple domain models, where 1..N relations between classes are not explicitly hard-coded.
When needed, such relations can always be implemented implicitly in a feature's Action, as opposed to explicitly in the domain model.
Of course, if you choose some other persistence tool, then this drawback may not apply.
- when displaying an existing Model Object (built from an SQL statement) in a form, the data is formatted by the <w:populate> tag using application-wide format settings defined in web.xml, with no override. Some may find this pleasing, while others may find it an onerous constraint.
You May Need Third Party Tools
WEB4J doesn't depend on any third party tools or jars other than those published by Oracle and expected in a servlet environment (Servlet API, JSP/JSTL).
Thus, adding third party tools to your WEB4J application may well be necessary.
Examples of tools you might have to add:
The toString, equals, and hashCode Methods Have Some Repetition
WEB4J provides good tools for implementing toString, equals, and hashCode.
For each Model Object, the implementations of these methods vary in details, but their general technique or style is always the same.
It would be very satisfying if these "general techniques" could be defined in one place.
There doesn't seem to be a satisfactory way of doing this with standard techniques of object programming.
You may want to try and remove that repetition by using aspect programming tools such as AspectJ.
Using JDK 5 annotations may be another option.
Backwards Compatibility Issues
We apologize for making occasional changes that are not backwards compatible.
Such changes occur only when deemed necessary for the long term quality of the tool, in the direction of increasing elegance and simplicity.
Such changes are never large scale, but it doesn't take much to break backwards compatibility.
If you need to update an existing WEB4J app to a new version of web4j.jar, you may need to perform some migrations to the new way of doing things, using the Version History to find items that may affect you.
Such migrations are almost always fairly minor, and there's never been a major rewrite of web4j.
Its core ideas have remained intact from the beginning.
You should evaluate the recent Version History to see if you are comfortable with the size and frequency of such changes.
It's true that there isn't much positive to say about such changes, except for this: it allows the tool to remain aggressively minimalistic, and increases its overall elegance.
"There's a natural law in programming language and API design : as backwards compatibility increases, elegance decreases."
Given the minimalist philosophy of WEB4J, it seems appropriate to trade some backwards compatibility problems for increased elegance and simplicity.
Some will not be comfortable with this.
The Spring Framework is popular.
It has also met with a disturbing lack of criticism, aside from some
interesting comments by Bob Lee.
The following remarks are based on Spring 2.0. (Note: of course, Spring itself isn't a web application framework - Spring MVC is. However,
when building a Spring MVC app, Spring is necessarily involved, so discussion of Spring itself is
relevant in this context.)
Spring is huge.
The unzipped distribution is over 150 Meg. Spring is not a single framework. Rather,
it's more of a collection of independent tools, with its Dependency Injection framework as the core item, Spring MVC as its web framework, and many other tools besides.
Some immediate consequences of this large size:
very fond of describing itself as lightweight.
However, not many programmers would characterize a tool having more than 2400 classes,
82 dependencies on external jars, and a distribution size of 150 Meg as lightweight.
This stretches the usual meaning of the term beyond its comfortable limits.
- it's complex.
- it has no clear focus. It includes "everything and the kitchen sink".
- its javadoc has over 2400 classes.
- its lib directory contains 49 other tools, totaling 82 jars.
It's true that an application would never require them all, but this clearly a non-trivial number of possible dependencies.
- it takes significant time to learn about all of its parts.
- Joshua Bloch's dictum of "when in doubt, leave it out" has not been applied to this tool with much enthusiasm.
Spring has many bad names for things.
In designing an API, the importance of proper names cannot be underestimated.
A good name will communicate clearly the purpose or general idea behind an item.
A bad name causes the reader to feel confused.
Spring has many bad names. Some examples:
|Name ||Context ||Why This Is A Bad Name|
|singleton ||scoping ||These items aren't singletons in the commonly accepted sense of the word.
|abstract ||scoping ||Has two meanings, one of which doesn't refer to an abstract type.
|set/list ||wiring ||These items don't necessarily correspond to the familiar Set and List.
|Spring MVC ||web ||This the name of the web app framework, but you would never know it from the name.
|global-session ||scoping ||Refers to portals, but doesn't mention portal in any way
|command ||web ||Refers to objects that hold request parameters. Command is usually reserved for action classes, not data-related classes.
|RequestContext ||web ||This refers to request parameters. In web apps, context refers to the application context, not request params.
|AccessDecisionManager ||security ||Performs authorization. Name unclear.
|ProviderManager ||security ||Performs authentication. Name unclear.
|ThrowawayController ||web ||Refers to the fact that the object can be garbage collected after use. From the point of view of the caller, this detail is irrelevant.
|bean ||wiring ||These items aren't actually Java Beans, since they don't need to conform to the Java Bean Specification (no-arg constructors aren't required).
The prevalence of bad names in Spring is unfortunate.
Spring apps need a lot of XML.
Spring applications often use large amounts of XML.
In typical Spring documentation, about half of the examples are in XML, not in Java.
The example applications provided with Spring show that XML files specific to Spring are on average about 24% of the size of your Java files:
|App ||Lines XML ||Lines Java ||XML as % of Java|
|Pet Clinic ||913 ||2,945 ||31%|
|Pet Portal ||318 ||1,431 ||22%|
|JPetstore ||693 ||3,512 ||20%|
|Average || || ||24%|
Anyone considering Spring should be aware that they will be spending a significant amount of time coding in XML.
Moving application development from Java to XML has many significant drawbacks for the typical developer:
- compile time errors are moved to runtime errors (this is the cause of many other problems).
- type safety is thrown out the window.
- refactoring is more difficult.
- modern IDEs are very adept at editing Java, but such tools are usually not available for editing XML.
- understanding such files often requires following a tedious 'trail of breadcrumbs' of string identifiers.
- names within a single XML file (or between XML files) can be mismatched.
Typos are easy to make, but hard to find (a bad combination).
- XML is not particularly legible or concise.
- when working in a source code control environment, monolithic XML files that refer to multiple features will often be a source of contention between programmers working on different tasks.
- XML was intended as a tool for transfering data between systems. In general, Spring uses XML in a way that wasn't intended by its creators.
(Some refer to this as "XML abuse", with some justification.)
Spring confuses coding with configuration.
As noted above, Spring apps contain significant amounts of XML. Thus, programmers spend a lot of time editing XML files
when building their application. In other words, they spend a lot of time coding in XML.
Spring documentation refuses to acknowledge this fact. Instead, coding in XML is always referred to as "configuration".
But this is both erroneous and egregiously misleading. For apparent marketing reasons, Spring wants you to think using
XML is somehow inherently beneficial to your application. That is, since they are "only configuration files", they must therefore
carry less burden or effort than regular coding.
(Given the difficulties mentioned above, however, one could strongly argue that XML files require more effort, not less.)
However, if you are building an application, then you are coding.
Configuration is applied to applications that have already been built and deployed.
It's inaccurate and downright misleading to refer to any part of building an app as "configuration".
Here's a comparison of the typical meaning given to the word 'configuration', versus
the meaning implied by Spring documentation:
|Item ||Normal Config ||Spring "Config"|
|Number of files ||1 ||N|
|Total number of lines ||small ||large|
|When settings made ||deploy time ||development time|
|File format ||simple text ||highly structured XML|
|Items interdependent ||usually not ||common|
|Usually small tweaks to behavior ||yes ||no|
|Specify class names ||rare ||common|
|Specify method names ||almost never ||common|
Spring has too many parallel mechanisms.
Parallel mechanisms are different ways of doing more or less the same task. Instead of deciding on a single reasonable way
of performing a task, there are often 2, 3, or even 4 variations on the same theme. This can be very frustrating, since you
need to spend significant time, first understanding all the options, and then deciding which one to pick.
- N different ways of wiring 'beans' together.
- 4 differents ways to map URLs to controllers.
- 3 different ways to use JDBC template classes.
- 2 different ways of binding data to form controls in web apps.
- choosing between XML coding and annotations.
- Spring AOP and AspectJ have a lot of overlap between them.
- the Spring security mechanism is very similar to that of the Servlet API.
- ...and many other items.
Spring has many other issues as well.
- Spring MVC has embarrassing security holes in its own example applications.
- Spring MVC documentation has no clear guidance on Cross-Site Scripting (XSS) attacks, and no clear guidance on Cross Site Request Forgery (CSRF) attacks.
These attacks are very common, and every web app framework should help you defend against them.
The absence of any clear discussion of these issues is disturbing.
- your application code will often require cast operations.
- you will sometimes need to catch exceptions to implement logic branches. Many would disagree deeply with using exceptions in this way.
- Spring translates checked exceptions into unchecked exceptions.
Many would disagree with that approach.
- Spring doesn't help you implement toString,
- you can't place your SQL statements in a plain text file.
- it doesn't encourage package-by-feature.
- you can't centralize display formats for various data types.
- Spring has no services or guidelines for implementing code tables.
- Spring doesn't encourage you to avoid ResourceBundle and its defects.
- wiring of 'beans' can be ambiguous, non-obvious, and can have circular dependencies.
- Spring MVC itself has no built-in services for validation or templating.
Instead, you are pointed to other tools of questionable quality.
- Spring MVC takes validation out of your Model Objects (its proper home), and moves it into a separate class having a single method.
This is very unfortunate, since validation is such an important part of most apps.
- it doesn't let you implement your Model Objects as immutables.
- you can't implement your forms in plain HTML.
Here are the major pitfalls and drawbacks of using PHP:
- PHP has the dubious distinction of having the largest number of security holes of any tool in its class. This fact alone is enough for many organizations to reject it.
- PHP does not support Unicode, so it's difficult to implement multilingual applications with it.
A web framework that doesn't support Unicode is a parochial anachronism - WWW does stand for world wide web, does it not?
- the PHP language has no formal specification.
It was originally built informally, by a single programmer, who wasn't experienced in designing programming languages.
(Evidence for this is the large number of security holes in PHP.)
- many complain that the APIs are a mess -
inconsistent naming conventions, functions of dubious benefit, synonymous functions, silent errors, and so on.
- according to its creator, PHP was "not designed to win any beauty contests".
- PHP doesn't use convention over configuration. Its creator states unequivocally: "I absolutely hate programming frameworks that lock me into a certain way of approaching a problem."
This contradicts many modern tools, which embrace such conventions, since they save time and money.
- PHP by itself isn't a Model-View-Controller framework. As a result, many PHP applications and examples suffer from a lack of
separation of concerns. In the hands of an inexperienced programmer, using PHP by itself
often leads to higher maintenance costs because of poor design. Thus, the use a of second tool, an MVC framework built on top of PHP, is almost always necessary.
For the typical Java developer, here are the major pitfalls and drawbacks of using Ruby On Rails.
Rails doesn't do much to protect the application programmer from common security issues:
WEB4J does not suffer from the above security defects, since:
- Rails doesn't have the parameterization found in Java's PreparedStatement, so it's
open to SQL injection attacks when you manually construct SQL statements.
- by default, Rails will attempt to automatically bind all request parameters to items in your code.
That is, it doesn't always use a white list of accepted request parameters.
This is an egregious design flaw for a web application framework.
- Rails apps usually store session data in files or database records.
This is inherently less secure than Java's in-memory sessions, since people with access to the server may view private information.
- by default, Rails will log request parameter values in clear text, including passwords.
- it always uses PreparedStatement. This protects you from SQL injection attacks.
- it always uses a white list of acceptable request parameters.
- it uses Java's in-memory sessions.
- it never logs the value of request parameters whose name contains the text 'password'.
In addition, the form-based login mechanism defined by the servlet API usually handles login.
So, in this important case, the framework cannot log any items in the first place.
Rails has other issues as well.
- Ruby is a delightful language to use. But if it's new to you, then you will need to learn
an entirely new language, its libraries, and idioms.
When constructing a Rails application, your experience with Java and its libraries will be mostly irrelevant.
- Rails uses the Active Record pattern, where Model Objects have intimate knowledge of their own persistence. In WEB4J,
Model Objects are not tightly coupled to the database in this way.
- by default, Rails takes control of the database schema. For many organizations, this is backwards, since the
database schema is usually under the control of database administrators, not programmers.
In WEB4J, the application never assumes that it "owns" the database.
- in Rails, using more than one database is possible, but rather inelegant. In WEB4J, using multiple databases is
just as natural as using one.
- the views in Rails are rather different from regular hypertext. For most Java programmers, their overall
appearance is a bit heavy on scripting.
- the code generated by Rails uses package-by-layer, which is inferior to the package-by-feature style encouraged by WEB4J.
- Rails does not support distributed transactions.
It is true that WEB4J also does not have services related explicitly to distributed transactions.
However, since you are using Java, a UserTransaction can always be used when it is available in your environment.