1. 135
  1. 54

    Yeah, I wrote some of the worst code of my entire life in the two years after reading Clean Code. I kept adding more and more functions into my code at different layers, and it made my code into a mess with way too much indirection for relatively simple problems. When reading back through the code months later, I would be hard-pressed to figure out where modifications needed to be made, and had to walk back a lot of my design decisions. Pretty embarrassing.

    It reached a breaking point when I went back to a previous project to ship something for a client months later, and every single file I had written had been thrown out because the senior developer on the project was sick of having to deal with it. I felt humiliated and spiteful, and then I grew from the experience a bunch.

    Lately I’ve been following the idea from Casey Muratori’s Semantic Compression post a bit, mainly this little tidbit:

    Like a good compressor, I don’t reuse anything until I have at least two instances of it occurring. Many programmers don’t understand how important this is, and try to write “reusable” code right off the bat, but that is probably one of the biggest mistakes you can make. My mantra is, “make your code usable before you try to make it reusable”.’

    It seems obvious, but it’s been helpful for me to avoid abstractions until I have a better sense of where the code is going (and usually only two instances of some code is too small a number for that).

    Making functions when you have obvious inputs and outputs can be nice too, although it can be more difficult when writing graphics code, which tends to be pretty stateful (part of the motivation for Carmack’s post in defense of inlined code).

    1. 13

      When reading back through the code months later, I would be hard-pressed to figure out where modifications needed to be made, and had to walk back a lot of my design decisions. Pretty embarrassing.

      This is such a good point. Code written in that style isn’t even read only it’s write only. All you can ever seem to do to change how any of it works is to delete swathes of code and write more because all the functionality is implemented in the form of class relationships rather than simple logic.

      Like a good compressor, I don’t reuse anything until I have at least two instances of it occurring.

      Very much agree with this too.

      1. 6

        make your code usable before you try to make it reusable

        Thanks for the Semantic Compression recommendation, and this quote in particular. I think I’ll get a lot of mileage out of this concept.

        1. 2

          I had a similar experience. Clean code rules are great to get you thinking about this subject, and actually get you to start experimenting with making maintainable code. But your first experiments will always end up very bad, no matter how many books you read on the subject. Only experience with your old code will teach you how to write better code.

          1. 1

            Wow, I came to the same conclusion of Semantic Compression just naturally. After awhile you realize how wasteful you’ve been codewise and adapt a better way of thinking.

          2. 34

            Someone on Reddit put it best:

            Java devs never fail to be parodies of themselves.

            This is so spot on.

            Java is actually a good language, it’s the ecosystem that kills it for me. By “the ecosystem”, I don’t just mean the tooling (e.g. Java build tools are universally awful AFAICT), but the developers themselves. So much Java I read is just “magic”. Magic annotations, magic dependency injection, interfaces over classes that there is only one of etc. etc.

            The author points out very good failures in the way its been architected, but the code in the OP isn’t all that strange looking to me as Java, and that’s a pretty damning statement.

            I wish Java had a better audience around it. The Kotlin ecosystem seems better, but I’ve never used it.

            1. 27

              (edit: my first pass at this came off a little overly negative in a way that I think betrays the seriousness of my point)

              I’m not sure Java actually is a good language. My first introduction to Java was as the primarily language that was used in college, and even as a pretty green programmer them (I’d started writing C and C++ a few years earlier in high school, but I was definitely not a good programmer), I found it awfully questionable. In the intervening 15 years I’ve managed to avoid it, until quite recently. It’s been really eye-opening to see how the language has evolved in that time, but not really in a good way. Perhaps it’s because I’ve largely written OOP off as a bad idea that shouldn’t have ever taken off like it did, and is certainly outstaying it’s welcome, but I find that Java, and even the JVM itself, to be a masters class in solving the wrong problem in the most complex possible way. The complexity in java seems to be like glitter, you can’t touch anything with getting covered in it, and once it’s on you you’ll never get it off. Even working with people that I generally hold in high regard as developers, I see that the ecosystem has forced them into patterns and architecture that I think is questionable- except it’s not because to do anything better would be to try to work against every single design decision in the language and ecosystem. There’s simply no reasonable way to write good Java, the best you can reasonably hope for is to write as little java as possible, and hope the absurd complexity giltter doesn’t spread to all of your connected services by way of the blind “the whole world is Java” assumptions that the JVM ecosystem wants to make on your behalf.

              I say Java here, but realistically I think that all JVM languages end up falling into the same gravitational well. I’ve been using Kotlin lately, and from what I’ve seen of Scala and Clojure they are all infected by the same inescabable fractally wrong view of the world that is imposed by the JVM, by way of the JVM itself being born from the primordeal ooze of bad decisions and oop-kool-aid that led to Java in the first place. Kotlin in particular suffers from being not only unable to escape the Java ecosystem, but also from generally being a poorly designed language. Everything it adds to java, it adds in such a superficial and impotent way that a slight breeze knocks over the facade and you realize you’re stuck back in the Kingdom of the Nouns all over again.

              1. 7

                I tend to agree about the java part. The constructs at your disposal requires you to write very very verbose code, even for simple things. But I disagree about the JVM bit. I find it a pretty good runtime system. Although it tend to eat its fair share of RAM, the GCs and the JIT are first class. Overall, you get pretty decent perf without too much thought. Also, Having written a lot of clojure, it’s vastly different from java, couldn’t be further from the Kingdom of the Nouns.

                1. 16

                  The JVM feels to me like it was written for a world that just didn’t really ever happen. It promised cross platform compatibility, that never really materialized since there are only two real meaningful places where the jvm is heavily used these days (x86 linux servers and arm Linux phones). Even where the jvm itself is running on multiple platforms, it’s not running the same workloads across it. We would have been every bit as well off with a toolset that made native cross compilation feasible (go and rust), and probably would have been no worse off even with the old C and C++ cross compilation story. Love it or hate it, JavaScript is what actually fulfilled the promises that java made and never was able to keep.

                  Other promises that JVM made either never made sense- language interoperability always existed before java, and exists outside of it now. All the JVM did was fracture the environment by making it nearly impossible to produce native code- it’s a vampire if you look at it in terms of interoperability, unless you want to use gcc to compile your java code. The isolation and runtime management is, consistently, 90% of the work involved in deploying any java application I’ve used, and at the end of the day everyone does that work twice now because most workloads are getting deployed in cloud native containers anyway- so the JVM is superfluous there. GC is a pain in the JVM and has been done as well elsewhere without requiring the rest of the baggage of its runtime and jitter.

                  Looking at performance, I’m dubious that it has much going for it. It’s still not a contender in the same space as C or C++, and in many cases the pain of native interop make it slower than even python because python can rely on native code for a lot of heavy lifting. I’ve even seen fairly well optimized JVM code fail to keep up with reasonably (perf) naive Haskell.

                  Even with instrumentation, the supposed killer feature of the jvm, I have yet to see anything I can’t get out of a native application with native tooling and instrumentation, and the case is getting weaker by the day as more and more application telemetry moves up and down the stack away from the application itself and into either tracing layers in front of services, or tooling built around things like ebpf that live very low down in the system and allow you to instrument everything.

                  The JVM is at best a middle-of-the road performance language with a largely superfluous ecosystem. It might have been a good idea when it was created, and I have no doubt a lot of smart engineering went into its implementation, but it’s time we give it up and realize it’s a sunken cost that we need to leave to the history books as a quirky artifact of the peculiar compute and business environment of the early 90s.

                  1. 4

                    Clojure’s okay (and still way better than Java, IMO) but suffers from pretty poor error handling compared to other Lisp environments.

                  2. 5

                    I really don’t like how Java makes optimization of its runtime overcomplicated, then has the gall to make you deal with the complexity. There is no reason to be manually tuning GC and heap sizes when every other runtime, including CLR implementations, can deal with this efficiently and automatically. They might be complex, unlike the JVM, they’re not complex and making you deal with that complexity.

                    1. 3

                      Just curious what you dislike about Kotlin’s design? It seems like you make two points: that Kotlin can’t escape Java and, separately, that it’s poorly designed. I agree with the former, but in light of the former, I find Kotlin to be pretty well-designed. They fixed Java’s horrible nullness issues and even kludged in free functions to the JVM, which is neat. Data classes are a band-aid, but still help for the 80% of cases where they can apply. Same with sealed classes (I’d much prefer pattern matching akin to Rust, Swift, OCaml).

                      1. 14

                        My biggest issue is that everything feels like a kluge. Null tracking at the type level is fine, but they didn’t really go far enough with the syntax to make it as useful as it could have been- rust does better here by allowing you to lift values from an error context inside of a function. The language tries to push you toward immutability with val and var, but it’s superficial because you’re getting immutable references to largely mutable data structures without even getting a convenient deep copy. Extension methods are a fine way of adding capabilities to an object, but you can’t use them to fulfill an interface ala go, or outright extend a class with an interface implementation ala Haskell typeclasses, so you’re left with basically a pile of functions that swap an explicit argument for a this reference, and in the process you are conceptually adding a lot of complexity to the interface of an object with no good associated abstraction mechanism to be explicit about it. Even the nature of the language as a cross platform language that can target jvm, llvm, and web asm seems fundamentally flawed because in practice the language itself seems to lack enough of a stand alone ecosystem to ever be viable when it’s not being backed up by the jvm, and even if you did have a native or web ecosystem the design choices they made seem to be, as far as I can tell, about the worst approach I’ve ever seen to cross platform interoperability.

                        Ultimately the features they’ve added all follow this pattern of having pulled a good idea from elsewhere but having an implementation that seems to not fulfill the deeper reason for the feature. The only underlying principle seems to be “make java suck less”. That is, of course, a bar buried so low in the ground it’s in danger of being melted by the earths core, and I would say they did cross over that bar- kotlin does suck less than Java, but what’s astonishing to me is how for such a low bar they still seem to have managed to cross over it just barely.

                        1. 5

                          I share every single one of those sentiments, but I’ve excused many of them specifically because of the limitations of being a JVM language. (interfaces at class definition, no const, no clones)

                          I’ve almost taken it upon myself to periodically go and correct people in the Kotlin subreddit that val does not make things immutable, and that Kotlin has not cured the need for defensive copies in getters.

                          I think the idea of making Kotlin cross-platform is totally stupid for those same reasons you point out. All of that is a limitation of wanting to be on the JVM and/or close to Java semantics. Why they hell would you want to export that to non-JVM platforms?

                          Thanks for the response.

                    2. 12

                      I have a completely opposite opinion. Java is not the best language out there, I prefer Scala and Kotlin, but the selling point for me is the ecosystem: great tooling (tools simply work in lots of cases), great platform (lots of platforms are covered, really awesome backward compatibility, stability), great API (it might be far fetched, but I have a feeling that Java’s stdlib is one of the most feature-packed runtimes out there, if not the most?). The “magic” is the same problem as everywhere else; it’s magic until you know the details. Also just because there’s a dependency injection trend in the backend development world, it doesn’t mean that you should use DI in different projects. Interfaces of classes are a Java thing; it wouldn’t exist if the language was more sophisticated.

                      Maybe I’m comparing Java’s ecosystem to C++ – because with C/C++, the tooling is in appalling state, the standard library is awful and I’m not sure what it tries to achieve at times. So I guess I have a very low standards to compare to :P

                      1. 3

                        Java has an incredibly rich ecosystem, that’s true. What annoys me though, is that every single tool in the Java ecosystem is written in Java, meaning you have a ton of CLI programs which take a couple of seconds just to heat up the JVM. Once the JVM is hot and ready to actually do work, the task is over and all that JIT work is lost.

                        At least C/C++ tooling is fast :p

                        1. 2

                          That’s true, JVM startup time is a pain point. But there are several walkarounds for that:

                          • some tools use build server approach (gradle), so that startup time is less slow ;)
                          • some tools like sbt (scala build tool) use build server + shell approach, and it’s possible to use a thin client to invoke a command on this build server (e.g. ‘sbt-client’ written in rust). This makes Scala compilation take less time than compiling a C++ application.
                          • GraalVM native-image is pushed right now, which allows to compile JVM (java, kotlin, scala) application to native code without the use of JRE. This allows writing tools that have non-noticeable startup time, just like tools written in e.g. Go. I was testing some of my small tools with it and it was able to compile a small Clojure app to native code. This tool had same startup speed than a C++ application. Unfortunately, GraalVM can’t compile every app yet, but they’re working on it ;)

                          Also C/C++ tooling is fast, but C++ compilation is nowhere near being fast. Changing one header file often means recompilation of the first half of the project. Bad build system (e.g. in manually written Makefiles) that doesn’t track dependencies properly sometimes produces invalid binaries that fail at runtime, because some of the compilation units weren’t recompiled when they should be. It can be a real mess.

                      2. 11

                        I wish Java had a better audience around it.

                        That doesn’t seem terribly likely to happen.

                        1. Java was never aimed at programmers who value power, succinctness, and simplicity - or programmers who want to explore paradigms other than OO (although newer versions of the lanaguage seem to be somewhat relaxing the Kingdom of Nouns[1] restrictions). It was intended to improve the lives of C++ programmers and their ilk[2].

                        2. Java is frequently used in large, corporate, environments where programmers are considered (and treated as) fungible. “The new COBOL”, as it were[3].

                        3. The JVM itself allows programmers not falling into (1) and (2) to abandon the Java language itself - Clojure, Scala, Kotlin, and Armed Bear Common Lisp spring (heh) to mind. Most of the best JVM programmers I know aren’t actually using Java. Most of the ‘Java shops’ I’ve worked with in the past decade are now, really, ‘JVM shops’.

                        My observation is that most - to be clear, not all - people who continue using Java in 2020 are forced to do so by legacy codebases, and / or companies that won’t let them adopt new languages, even JVM languages. I honestly believe this is the proximate cause of the audience problem you describe. (Not the root cause, mind you).

                        Edited: I’m amused by the fact that the first two, nearly concurrent, replies both reference Yegge’s nouns blog post :)

                        [1] http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom-of-nouns.html

                        [2] “We were after the C++ programmers. We managed to drag a lot of them about halfway to Lisp.” - Gosling. http://www.paulgraham.com/icad.html

                        [3] https://www.infoworld.com/article/3438158/is-java-the-next-cobol.html

                        1. 5

                          Java is a horrible language. No mortal can mentally hold on to a class hierarchy where inheritance is more than a few levels deep. Furthermore it is a bad way to add “another layer of abstraction” , because it just paints you more and more into a corner.

                          (Clojure is a great language, you can add layers of abstraction to solve problems, without just digging yourself deeper.)

                          1. 3

                            But one can write Java programs without abusing inheritance, and even pretty much without inheritance.

                            1. 1

                              Yes. I agree that Java is a horrible language, but class inheritance doesn’t even make the list of things I find poor about it.

                          2. 3

                            I don’t agree that Java is a good language at all, but I wanted to hard-agree at the distaste for magic annotations and DI frameworks.

                            1. 1

                              Java is actually a good language, it’s the ecosystem that kills it for me. By “the ecosystem”, I don’t just mean the tooling (e.g. Java build tools are universally awful AFAICT), but the developers themselves. So much Java I read is just “magic”. Magic annotations, magic dependency injection, interfaces over classes that there is only one of etc. etc.

                              I don’t agree with this - in my experience, “magic” is “code that integrates my application-specific functionality with a massively feature-rich general purpose framework”. It’s magic in the sense that you need to understand the enclosing framework to understand why those annotations are there and their semantics, but they do real work. Work I’d have to do myself if I didn’t use them.

                              You don’t see this much in other languages, but it’s because “massively feature-rich general purpose frameworks” aren’t common outside of Java. The ones that do exist seem to have punted on important architectural decisions - you don’t need a dependency injection framework if your data layer objects are just global values (I’m looking at you, Django).

                              I’ve definitely felt this urge before - why do I need all this spring crap? Then I end up re-implementing half of that magic myself and not as well.

                              1. 1

                                What language has tooling that you like? Curious what you are comparing the Java build tools with

                                1. 2

                                  Rust and Go (at least since Go modules) I find both intuitive and fast. I am still not sure how to properly build a Java application without an IDE.

                                  1. 1

                                    $ ./gradlew build

                              2. 15

                                Clean code is a really good book. Even if it has some examples that are on the edge, and some examples that you don’t agree on, it doesn’t mean that rest of the examples are bad.

                                Most of the things from Clean Code is simply a good idea. I’m not sold on all points, but it’s a damaging reaction to “stop recommend” 1000 hints, just because 20 of them are bad (in the worst case). If everyone would use 25% of the hints that Martin suggested, the world would simply be a better place. Even if people would follow the “bad” advice from this book, it still would be a better situation than people inventing their own strange philosophies for e.g. naming things, that happen to change from variable to variable. From my experience, lots of people don’t even consider most points that Martin has proposed. And if there’s a value to the book, then it might be just to tell you what you should think about. Which is a good outcome I think.

                                1. 17

                                  There are so many books out there, it it really necessary to settle for one that contradicts itself? It is such a red flag.

                                  1. 5

                                    Are there so many books on the same topic as Clean Code? I only know Code Complete, and then an incomplete, outdated smattering of language-specific ones including Eloquent Ruby, Effective *, and Smalltalk Best Practice Patterns.

                                    1. 5

                                      How about The Practice of Programming by Kernighan and Pike?

                                    2. 3

                                      I didn’t have an impression that the book contradicts itself.

                                      I don’t think the blog post does a good job with argumentation. Author’s rationalization after reading a paragraph is often completely different than mine.

                                    3. 8

                                      These days I write maintainable code because I have been forced to maintain my own code. Martin’s ideas were a great help to get me started on the journey, and I still draw from them periodically. So yes, I think Martin is great learning material, with the huge caveat that experience is the best teacher and Martin’s ideas are not gospel.

                                      1. 9

                                        I have yet to see maintainable code written by someone who has not spent a few years maintaining code they wrote.

                                        This effect mostly seems to kick in around the two year mark; if you change jobs every two years you may have never seen the long term impact your work had on code health.

                                      2. 5

                                        What specifically is good about it? The specific points that this article makes do strike me as egregiously bad code - and moreover, it seems like the book’s dictums are fairly closely tied to the Java ecosystem and its mandatory object oriented paradigm. If I was writing code in Rust or Haskell, what advice in this book would even be applicable?

                                        1. 5

                                          Prefer small functions over large ones, prefer consistence when naming things, write tests for your code, prefer to document the app through code/naming conventions instead of comments but remember about adding comments if you need to, remember to maintain the comments as much as the code, think about maintenance aspect when writing code, perfer abstraction over code duplication.

                                          There are lots of things in the book that are general. Granted, lots of the things are aimed towards Java. But I think think that lots of things from the book are applicable to e.g. C++. Rust is not an exception (no puns here).

                                      3. 5

                                        I offer the metacircular interpreter from SICP as a counterexample. Literally every function is abstracted there, almost down to functions fetching only car or cdr of their argument. The thing is beautiful.

                                        1. 5

                                          SICP also sprung to my mind. That book teaches how to write clean code without being specifically about clean code. For a good book about style aimed at beginners (which SICP isn’t really), I like the Practice of Programming by Pike.

                                        2. 4

                                          At the end I’ve got a feeling clean-code was written by some of the people featured in the daily wtf. Something made by someone that only shines if you don’t know anything on the topic or want to follow a cargo cult. Like when I would start writing a book about medical topics based on reading wikipedia articles.

                                          1. 4

                                            Martin says that it should be possible to read a single source file from top to bottom as narrative, with the level of abstraction in each function descending as we read on, each function calling out to others further down. This is far from universally relevant. Many source files, I would even say most source files, cannot be neatly hierarchised in this way. And even for the ones which can, an IDE lets us trivially jump from function call to function implementation and back, the same way that we browse websites. Outside of a book, do we still read code from top to bottom? Well, maybe some of us do.

                                            I strongly think that one should still write code to be written, and not rely on an IDE to navigate it. This isn’t because I think we should avoid using powerful tools (I use Emacs, after all!) but because I think that powerful tools can lure us into writing systems more complex than they should be. It is kind of like the saying that you should never write the cleverest code you can, because debugging is twice as difficult as writing — and thus writing the cleverest code you can requires that you be twice as clever as you are when you debug it. I think that the corollary is that code which relies on the skill multiplier of a good IDE to write requires an IDE with twice the multiplier to debug.

                                            1. 1

                                              Did you mean to say “write code to be read”, or was that first sentence actually talking about writing code for the end purpose of writing code?

                                              1. 1

                                                Doh, yes — that is exactly what I meant to write!

                                            2. 4

                                              Why does the code have throws Exception everywhere? It is to allow introducing checked exceptions later? Seems like he is working against the language.

                                              1. 2

                                                Java idiom has “limit your use of checked exceptions” from Joshua Bloch’s Effective Java, and many developers have run with it to mean “don’t bother writing the exception signatures in detail”. That’s actually the opposite of his recommendation, but it’s one that’s compatible with the section heading if not the body.

                                              2. 5

                                                This article by Dan is good and on the same topic:

                                                https://overreacted.io/goodbye-clean-code/

                                                1. 4

                                                  But that article is about some abstract definition of “clean” as opposed to talking about the book.

                                                2. 3

                                                  Personally I don’t think that Clean Code (or similar books) are bad per-se. The problem is that people read it and try to apply what they read blindly everywhere, without realizing that it might be introducing more problems than what it tries to fix or prevent. One reason for this IMHO is that the book portraits a very specific view of good code vs bad code with little room for the reader to understand the downside of over abstracting.

                                                  Personally, I’ve seen many codebases that made everything generic. They introduced interfaces all in the name of a “future different implementation” when in practice, even after years there have been a single implementation for that interface. It takes a bit of common sense (that IMHO comes with experience) about what to make extendable, and at which point. You also don’t need to get it right from the beginning, what needs to be extendable will become clearer as the code changes and evolves.

                                                  Like a good compressor, I don’t reuse anything until I have at least two instances of it occurring.

                                                  This is a very good thumb rule if you ask me. If you find yourself writing the same code in multiple places, this is a clear sign that something might be abstracted way.

                                                  1. 3

                                                    picked up Clean Code about a year and a half ago, made it to about page 100 before closing it for good. I was reading it on the train to work in the morning and I caught myself audibly groaning (practically yelling honestly) multiple times while reading it. I remember the code sample from chapter 3; I remember thinking it was some of the most overwrought code I had ever read.

                                                    1. 2

                                                      This is done as part of an overall lesson in the value of inventing a new domain-specific testing language for your tests. I was left so confused by this assertion. I would use exactly the same code to demonstrate exactly the opposite lesson! Don’t do this!

                                                      I disagree, slightly. I think if you have a large number of tests that cover a very specific domain, a DSL might make things easier to read and write. I was reminded of a talk given by Brian Kernighan, where at one point he reviews a tiny DSL that was used to unit-test regexes in AWK.

                                                      I think the “turnOnLoTempAlarmAtThreshold” example in Clean Code is a little too contrived, and it doesn’t really convey the idea.

                                                      1. 1

                                                        Sure, just make sure to test your test(helper)s…

                                                        When I saw “clever” and “convenient” test helpers, I encountered bugs in them masking real bugs, because the helpers had zero tests, but quite complicated logic.

                                                        I prefer DAMP tests, and test looking as clean, as in the examples in the article: preferably no control structures, or at most 1 level of them, and repeat yourself as needed, add comments when needed. Usually these are clearly understandable, while the custom DSLs needs a lot of knowledge if its internals, as rarely is it designed thoroughly to be a contradiction free as needed for writing (and especially reading) test.

                                                      2. 2

                                                        I originally read Clean Code as part of a reading group which had been organised at work. We read about a chapter a week for thirteen weeks.

                                                        I am so eager to know (a) who organised this reading group, and (b) what the goal was.

                                                        1. 2

                                                          Anybody can refactor some given source. Does Bob Martin actually write original code?

                                                          1. 9

                                                            Not anybody can refactor, and some people simply shouldn’t refactor anything. Lots of people have no idea what to focus on when writing code.

                                                            1. 2

                                                              Yeah, I guess the way I wrote my comment made it seem quite dismissive, which I regret. Really I was just wondering if Bob Martin writes original code, though I found some on his Github profile.

                                                            2. 2

                                                              Try refactoring a 10 year old java code base.

                                                              1. 3

                                                                Our term of art for similar things is “refucktoring”.

                                                            3. 1

                                                              I think that most of the principles listed in the OP are not merely executed badly, but inherently bad.

                                                              functions should do exactly one thing, and do it well
                                                              functions should not have side effects
                                                              functions should generally either be commands, which do something, or queries

                                                              Aren’t these all saying versions of the same thing?

                                                              What a “thing” is is up for debate. But even if it weren’t, let’s imagine I want a program that does two things. I suppose I could create a ThingDoer interface, advertise implementations of it somehow, and write functions to collect things, order them according to any dependency relationships, and execute them. Or I could write a function that does two things.

                                                              I think there’s a pervasive need for doing two things all the way down, too. Reading from a file both copies some data from it (a side effect!) and moves the seek head. I guess you could argue that these are both the same effect, but at that point “exactly one thing” seems too inexact to be useful.

                                                               

                                                              He says DRY

                                                              I’ve found repeating myself to be a very productive tool. Other people have said most of the things I want to here, but in short, I think copy/pasting code and then fiddling with it a bit is a better use of time than trying to minimise repetition.

                                                              I’m generally sympathetic to the view that Java the language is fine, or at least mostly sort of okay, but Java programmers use it horrible ways. One of these, and a particularly jarring one for my way of working, is that the high-level concerns of the author aren’t reflected in the structure of the source code.

                                                              In a C project, you’d generally expect files to map to how the author broke the problem down into concepts. which yields both useful orientational insights and an easy way to internalize the project layout as you work on it. If that exists in Java, it’s lost on me. I’m not sure quite why it always happens, but I’m strongly inclined to blame the obtuse fractal patterns of Java source trees on the obsession with trying to write everything as a reusable component.