TITLE: How to Write Code That Doesn't Get in the Way AUTHOR: Eugene Wallingford DATE: October 25, 2016 3:33 PM DESC: ----- BODY: Last week some tweeted a link to Write code that is easy to delete, not easy to extend, an old blog entry by @tef from last February. When I read it yesterday, I was nodding my head so hard that I almost fell off of the elliptical machine. I have done that before. Trust me, you don't want to do it. You don't really fall; the machine throws you. If you are moving fast, it throws you hard. I don't gush over articles in my blog as much these days as I once did, but this one is worthy. If you write code, go read this article. Nothing I write hear will replace reading the entire piece. For my own joy and benefit, though, I record a few of my favorite passages here -- along with comments, as I am wont to do.
... if we wish to count lines of code, we should not regard them as "lines produced" but as "lines spent".
This is actually a quote from EWD 1036, one of Dijkstra's famous notes. I don't always agree with EWD, but this line is gold and a perfect tagline for @tef's entry
Building reusable code is easier to do in hindsight with a couple of examples of use in the code base, than foresight of ones you might want later.
When OO frameworks first became popular, perhaps the biggest mistake that developers made was to try to write a framework up front. Refactoring from multiple programs is still the best way for most of us mortals to create a framework. This advice also applies to cohesive libraries of functions.
Aside: Make a util directory and keep different utilities in different files. A single util file will always grow until it is too big and yet too hard to split apart. Using a single util file is unhygienic.
Golf clap. I have this pattern. I am glad to know that others do, too.
Boiler plate is a lot like copy-pasting, but you change some of the code in a different place each time, rather than the same bit over and over.
For some reason, reading this made me think of copy-and-paste as a common outcome of programming language design, if not its intended effect.
Boilerplate works best when libraries are expected to cater to all tastes, but sometimes there is just too much duplication. It's time to wrap your flexible library with one that has opinions on policy, workflow, and state. Building simple-to-use APIs is about turning your boilerplate into a library.
Again, notice the role refactoring plays here. Build lots of code that works, then factor out boilerplate or wrap it. The API you design will be informed by real uses of the functions you define.
It is not so much that we are hiding detail when we wrap one library in another, but we are separating concerns: requests is about popular http adventures; urllib3 is about giving you the tools to choose your own adventure.
One of the things I like about this blog entry is its theme of separating concerns. Some libraries are perfect when you are building a common application; others enable you to build your own tools when you need something different.
A lot of programming is exploratory, and it's quicker to get it wrong a few times and iterate than think to get it right first time.
Agile Development 101. Even when I know a domain well, if the domain affords me a lot of latitude when building apps, I like explore and iterate as a way to help me choose the right path for the current implementation.
[O]ne large mistake is easier to deploy than 20 tightly coupled ones.
And even more, as @tef emphasizes throughout: It's easier to delete, too.
Becoming a professional software developer is accumulating a back-catalogue of regrets and mistakes.
When we teach students to design programs in their first couple of years of CS, we often tell them that good design comes from experience, and experience comes from bad design. An important step in becoming a better programmer is to start writing code, as much as you can. (That's how you build your catalog of mistakes.) Then think about the results. (That's how you turn mistakes into experience.)
We are not building modules around being able to re-use them, but being able to change them.
This is one of the central lessons of software development. One of the things I loved about OO programming was that it gave me another way to create modules that isolated different concerns from one another. So many folks make the mistake of thinking that objects, classes, and even frameworks are about reuse. But reuse is not the key; separation of concerns is. Design your objects that create shearing layers within your program, which make it easier to change the code.
It isn't so much that you're iterating, but you have a feedback loop.
As I blogged recently, competence is about creating conditions that minimize mistakes but also help you to recognize mistakes quickly and correct them. You don't iterate for the sake of iterating. You iterate because that's how you feed learning back into the work.
The strategies I've talked about [...] are not about writing good software, but how to build software that can change over time.
This blog entry isn't a recipe for writing good code. It's a recipe for creating conditions in which you can write good code. I do claim, though, that all other things being reasonably equal, in most domains, code that you can change is better code than code you can't change.
Good code isn't about getting it right the first time. Good code is just legacy code that doesn't get in the way.
That is a Kent Beck-caliber witticism: Good code is just legacy code that doesn't get in the way. This blog entry made me happy. -----