4 ms·
No. The long answer is that Java did it to us. Like jacquesm below, I have inherited a large Java enterprise project, 400,000 lines of Java, XML, JavaScript,
by russell 18y ago
No. The long answer is that Java did it to us. Like jacquesm below, I have inherited a large Java enterprise project, 400,000 lines of Java, XML, JavaScript, HTML, and Flex. And no comments, JavaDoc, or design documentation. All of this seems to have been written by one person with smaller contributions by a couple of others. There seems to be lots of copy and paste and IDE generated code. The system was designed to be modular with plugin components.
The first culprit is Java itself. The language is missing critical builtin data structures, ArrayList and Hashmap with corresponding literals. If they had been part of the language and not just libraries, Java might have taken a completely different direction. Throw in lack of overloadable operators, first class functions, and descent introspection and you get a language that in not very expressive.
Lack of key fundamental data structures, leads to the OOP bandwagon. Interfaces and inheritance are good tools but they should be used in moderation. In my project there is the pattern of BaseInterface, BaseClass, MoreCompleteInterface, MoreCompleteClass, ModuleLevelInterface, and ModuleLevelClass all to implement a DAO with nothingg but getters and setters. In one case this adds up to more than 2000 lines of code that does nothing that could not have bee done with a hash. Just to make sure that the code is completely non-understandable most serious classes have something like this
BaseInterface dataSource;
along with a setter that is filled in by Spring at runtime. I cant even explore the class structure. Contrast this with Python, where it would be a handful of lines of code, maybe 100 or 200 times fewer.
To get around the problems inherent in the language, Sun came up with beans and the Java community went charging off into complexity. And throw in XML configuration just to create an impedance barrier. Since this was all new territory, the result was an explosion of frameworks.
So now I have a stack that includes JBoss, Spring, Hibernate, MySQL, 200k of JS libraries (some of which I never heard of before), Flex, Granite, and more open source Java libraries than I can shake a stick at. I suspect there are many cases of a library being added for a single feature. Java OK, JS not so OK because of download bloat. Maybe Java is not OK either because I have to deal with what broke when I upgrades to a new version.
I particularly dislike the addition of Hibernate because it separates the programmer from the understanding of the database. In my case the database itself was generated from the the .hbm.xml files. The database was created from a Java-centric point of view as a network of classes. As a consequence Hibernate created hundreds of tables. One query to fill in a simple list in the browser created an SQL query with 10 joins. I'm surprised the db didn't roll over dead.
At least I'm being paid well.
- sdp 18y agoHow does a lack of "critical built-in data structures" (as opposted to libraries) lead to poor design? C has a ridiculously small set of built-in data structures, but the unix core tools written in C are very elegantly designed.
- frig 18y agoEh, don't read more into an argument than is really called for. The crux of the above argument is usually something like: In most nontrivial programs you'll wind up with a lot of "sophisticated" code that performs some task but has a ton of parameters and behaviors it'd be at least theoretically useful to be able to tune or override at some specific point-of-use of said code. Sometimes the right decision is to just hard-code in all the non-essential parameters to sensible defaults, and do only what you need; in places where this approach is warranted ("keep it simple, and only do what you need to"), Java is as annoying to use as ever but doesn't do much to shoot you in the foot beyond being more verbose than it needs to be. It's also sometimes the case that the right decision is to make the code as fully-articulated-as-possible: as many parameters as possible are tunable, and as many behaviors as possible can be overridden. We'll call this the "complicated" scenario. In the "complicated" scenario, you have at least the following choices for architecture: - approach 1: a tower of interfaces and base classes; each interface+base class combination augments or extends some of the behavior or adds or removes points-of-articulation from the layer beneath it. Once you've built the tower, whenever you get to a point where you need to call on this functionality you pick the appropriate item from the tower, subclass+augment its behavior further (if necessary), and go to town. - approach 2: similar to 1, but make heavy use of reflection (at least at certain points) to try and achieve some level of genericity (in the core methods and algorithms) and to make the implementation less dependent (at time of coding) on the specifics of any particular interface implementation. - approach 3: have methods that're like void openConnection(IConnectionSpecification connectionSpecification, Map<String,Object> options), and then be smart about how you extract options from the options Map. approach 1 and approach 2 have their problems but fit well into the tools Java gives you. Approach 1 is more suited for writing code that other people will use (ie, call into), whereas approach 2 is more suited for writing code that other people's code will be used in (ie, called) (yes, that's a bit vague, but it's good enough for today). Approach 3 is common in the scripting languages, because it allows for a lot of ad-hoc extension / parameter setting without excessively cluttering the interface. Approach 3 isn't impossible in Java, but the lack of literal syntax for eg maps and lists makes it unwieldy. If it were possible to write something like: - ConnectionBroker.openConnection(cSpec, {"port":80,"username":"username","password":"password"}); you'd see a lot more use of Approach 3 in Java. As-is, you'd have to explicitly construct a Map of the right type, then one-item-and-line-at-a-time populate it with keys and values, and so on, at which point (especially if used often and in a big project) you're better off coding up an IConnnectionOptions interface, etc., and going from there. So it's less: lack of data structures == bad design. It's more: lack of literal syntax for the basic data structures means that it's a royal pain to do certain ad-hoc friendly tasks in an ad-hoc way. Assuming laziness (always a good assumption), given an idiomatic way to handle cases with lots of potential parameters most programmers would handle things the ad-hoc way, and save the "over-engineered" tower-of-interfaces for the situations which are actually necessary (eg: real-honest-enterprisey-software).