Live data from Hacker News

Code doesn’t have to be a mess

danielsieger.com

141–150 of 190 posts

Re: Code doesn’t have to be a mess

#141

Earlier quoted context omitted.

Jumping around is the nature of code in general, whether its in a 1000-line file or split up amongst multiple files. For a maintenance programmer, they may already understand how everything works. They aren't following a particular code path, necessarily. Maybe they're working on a new feature and they need to re-familiarize themselves with previous chapters. It that case, it's nice to jump to a file that concerns it…

>> things grouped nicely together fixed it for ya :) I'm a maintenance programmer. Even working layers of layers of layers above the actual shit does not make it not stink. >> jumping around ...should be intuitive and joyful, not a disaster to your brain. EDIT: I am a fan, though, of SOC. I guess enterprisey code tries to be that (but fails hard at it).

Okay, great. You are a maintenance programmer. You have a 1000-line program all in one file. You need to update the e-mail functionality of this program. You aren't following a stack trace or following a particular code path. There are 15 or 16 different e-mail related functions. How do you find the e-mail function you need to update? Do you memorize line numbers? Use regex search? Do you have vim marks setup?

Re: Code doesn’t have to be a mess

#143

Also: If requirements change or new features are added, rather than only making the changes nescessary to existing code, rewrite code it touches. This forces you to keep all corner-cases in mind and will lead to more correct code. In a similar vein, when starting a new project form scratch, first do a quick and dirty prototype and then throw everything away and start anew. This way you know up-front what the challeng…

That doesn't work, and it comes from experience. The messiest bit of our code base is the business logic, which out of necessity, is intertwined with I/O logic (we have very tight timing requirements, and we have to query several sources of data over the network) and we only ever add new requirements, never retire old ones (or at least, that's been the case over the past 12 years). Rewriting the code the new requirements touches is pretty much out of the question.

About eight years ago I started a "proof-of-concept" that my manager asked for. I was using Lua for ease of development, and LPEG because it involved a ton of parsing. My intent was to get a handle on what was required and then do it C or C++. I found out a few months after the fact that my "proof-of-concept" was, in fact, in production and running. So much for my quick and dirty prototype. (And in retrospect, it hasn't turned out that bad---the code is way easier to deal with than our business logic in C/C++ because of Lua's coroutines make the event driven code look linear, and it's been fast enough).

Re: Code doesn’t have to be a mess

#144

Earlier quoted context omitted.

> I tend to write reference implementations of everything, then combine them together as a separate project. This is how I write software. My stackblitz is full of domain independent experiments https://stackblitz.com/@Pyrolistical . I then copypasta this into private projects once I figured out how the individual piece works.

Yeah I love this approach too. I’ve been learning CRDTs lately and I’ve gotten so much value from making tiny, inefficient reference implementations of things before diving in and optimizing. Toy implementations shake out all your misunderstandings of your design, and you can refactor like crazy. Going from simple code that works to complex code that works is much easier than creating the complex code correctly from…

Also I've discovered (and reported) so many bugs when I realized my very simple toy example was broken

Re: Code doesn’t have to be a mess

#145
post #117

Earlier quoted context omitted.

The book analogy you use isn't very accurate. Even if you merge chapters and paragraphs like that, you still read it sequentially. Just in a less comfortable way. Which is not at all like a modern codebase that is modular, abstracted, etc. If you're new to a codebase, and want to understand one particular feature, you'd likely need to jump back and forth across 10 files. It's not far-fetched to say that makes it diff…

The thing is that if you just need to understand a specific part of something you will need to jump as well even if everything you needed for that one thing is written sequentially in one file. You will want to skip over implentation details of certain things to get the general picture first on a more abstract level. Let's say you have a simple endpoint that takes a list of comma separated inputs, parses them as numb…

You can easily understand what it does because you picked an example that is easy to understand :)

This discussion often ends up in the extremes: inline everything versus abstract everything. I don't think anybody reasonable would opt for either of those extremes, we should focus on the very large middle ground where there's a lot of subjectivity.

Trust me on this, I've been raised on the DRY dogma and all related architectural patterns in favor of abstraction. I've lived the life, for 2 decades. But I cannot ignore the outcomes. Most codebases are extremely difficult to understand and it's very painful to change things. As 90% of all software development is maintenance, that's a planetary-sized problem.

This doesn't mean you should inline everything, it means sane choices. As a simple example, say you're using a literal in your code:

(if orderAmount > 100000)

This code is incredibly easy to read. Common convention says to put this in a constant, at the top of the file. Old me agrees, new me does not. For as long as it's the only occurrence of the value, it doesn't need abstraction. The only thing it would do is make the code more difficult to understand. The very eager abstracter might even put that constant in a separate file.

The point of this example is to abstract based on real reuse, not imagined reuse. I'm not against abstraction only against unnecessary abstraction.

A second example. Say you have a reusable UI component. A change request comes in that's pretty large and specific for one niche need. It kind of goes against the spirit of the initial purpose of the component but is still related enough to consider it in scope of the component.

