5 ms·
I don't know--my impression is that most people go to far in the other direction. They write code with no thought at all for the future, and then shortly have n
by tikhonj 13y ago
I don't know--my impression is that most people go to far in the other direction. They write code with no thought at all for the future, and then shortly have nightmarish debugging sessions in spaghetti code that's impossible to extend or reuse. All in the name of a rather extreme "worse is better" philosophy.
I've certainly experienced this with some of the people I worked with recently. Anything you win in the short term gets lost several weeks--if not days--later when everything is a horrible mess. Don't even think about coming back to that code months later!
I've found that putting in a little bit of care for the future pays off even in the short term. Perhaps not on the scale of hours or days, but definitely weeks. Which is still pretty immediate.
However, how you do this is also very important. The handy rule I've been using is simple: simplicity. Improve your code by making it do less not more. If you can make code more maitainable or general by simplifying, do it. If it would require adding new concepts or mental overhead, reconsider. Try to reuse existing abstractions as much as possible.
This usually--but not always--means making your code more functional. Do you really need to write this operation in place? Do you really need to tie everything together with a bunch of implicit state changes? Probably not! This is not to say that you should never use state: just be sure to only use it when it fits well and makes sense. And be explicit about it.
The functional style (at least in languages like Haskell) also lends itself very well to reusing simple and general abstractions. The key idea here is that these abstractions are not about doing more: they're about doing less. More general code simply leaves you less room to make mistakes. If you're working with lists of numbers, there are all sorts of arithmetic mistakes you can make; if you manage to write the same code against lists of anything, the only mistakes possible will be in list handling.
Haskell just makes this more practical by providing abstractions with a great "power-to-weight ratio": ones that manage to be simple, general and yet still expressive. Code with functors or monoids or traversables is easier to write than more concrete code and yet still flexible enough for many useful tasks. As a bonus, it's also more reusable. For free.
So the key idea is reduction: all these abstractions work by stripping concrete types of power. A functor can do much less than a list. A monoid can do much less than a number. This lets you write nicer code without becoming an "architecture astronaut" because instead of adding structure, you're really taking it away.
I've found that programming like this really helps in maintaining and extending the code later on. But it doesn't slow me down when I'm writing either--I actually save time because I spend less getting time getting the code correct in the first place.
These days, I've started being able to make large changes or add complicated features and have them work on the first try. Not every time, but surprisingly often. Certainly much more often than before! In large part, I think this is because of writing the code with an eye towards simplicity.
So the important insight: take the simple route, not the easy route.
- ay 13y agoGreat advice IMHO. One trick that I found useful for myself (good chunk of my code is "hobby" code that I myself revisit some months later, so not really "production" problem but nonetheless almost the real-world maintenance example): - make the function fit in your head. Literally. Make it fit in one screen, if you can. If it does not, think how you can make it fit on the screen - everything, including variable definitions. - avoid branching as much as possible unless it is the 'exit' branches. Avoiding branching sometimes can be done by tricks like passing function pointers. Do it - it makes code much more expressive and easier to read. These two heuristics allow me to make the code much simpler to understand for $(me+6months). I saw the same patterns in real-world code at $work as well - using the above two principles makes the code dramatically easier to support later.
- jes5199 13y agoOne screen is way too big! Make each function do a single thing. Even in verbose languages, you should be able to get most of them down to 5 lines or less - and this isn't actually difficult (except for coming up with names for all of them) the transformation is actually very mechanical, so much so that if you're using an IDE it can probably "extract method" for you, but even doing it by hand is trivial once you get the knack of it.
- ay 13y agoIndeed. 25 is the maximum - mostly the shorter, the better. Though at least for me there is somewhere a limit (2-3 lines?) where the returns start to diminish - there's more noticeably more typing involved, and more mental context switching while debugging.
- Zakharov 13y agoIf you write code too slowly, go faster. If you write code too quickly, go slower. You can tell if you're too slow when you've spent two weeks thinking about the program and have neither working code nor a detailed design, or if you've created a detailed design only to realize upon implementation you'd gone about it entirely the wrong way. You can tell if you're too fast if you find yourself spending more time cleaning up messes of poorly-thought-out spaghetti code.