11 ms·
Code's Worst Enemy [2007]
- wccrawford 15y agoRead all of it before I looked at the date. (The date was added to the title just before I posted this.) I thought it very interesting that Clojure and Scala feature very prominently in the comments, and yet I just heard about them a few months ago. I feel like I've had my head stuck in the ground. As for codebase size... Yes, Java is going to have more lines due to the nature of the language. He noted that experienced Java programmers don't see all that excess any more... He claims that's a bad thing, but I think that's what makes the language tolerable for them. They just look over them. I also have to wonder how Mirah would stack up for him. I had high hopes for the language, but it uses the built-in Java types so all that verbosity is still there for anything that uses them. It doesn't really have all the syntactic sugar that Ruby does.
- PaulHoule 15y agoIt's an important part of the Java problem that Java programmers aren't allowed to admit that verbosity is a vice and concision is a virtue. It goes hand and hand with a respect for "architecture" that too often can't say that the Emperor often has no clothes, and that a thick encrustation of barnacles often masquerades as an "architecture". Just to take an example, I wasted a few hours of my life trying to change the number of worker threads on a certain server written in Java. In a normal language with a healthy culture I should have been able to write server.setWorkerThreads(16); and I'd be done. But no, this is the land of the architecture astronauts, and if I want to set the worker threads I have to go find the undocumented classes so I can set the BlockingQueue and the ThreadPoolFactory and the fifteen other parameters that I don't care about (and will either set them in a way that is incorrect or suboptimal -- unless I spent two days researching each and every one of those parameters, checking the source code and doing experiments) Although the Java language is to blame for starting this fire, the Java culture perpetuates it. When you complain about this sort of thing, people don't listen, they just say you're a bad developer because you can't see the Emperor's clothes.
- deleted 15y ago[deleted]
- jbooth 15y agoActually, a setter on an instantiated server object would prob be a bad idea there, unless you're proposing logic to scale up/down the number of threads dynamically. You probably want a constructor parameter.
- PaulHoule 15y agothe trouble with the constructor parameter is you need one for each and every parameter. this might be a good answer if the language supports named parameters for the constructor, but Java doesn't. In this case, there's a ThreadPoolConfig object which you can set these things on. It turns out you can pass this to the constructor^h^h^h^h^h^h^h^h^h^h^h^h factory method AND you can pass it to a reconfigure() method on the ThreadPool -- so the (normal) static case and the (slightly odd) dynamic case are both covered. It wouldn't be so bad if there were reasonable defaults for the ThreadPoolConfig, but there aren't. If you take the defaults, the server complains that you've got the wrong ThreadFactory when you try to start it. In the end I was able to solve the problem by getting a copy of the thread pool configuration of the server (having to do two casts), changing the thread count, and then reconfiguring. The final answer wasn't that bad, but it wasn't that good either. And that's the trouble w/ the Java culture. The basic design is tolerable, but it's complex, which makes it hard to understand and hard to implement correctly. A little bit of attention to (i) sensible defaults, and (ii) documentation would go a long way. Given a fixed budget, complexity is the enemy of quality, since it creates more surface area for barnacles to accumulate.
- jbooth 15y agoWell, it does sound like a bad design, because they should just be using an ExecutorService.. better implementation and industry-standard interface. Plus you could just do new Server(Executors.newCachingThreadPool(10)). Smart job skipping past my initial point to the deeper point, that constructor values would just accumulate, which creates a need for the builder pattern in the absence of named parameters (which would be sweet.. java 7 supposedly will give us map literals which can substitute).
- scythe 15y agoSaying that a codebase needs to be small is like saying an airplane needs to be light: yes, it's true, in fact it's plain-and-simple obvious, but it doesn't reveal any of the hidden secrets and planning and so forth that are basically necessary to keep a codebase small and manageable. Even high-powered polymorphic languages a la Lisp will happily hand you enough rope to drown yourself in. If you look at code as basically a description of what a program does, like, a formal description, it's unsurprising that conciseness and clarity are not entirely unrelated and that redundancy is annoying for anyone who has to read it. What's not obvious is the most clear or concise way to describe what the program does, and this is just as true in a computer language as in say a natural language.
- jbooth 15y agoYeah, and if I went through the codebase for my current project and added a bunch of line breaks, I'd double the code "size" according to the LOC metric without changing anything about the complexity at all. Macros kinda terrify me because they mean I can't glance at a random 5-line fragment and know exactly what's happening. I'm not convinced that they add to clarity, even while doing a lot for conciseness. To be fair, I've never used them on a project that was bigger than "tiny", so maybe I'm just casting aspersions on something I don't understand. After macros, then what? Is the slightly redundant Foo foo = foos.next() in Java really hurting clarity that bad? I mean, yeah, the type should be inferred there but is that the reason big projects get unmanageable? Or is it higher-level architectural bloat? EDIT: Wow. Any downvoters want to explain why this comment is so offensive to them? Perhaps they could contribute their own thoughts about complexity and code bloat?
- deleted 15y ago[deleted]
- bad_user 15y agoMacros kinda terrify me because they mean I can't glance at a random 5-line fragment and know exactly what's happening Higher-level languages like Java running on top of advanced VMs like the Hotspot JVM -- are high-level enough such that you NEVER know what's happening. Even dropping to JVM bytecode doesn't help you much, as that doesn't show you how data moves in and out of the registers, how decisions on compiling hotspots / inlining functions are made, or how allocated objects move through GC-generations. You also lose control a lot. When you drop down to assembly, tail-calls are trivial for instance, not to mention dealing with cache pressure becomes a lot simpler. What high-level languages give you (versus assembly) is a way to express intent, rather than details that you don't care about in general. Which is no different from having macros in your language, or other high-level abstractions, in which you invent your own language for expressing intent, rather than deal with useless details that you don't care about 99% of the time. Foo foo = foos.next() But that line isn't really clear. It's saying stuff like - give me a Foo right now. But what happens when there are no more Foos to be given? Does it return a Null? Does it trigger an exception? That line of code also doesn't express intent. So you've got a Foo. Now what? And have I mentioned that objects in "foos" may not be Foo instances? Basically that whole line of code is totally worthless boilerplate.
- Auguste 15y agoI just realised that the game that Steve is referring to in his blog is Wyvern. It was one of the earliest multiplayer games I played. I wouldn't mind playing it again, but it seems I can't reach the website (www.cabochon.com) right now.
- sdfjkl 15y agoGame info (Wyvern): http://en.wikipedia.org/wiki/Wyvern_(video_game) http://en.wikipedia.org/wiki/Wyvern_(video_game)
- seles 15y agoI realize it is in bad taste to comment before reading the whole article (only 1/3 through yet). But I cannot help but see the irony in taking so many words to say that size is bad for programs.
- Conradaroma 15y agogreat comment
- helmut_hed 15y agoI was disappointed to see this line: design patterns – at least most of the patterns in the "Gang of Four" book – make code bases get bigger. This hasn't been my experience. In fact, learning about and applying design patterns has been a crucial part of reducing code size in previous projects by eliminating copy-paste code. For example, a previous company had a lot of code devoted to traversing a particular data structure and taking various actions at each node. There were multiple variants of this traversal code, each with different actions but also slightly different (for no reason) in the traversal code. Applying the Visitor pattern allowed me to write the traversal only once, reducing code duplication and potential future bugs. I also believe it was more readable. This was in C++ though - I'm not sure how much of his comments are directed solely at Java.
- gmartres 15y agoIf you had experience in a functional programming language, you'd have recognized this as a fold and written the foldMyStructure function. If your Visitor pattern solution is similar to the example code in https://secure.wikimedia.org/wikipedia/en/wiki/Visitor_pattern https://secure.wikimedia.org/wikipedia/en/wiki/Visitor_patte... then it is certainly longer than the natural solution in functional programming.
- JoelMcCracken 15y agoI have read this essay a few times, and I think that steve is missing an insight into modularity. We should be writing libraries for ourselves, not just piling code on top of other code. As an argument, I first offer a few propositions. Any code upon which your project relies can be considered "part of the code base". As an example from Rails, it has become a somewhat common/accepted practice to notice a deficiency in a gem, fork it on github, fix it for your needs, and use it. This is especially common if your project depends on abandoned gems that you still need to use, for whatever reason. Even if this isn't a problem, I often need to look into internals to figure out where something is breaking. Then, if code that your code depends on is considered part of the project, if steve was correct, then it would be very hard to use anything more advanced. However, practical wisdom shows that higher level such as Ruby are more productive than lower level languages, such as C. Thus, the original premise is shown false. If the original premise is false, then what is it that steve is noticing? I think it is about leaky abstractions. If you write libraries for yourself, with good, clean interfaces, you do not need to "notice" the lines of code from other parts of the project. tl;dr It's about creating abstractions for yourself, not pure LOC count.