Live data from Hacker News

Ask HN: How to avoid over-engineering software design for future use cases?

news.ycombinator.com

121–130 of 258 posts

Re: Ask HN: How to avoid over-engineering software design for future use cases?

#121
post #67
post #32

Earlier quoted context omitted.

Unit tests are absolutely fantastic during refactoring. I once had to rewrite a piece of code where nobody really knew what it did or what it had to do, and the original author just made some guesses about the intention. I started out by writing unit tests for everything, which became my handhold and documentation for what the system originally did. Then I started reorganising the code into a more structured and more…

I would argue that having a robust type system and some (not too many) end-to-end tests for your software makes unit testing almost completely useless overhead.

End-to-end tests are more overhead than unit tests. End-to-end tests are also not great for testing the many edge cases that you are likely to mess up if you refactor carelessly.

I also don't see how a robust type really helps there. It might even be part of the thing that needs to be refactored. Besides, many languages don't have a very robust type system.

End-to-end tests and type systems certainly have their uses, but for refactoring messy code, I don't think there's a good substitute for thorough unit tests.

Although there are different kinda of refactoring of course. The case I'm referring to was about one very messy module. This makes it very easy to unit test. If instead it's the entire architecture of your application that needs to be refactored, then you're looking at a very different case, and end-to-end tests become more important than edge cases.

Re: Ask HN: How to avoid over-engineering software design for future use cases?

#122
post #68
post #18

> engineers go extreme in designing things/code for future cases which are not yet known They're afraid. Fear: If I don't plan for all these use cases, they will be impossible! I will look foolish for not anticipating them. So let's give into that fear and over-architect just to be safe. A bit of the 'condom' argument applies: better to have it and not need it than to need it and not have it. But the reality is that…

>> engineers go extreme in designing things/code for future cases which are not yet known >They're afraid. In many companies (think FAANG), engineers, especially senior engineers are incentivized/forced to show fancy design docs as part of the annual appraisal process. The more complicated the design, the more 'foresight', the better. If it sounds kind of ridiculous (TPS reports from Office Space anyone?) it is. But…

> In many companies (think FAANG) > The more complicated the design, the more 'foresight', the better.

Certainly not in Amazon. Surely there can be exceptions but in general the company has a culture of simplifying stuff anywhere is possible.

Re: Ask HN: How to avoid over-engineering software design for future use cases?

#123
I have been in this trap myself. I tried writing only perfect code. I ended up thinking more about the design than actually progressing on the issues. The solution I found was to write explicitly hacky solutions first, then improve them as you go forward. Either hacky by being slow, or by not having all the features you want it to have eventually. Not hacky by having huge bugs, don't do that, as finding them is a huge cost the later you find them! Put TODOs about the aspects that need improvement, this allows you to grep for them. Also, as you write the first implementation, you'll gain more knowledge about the problem domain than any non-coding research could give you. Maybe you don't need that one feature after all, or maybe your approach was totally wrong and you should do a different one. It's better to find that out when you only have invested time into a prototype instead of a full generic solution!

And this is not an obligation. If you are really sure about the design of some component, you can also do it right the first time. But in most places, you usually don't know the design well enough.

Also, the imperfect solution can help as a validator. Have a problem that has a unique solution? Make a slow algorithm for it which you are sure is correct, then build a faster version and use the slow algo to compare for correctness. You can also use the slow algorithm to tell you about non-output values that both algorithms compute implicitly or explicitly.

Re: Ask HN: How to avoid over-engineering software design for future use cases?

#124
post #98

Earlier quoted context omitted.

If the code is a mess the type system can’t help, it is part of the mess. End to end tests are really slow, but if you can get them into the 300-1600 tests per second range then i have no beef. I value tests but I seriously grudge waiting for tests.

If the code is that bad, unit tests aren't going to help you. Messy spaghetti code with massive structural issues will break every unit test every time you change anything in the code, in ways that make no sense and provide you with little useful information. You will fix things faster if you just let the tests fail, fix the code and then rewrite the tests. Which makes the unit tests useless. Also, have you ever seen…

What do you mean with "perfect" unit tests? For this case, I wrote the unit tests to document the current functionality. That's basically what unit tests do: they document functionality and enable you to preserve that functionality of that piece of code. Of course once you realise that the functionality is wrong, you should change it and the unit test. And you can't fix the code if nobody knows what it's meant to do.

There's quite a lot you can refactor without breaking unit tests. If you've got a single 200-line function full of nested loops with cryptic variable names, modern IDEs make it really easy to extract those loops to their own functions. Figure out what they're meant to do, give them a descriptive name, and you already improved the code a bit without breaking any unit tests. If your IDE does this well, you could even do this without unit tests, but you really will need those unit tests once you start reorganising the code making use of the excessive number of parameters those extracted functions invariably end up with.

Of course you can write unit tests for super bad code. If it's a function that returns something, it's trivial to unit test, no matter how badly written that function is. If it calls other code, you have to mock those calls and test that those mocks get called under the same conditions. If they mess with global variables, that's terrible, but even that can be mocked.

If the code uses gotos to code outside the module, somebody needs to get shot, and I guess you need a unit testing framework that can mock those gotos. I've never seen one, because nobodoy uses gotos anymore.

Re: Ask HN: How to avoid over-engineering software design for future use cases?

#125
It's a balancing act.

You need to always ask yourself "What are the reasonable future use cases? How much will it cost to add infrastructure now to enable each of them, and how much will completing the feature in the future cost? How much will it cost to refactor my code later to add it if I don't make preparations for it now?" and only prepare now for things where not preparing would cost a lot more.

