An Overview - Guiding Principles
Guiding Principles
Stripes was initially conceived and developed as a lightweight framework, taking advantage of the latest technologies to remove the drudgery from Java web development. The following set of principles describe the general philosophy in developing Stripes, and should inform all future development:
Simplicity
Simplicity can mean many things, but particularly this means keeping Stripes easy for developers to pick up, to learn and to use on a daily basis. In this sense, simplicity means intuitiveness and productivity. Concretely, this means things like:
- Not having to link lots of artefacts together to get things done (keeping a bean and a view in sync is enough!)
- Not introducing extra dependencies (jars) unless they provide amazing value
- Not introducing additional languages (EL, scripting or configuration) for users to learn
- Relying on convention as much as possible, but making it easy to override
- Generalizing far enough to cover all common cases, but not so far as to be confusing or meaningless
One extremely important concept is "latent functionality".
latent (adj): present and capable of becoming though not now visible, obvious, active.
Stripes is simple in that it doesn't force developers to grok everything about it in order to get started. By not having to know all the details, or even that many of them exist, it's easy for a developer to get the basics and get started. A perfect example of this is the interceptor framework, and the before/after methods. A developer can be blissfully ignorant of these with no negative consequences. But when a need for such a function arises, they are easy to discover (because they are well documented, and have obvious names!).
Web-i-ness
Stripes, at its core, is an action framework and action frameworks as a whole don't shy away from the fact that the entire web is implemented on top of a stateless protocol (HTTP). There are myriad shortcomings in HTTP, and in the various dialects of HTML that are in use. Trying to hide the fact that HTTP is stateless and provide a framework that hides this fact from the developer is fraught with issues, and nearly always leads to a leaky abstraction. Component frameworks tend to lead to more complicated programming environments, while simultaneously not dealing completely with state issues (you have to worry about back button support, how many versions of state to keep etc. etc.).
As such Stripes should aim to give developers tools to deal with building stateless applications on top of a stateless protocol, and ways to accomplish what they need, but not attempt to hide this reality from them.
The importance of small things
Focus on details can make all the difference, to developers and end users alike. A couple of examples can illustrate this best:
- Date conversion. Every web framework I've ever used forces you to specify a single mask for converting the user's String input into a valid Date object. Why? Probably because java.text.DateFormat works that way, and no one ever stopped to think if that was enough. In contrast, desktop applications like Microsoft Excel will often let you enter anything vaguely resembling a date, and parse it correctly. Stripes works more like Excel - it uses a bunch of DateFormats and pre-processing to parse literally hundreds of different formats without the developer ever specifying a mask.
- Log and exception messages in Stripes are frequently several paragraphs long and point out, a) what went wrong in excruciating detail, b) the common causes of the problem, and c) the solutions to those common causes. And, where possible, they do it with a sense of humour. What this means is that instead of Googling around to find an answer, developers will more often than not find the answer to their problem in the error message they get, and be able to fix it right away.
- Going the extra mile on HTML attributes. HTML/CSS uses the word
class
. A lot. But in Javaclass
is a reserved word, and because of thegetClass()
method on Object,class
you can't write JavaBean methods of your own calledgetClass()
. As a result it's common to see custom tags in frameworks that force you to writecssClss=""
orstyleClass=""
. In reality, all you have to do is write aBeanInfo
class, and you can have yourclass=""
attribute. This might seem like a small detail, but it means that templates from designers don't need as much translating, and muscle memory that typesclass=""
just like on every other HTML element, don't get in the way.
Backwards compatibility is important, but doesn't trump everything
Backwards compatibility is important because it effects developers using current releases of Stripes. That said, a blind mantra of "thou shalt not break backwards compatibility" helps no one. Instead backwards compatibility should be evaluated as with any other trade-off.
For example, a change that brings benefit, but causes developers to have to hand-edit every ActionBean is a terrible idea. But a change that is easy to fix (e.g. using a regular expression search and replace), but improves the quality or functionality of Stripes significantly is a reasonable trade-off.
A case in point is the current @Before
/@After
method annotations. In Stripes 1.4.x they use the default value=""} attribute to accept the list of lifecycle stages to run before/after. A common pattern in Stripes is to use an {{on=""
attribute to allow the effect of an annotation to be sub-setted based on the submitted event. It isn't possible to add that attribute to these annotations without breaking usages like: @Before(LifecycleStage.HandlerResolution)
. Alternative solutions would involve creating new annotations (and supporting both versions), or not adding the functionality. The value of the change is quite high, and the cost of fixing the backwards compatibilty breaks is low, so this would seem a change worth making.