Ok, so I should specify right off the bat my opinions about Java. I don’t like it, and many of its shortcomings more pronounced due to my experience with Python. I don’t like forcing a coupling between object and file hierarchies. I don’t like silly typing rules casting everything under the sun to an Object. I don’t understand the hype around JDBC: I expect my language to be bindable to my RDBMS, and I know that any advanced database programming will require sacrificing portability. I don’t like hearing advocates brag about the “write once, run anywhere” mantra when I know that not all JVMs (or JNI modules) are equal, or possible. I know Python’s not perfect either, but for the sake of my argument let me use it simply as a foil:

XML- and Properties-style config files

Great for standardization, but why add syntax? Properties config files should be simple to implement as parsed code. INI files become inline code, and the goofy [headers] are replaced by… object notation, maybe? Something like:

logname = Silly Goose
logtarget = syslog # this can be one of several fixed values
logname = Emergency Log
logtarget = stdout

becomes, in Python,

import logit, sys
log1 = logit.Log()
log1.name = "Silly Goose %s" % someDynamicStringVariable
log1.target = logit.SysLogTarget() # this can now be subclassed
# maybe it's even simpler than "one line per option"
log2 = logit.Log(name="Emergency Log", target=logit.FileTarget(sys.stdout))

XML config files look like object manipulation, and end up looking about the same (but maybe with more objects). Javadoc (or python docstrings) on the “configurable” objects provides the documentation framework for configuration without any extra tools. This ends up looking like a Twisted TAC file.

The obvious downside of course is that either of these methods results in a compile-time binding. Well, what’s stopping Java from allowing run-time compilation of source? javac can be accessed programmatically, so it wouldn’t be absurd to allow Java modules to compile each other at run-time.

Ok, ok, so now what about language independence? Theoretically, all of J2EE could be ported over to Python (though I wouldn’t, least of all because of Python’s Global Interpreter Lock that basically destroys high-performance threading). In such a case, deployment descriptors would suddenly become attractive again, because they abstract the configuration management of a [PJ]2EE project from its implementation language.

However, I think this is a straw man argument. Sun developed J2EE as a complete solution. They are not interested in compatibility with other languages, and I don’t blame them. A lot of code is involved in the J2EE framework, and I haven’t seen any Python that attempts to match it (Twisted is probably the closest match, and it is still quite different). Furthermore, the learning curve in training a developer on the new language effectively is significantly higher than the savings for a few configuration files. Thus, language independence, while it would be a nice castle in the sky, isn’t really something useful in practice.

Abstraction of Business Component Tier

Separation of business logic from UI logic is a great idea. EJB does that. So can a Servlet. Or a PHP script. Or internal SOAP/XML-RPC servers. I guess I don’t really have much to say about this part. EJB is just a means to an ends. I don’t like the term “business object”, because I don’t understand what knowledge it imparts other than “program state”. Maybe I’m missing something bigger here. The concept of stateful EJBs is nice, and the closest approximation with any code I’ve worked on is session variables in a web server (or possibly cookie-keyed data stored remotely and accessible from a stateless web server).

Abstraction of Remote Operations

There are two schools of thought I’ve heard on this subject. The “what’s downtime?” crowd wants to treat remote objects as local objects, and completely hide the remote aspect. The “fear the network, for it is your enemy” crowd wants application developers to be fully aware that their operations are remote and may fail at any time due to any number of network-related issues. Java RMI looks to me like it fits into the latter category, though the former could be appeased by allowing dynamic wrappers around the RMI functions. But here’s what I don’t get about RMI: Why do I have to add a scaffolding class for construction/destruction? Isn’t that what constructors and destructors are for? Consider this example (xmlrpclib is a real module, but I just made up rmi in this case):

import xmlrpclib
myobject = xmlrpclib.Server("https://hostspec/path/to/myobject/RPC2")
myobject.some_remote_function(lotsa_params) # might throw xmlrpclib.Fault
yourobject = xmlrpclib.Server("https://hostspec/path/to/yourobject/RPC2")
# equivalently with stateful RMI instead of stateless XML-RPC
import rmi
server = rmi.Server("hostspec", ...)
myobject = server.path.to.MyObject(constructor_params) # might throw rmi.Error
myobject.some_remote_function(a_few_params) # stateful connection gives warm fuzzy feelings
yourobject = server.path.to.YourObject(ctor_params)
yourobject.someVariable # this could be calling a function behind the scenes

The point is, Exceptions provide the means to get clean-looking application code without totally disregarding the network, and RMI’s scaffolding is boilerplate. Python has Java nailed in this regard – introspection tools are extremely common for disguising remote or complex operations under basic object skin. At least, not without code-generation tools, and I think those are just evil anyhow (if your application generates code, maybe your language isn’t choosing the right abstraction). Something like Pyro would really shine here.