Old me might add a "toggle" to the component, after which it can render in two modes. Sometimes called a "god component". This approach sucks. It makes the component much more complicated and changing and testing it becomes a nightmare.

Even older me would break down the component into smaller components and then "compose" them based on its mode. This is even worse, now you have to jump around many places whilst the sub components are never actually reused (pointless abstraction).

New me says fuck it and splits the component in two. Allowing significant code duplication between both components. It's not as radical as it sounds, it's in fact incredibly comforting. Each component can easily be understood (less complexity) and making changes becomes far less stressful as your blast radius is tiny.

Developers spent the vast majority of their time not coding, instead figuring out how something works and how to make a change that doesn't break anything.

Re: Code doesn’t have to be a mess

#146

> Minimize Dependencies ... Consider doing it yourself. This is terrible advice! Maximize your dependencies. Adopt as much external code as possible. Build what you can with it. Then, as you reach the limits of those dependencies, and you absolutely understand what needs to get done replace them as you need to. The vast majority of what people write will be trashed and/or changed radically. You should adopt whatever…

Honestly, I think you're both wrong. You shouldn't be trying to minimize or maximize your use of dependencies. You should add a dependency when it makes sense and write your own code when it makes sense. Doing more complex time and date work, then a good solid library for manipulating datetime variables will save your sanity. Need to right justify a string to set length then using a leftpad will leave you at the merc…

To me, the best case scenario is adding a dependency of medium size and complexity that you're confident you could write yourself. This means that if you run into problems, you can just shrug, and then ditch the library, but if it's ok then you save some time. What's terrifying is dependencies so large that you can't fathom the amount of effort required to make them. It also makes it much harder to tell if the library is actually any good. Luckily for your example of time libraries there's normally a "blessed" library for whatever ecosystem you're in. Tiny / super simple dependencies are a complete waste of time, if I can write it in IMO there's a lot to be said for writing your own version that does 60% of what some library does, but 100% of what you need it to do.

Re: Code doesn’t have to be a mess

#147

> Minimize Dependencies ... Consider doing it yourself. This is terrible advice! Maximize your dependencies. Adopt as much external code as possible. Build what you can with it. Then, as you reach the limits of those dependencies, and you absolutely understand what needs to get done replace them as you need to. The vast majority of what people write will be trashed and/or changed radically. You should adopt whatever…

This might start a fire here but I think dependencies are actually the problem, and see it happening in real time with all the latest gRPC offshoots for inter-service communication (Seems like there is a new one every day). The libraries attempt to "dumb down" TCP, HTTP, etc and treat them as an abstraction that you don't need to know the details of. But it ends up biting people in the a$$ because networking isn't a…

Agreed, it's not like you'll really forget how to write a Berkeley socket; couple of deques, mutexes and an header later just saved you forty gigs of BOOST BEAST.

Re: Code doesn’t have to be a mess

#148

In my experience people refactor code to their own understanding of the problem and not all refactorings improve the code. People abstract before an abstraction is necessary. I find single file dense leetcode style code easier to understand and follow the flow. Algorithmic code I can reason around. A large mature codebase is far harder to get to know. One of the first things I do when I study a new codebase is find a…

Generally most of my refactoring is cutting out code; I love an excuse to chunk down excessively verbose classes.. maybe I'm weird but I generally prefer a lean, concise codebase that might share a few free functions than a perfect OOP pyramid.

Re: Code doesn’t have to be a mess

#149

Earlier quoted context omitted.

>> things grouped nicely together fixed it for ya :) I'm a maintenance programmer. Even working layers of layers of layers above the actual shit does not make it not stink. >> jumping around ...should be intuitive and joyful, not a disaster to your brain. EDIT: I am a fan, though, of SOC. I guess enterprisey code tries to be that (but fails hard at it).

Okay, great. You are a maintenance programmer. You have a 1000-line program all in one file. You need to update the e-mail functionality of this program. You aren't following a stack trace or following a particular code path. There are 15 or 16 different e-mail related functions. How do you find the e-mail function you need to update? Do you memorize line numbers? Use regex search? Do you have vim marks setup?

>> here are 15 or 16 different e-mail related functions

Is this you showboating the greats of layered code?

Depth is not width and width is not depth, but surely you see the difference in the two?

Re: Code doesn’t have to be a mess

#150
post #105

In my experience people refactor code to their own understanding of the problem and not all refactorings improve the code. People abstract before an abstraction is necessary. I find single file dense leetcode style code easier to understand and follow the flow. Algorithmic code I can reason around. A large mature codebase is far harder to get to know. One of the first things I do when I study a new codebase is find a…

> One person's beauty is another person's mess. This is so true. Also I believe that when the original author wrote the code he had a (hopefully) clear vision of the solution. He wrote it as tidy and fitting to the problem as he saw it. Then sometime later someone else comes in and is supposed to alter the code in a way which does not fit the original author’s idea of the problem. This creates a mismatch. The new guy…

Spot on. You've described Peter Naur's "Programming as Theory Building" paper exactly.
Post reply on HN