It has been my experience that technologies such as Struts, EJB, and TopLink
for experience reports from others) have one disturbing thing in common: They require powerful, behavior-changing configuration parameters that are stored in XML or properties files.
I have nothing against config files per se, but why must we express behavior in a separate language, beyond the verification of the compiler and the control of the development team? One purpose of objects is to isolate the expression of behavior. But with many architecture-level technologies, the behavior is spread over the Java source and a set of other file types that can be tweaked "without a recompile".
How difficult is it to recompile and re-deploy your project? I understand that these config files can be changed and hot-deployed in a 24/7 environment, or when the fix needs to roll out right away. These are some powerful advantages of these technologies. But there are usually ways to hot-deploy compiled byte-code, too.
Perhaps the customers want to be able to adjust something, themselves. But what? And how--without running the tests--will they know that all the pieces are playing nicely together? I've heard that this on-the-fly configuration is a great thing. "We can change the database schema without rebuilding the application!" And it will still run? REALLY?
Then I discover that if I don't go modify this or that file, my code doesn't work. In order to change one object, I have to change the Java source, and the XML, and a properties file. This severely breaks OnceAndOnlyOnce
For any "piece" of behavior, I posit: You Have To Write It Somewhere. Unless there's a very compelling reason that the webmaster or the customer would need to "reconfigure" something after the developers are done, I suggest that all behavior is recorded in as few places as possible. For example: In the source code.
This is what attracts me to HiberNate
. I haven't used it on a project yet, but I noticed that the config information can be recorded in JavaDoc
. Why not? Then everyone who looks at the code also knows how the object maps to the RDBMS. It's not a compile-time restriction, but it keeps related information close together.
3 also supports ORM mappings via Java 5 annotations, per JSR-220 and EJB3. See http://www.hibernate.org/hib_docs/annotations/#gen4
for more info.
I've recently noted a related phenomenon with students who are learning about DesignPatterns
. They seem to anticipate some reduction in the amount of code to write, or they see the separation of logic into multiple classes as a code-heavy solution. JeffMcKenna
said it very well. Essentially, you do end up with less code if you choose good patterns. You get to throw out a lot of the logic code (if-else and switch statements). You are replacing it with structure (classes and their relationships). Replacing logic with structure! That's a great summary for the distinction between procedural programming and OO programming with DesignPatterns
. But, of course, YouHaveToWriteItSomewhere
In order to change one object, I have to change the Java source, and the XML, and...
- exactly. This is why there is XDoclet, which puts all of that at least back into one place (even if it's still a mix of notations).
Very cool. Thanks! -- RobMyers
I think one of the issues is that the usual programming languages in the industry are imperative, procedural languages. Configuration is best expressed in a declarative form.
True. But much of the configuration that irks me seems behavioral in nature. In other words, it's not really configuration at all. It's another disguised imperative with huge effects on the success or failure of my objects (which still need to be written in Java, else the whole system fails). I don't mind being bilingual when building an app, but I want clear and simple justification for why one bit is in Java, and the other is in XML. The reason given by vendors boils down to: "We want to be everything to everyone." Struts started out as an al dente
solution to the problem known as JavaServerPages
validation, and again this client-side validation would be co-located with the definition of the field. Disclaimer: It's also quite possible that this framework is being used incorrectly. I'm looking at some very peculiar Struts-abuse these days. -- RobMyers
Another problem with defining everything in the implementation language: if you want to make tools to maintain the configuration, or extract configuration parameters from a live instance, you need to have implemented those features in the application. Configuration files are always readable, since they are still kept in a "source form".
Absolutely true. If something doesn't change with the application, but does change between installations (for example), then a simple properties or XML file is fine.
But what I see happening with tools such as Struts and EJBs is that they are trying to be everything to everyone, and they try to be infinitely configurable without a compiler. The Struts validation XML drives me nuts. Can (and should) a non-programmer really decide that the validation rules for a field must be changed without a rebuild? Can that person assure that nothing in the application is broken? Can that person be sure that the changes are correct? Did that person run all the tests?
I may be smelling something worse than I first thought. These tools are supposed to make it easier for the developer to develop (I suggest that they do the opposite by providing too many "configurable" choices located in too many places), and easier for the business to "program" their own application. That would be cool and useful if we were using natural language. How many customers want to slog through pages of XML for their EJBs?
Are we trying to build tools so that any Joe MBA can build a web app? Or are we trying to obfuscate the industry to the point where engineers are paid to maintain...pages of XML? I don't like either of those scenarios. I prefer the business people to stick to their core business, the programmers to stick to being total enthusiastic brainiac geeks who get a thrill out of seeing flexible structures evolve in their code. And I prefer the software produced to satisfy (even thrill) the customer, yet remain maintainable by the development staff.
I feel your pain. The project I'm currently working on is a essentially a translator for different network formats used in simulation. Currently, we have the translations hard coded in our C++ code. A few of the members of the team keep saying, "Oh, we'll make a generic translation engine that will allow us to take all that translation stuff out of the code." And my response is, "but to where?" We'll still have to encapsulate the logic in some form. But they don't see that, for some reason. --BrianRobinson
Depending on how stuff is structured, that may or may not be a good idea. The key question is--does it reduce complexity (and not sacrifice debugability or performance, at least not beyond some acceptable level)? If the "translations" are interspersed with unrelated logic, might need to be maintained by the customer, or are duplicated in the code, this refactoring might be useful. Indeed, this sounds like an instance of the InterpreterPattern. It also is an application of the PrincipleOfLeastPower, which is often a good thing.
However, IMHO the threshold to cross for InterpreterPattern to be useful is generally high. A lot depends on your implementation language, C++ is not a particularly good choice for this sort of stuff. You have to write and maintain a "translation engine"; which is an easy thing to get wrong for folks not skilled in that particular programming domain. I've seen, in my time,
many such processing engines written to convert some higher-level descriptor language into code; in most cases the result was piss-poor and
more complicated than leaving the stuff in native code. Use of such an engine makes debugging a bit more difficult; as errors in the "translation language" are reported as errors in the bowels of the engine, if at all. Finally, your staff will need to be trained in your "translation language".
But, in many cases, translation engines can be useful.--ScottJohnson
If a database is in use, you could store such in the database, but most BigIron
databases don't make it easy to split stuff to smaller, independent databases. What is needed is a NimbleDatabase
standard so databases can be sliced and diced without worries of licensing or complex installations.