I'm finding the game of Go (Weiqi, Baduk) to be a great way to train in this skill, because it's all about seeing potential moves and deciding not to play them yet, and judging if a move should be played sooner or later and how much of a shape should be built now to enable it to be built later without wasting resources on building all of it now.

Re: Ask HN: How to avoid over-engineering software design for future use cases?

#126
post #90

32 comments so far and no mention of the word budget. There's a great analogy between software engineering and construction. Does your organization build skyscrapers and gorge-spanning bridges? Or does it build driveways and swimming pools? Commercially developed software consumes capital to get something in return. Are the people spending capital budgeting for a driveway or for a skyscraper? Must it be done this mon…

I've reprogrammed myself to only get the dopamine hit when I delete old or unneeded code :-)

Deleting code is one of the most satisfying things in the world. Puff and gone are all the worries, all the bugs, all the maintenance hassle, all the limitations that code imposed on you.

Re: Ask HN: How to avoid over-engineering software design for future use cases?

#127
post #84

You should immediately stop designing for future use cases. Use TDD and only write only just enough code for the currently known required functionality. When you get to know more required functionality the tests protect you from breaking existing functionality and you can extend your code to support the new use cases as well. At this point you should make your code just generic enough to support all known use cases w…

TDD has costs. It's expensive and only works on certain types of systems. It also makes exploration of the problem domain extremely costly and makes refactoring a nightmare. I dislike TDD full stop but there are some domains where it's unambiguously a bad idea.

It implies:

- Behaviour can and should be compartmentalised

- Certain types of efficiency are ignorable

- Data structures are better off being relatively simple

- Behaviour is able to be understood before the system emerges

- The system doesn't fundamentally need a lot of mutable state

- Dispersing functionality across small, atomic functions (that obscure sequential flow and state mutation) is good for the code

- It is easy to extract the functionality of this system into pure functions

- A high-level veiw of the system is unnecessary (!)

- In this system, most bugs will come from small units, not interactions between units

- Behaviour of units is likely to be relatively unchanging

- Refactoring primarily happens between interfaces, not to them

- Test rigging is cheap and easy at every level of abstraction, or at least that it's better to contort your system into a structure where that's true

None of these things are a given.

Re: Ask HN: How to avoid over-engineering software design for future use cases?

#128

32 comments so far and no mention of the word budget. There's a great analogy between software engineering and construction. Does your organization build skyscrapers and gorge-spanning bridges? Or does it build driveways and swimming pools? Commercially developed software consumes capital to get something in return. Are the people spending capital budgeting for a driveway or for a skyscraper? Must it be done this mon…

This is a good response. One of the things that has helped me temper myself is to explicitly consider the ROI of my work. If I do this, will I save more time in the long term than I expend doing it? Depressingly often, the answer is "no".

Software engineering has the potential to earn a lot of money with relatively little effort.

This is both a blessing and a curse: if I just do anything that I feel like, maybe only 5% of what I do would actually carry a profit – but that profit would be big enough to compensate for the other 95% of the time when I only do things that make me feel good without getting any real return from it.

If your goal is to produce maximum value, you have to think very long and hard about what projects you take on. It is worth taking the time to consider projects and research their viability, because very many of them won't pay off in the long run. You'll have to get used to saying "no" to anything that doesn't have an obvious route to profit.

On the other hand, if your goal is to have a little fun along the way and not only to produce maximum value, you can use this fact to your advantage! If you know you've rejected a bunch of low-value projects recently, you can afford to take on some low-value (but fun!) projects and still sit firm in the knowledge that you're still producing net value in total. Because the 40% of projects you've done that do produce a lot of value will easily pay for the other 60% that aren't obviously profitable. Or whatever ratio you settle at.

Re: Ask HN: How to avoid over-engineering software design for future use cases?

#129
post #68
post #18

> engineers go extreme in designing things/code for future cases which are not yet known They're afraid. Fear: If I don't plan for all these use cases, they will be impossible! I will look foolish for not anticipating them. So let's give into that fear and over-architect just to be safe. A bit of the 'condom' argument applies: better to have it and not need it than to need it and not have it. But the reality is that…

>> engineers go extreme in designing things/code for future cases which are not yet known >They're afraid. In many companies (think FAANG), engineers, especially senior engineers are incentivized/forced to show fancy design docs as part of the annual appraisal process. The more complicated the design, the more 'foresight', the better. If it sounds kind of ridiculous (TPS reports from Office Space anyone?) it is. But…

[deleted]

Re: Ask HN: How to avoid over-engineering software design for future use cases?

#130
post #68

Earlier quoted context omitted.

>> engineers go extreme in designing things/code for future cases which are not yet known >They're afraid. In many companies (think FAANG), engineers, especially senior engineers are incentivized/forced to show fancy design docs as part of the annual appraisal process. The more complicated the design, the more 'foresight', the better. If it sounds kind of ridiculous (TPS reports from Office Space anyone?) it is. But…

> In many companies (think FAANG) > The more complicated the design, the more 'foresight', the better. Certainly not in Amazon. Surely there can be exceptions but in general the company has a culture of simplifying stuff anywhere is possible.

>simplifying stuff anywhere is possible

https://raw.githubusercontent.com/aws-samples/aws-refarch-wo...

Ironically, that's how you are supposed to run Wordpress on AWS.

Post reply on HN