|« December 2014|
The meeting Tuesday night was a discussion of tools, and Dave started it off with the following intentionally provocative statement: "It is impossible to do quality software engineering with an IDE." Of course, there were a few people who took issue with that, but we quickly converged on something we could all agree on: while IDEs offer a lot of useful tools, you should never allow the IDE to shape your project. The project should assume its natural shape, and the tools should support that. We also agreed that the fastest way to go down the wrong path in that regard is to let the IDE handle builds.
The problem, of course, is that IDEs tend to impose a particular view of project structure. And more often than not, they only support particular compilation tools. So if you want to build part of your system using another tool, or a custom code generator, that part of your build can't be automated by the IDE. So you have to make a choice between automation and the natural technologies for developing your system. You can't win unless you take the build process away from the IDE and use a more general-purpose tool.
There's always a tradeoff between special-purpose and general-purpose tools. Special-purpose tools can make life a lot easier when your needs match what they were designed for, but they aren't easily adapted to other situations. General-purpose tools are never quite as easy as a specialized tool at its best, but they're life savers when you're thrown a curve ball.
I think the choice between specialization and generality is particularly important for software development. Part of this is because even software projects that seem superficially similar tend to differ in many surprising respects. (In other words, software projects nearly always throw you a curve ball.) Additionally, there is the problem that we still don't understand software development very well in any fundamental sense, so folks building specialized tools often make mistakes when deciding where to restrict flexibility. (Another of Duncan's recent blog entries aims straight at this, and scores a bullseye -- I don't know how many copies of that Gosling paper I've printed and given to clients over the past few years.)
A great example of the way seemingly benign restrictions can bite you later is
make. That program is shockingly general, at least if you measure that by the number of uses to which it's been put that the designer never envisioned. But it has one unfortunate limitation -- a bias toward operations within a single directory -- that renders it a poor choice for a task very close to its design center: building Java programs.
As Duncan points out, EJBs were designed for very narrow problems, and might be very good for those problems. (I'm not so sure even that's true, but that's another argument.) But they enforce a very narrow, specialized programming model. No threads. No ... well, no lots of things. You give up a lot to program in an EJB container, and that might be worth it if your problems are close enough to EJB's strengths that you really get a lot in return. But as Mike points out, most systems are warped by EJBs, without seeing any compensating benefit.
It's instructive to contrast EJBs with the other core element of J2EE: servlets. Within the externally imposed constraints of the request/response style of HTTP, they are nearly as general-purpose as you can get. "Here's the request: deal with it and get back to me with a response." There are a lot of other things that servlet containers can do for a servlet, but the servlet has to ask. And by comparison with EJBs, servlets are broadly applicable and extremely successful. (After that exercise, if you want to get depressed, think about the technology that was sacrificed on the EJB altar: Jini.)
When looking at a software development technology, favor generality over specialized tools that claim to make things easy. Unless the tool is aimed at a very well understood domain, and your system is squarely within that domain, chances are you'll regret going the special-purpose route.