Hacker News new | past | comments | ask | show | jobs | submit login

Biggest underlying reason for why software ends up complex, is because real world domain in which software operates, is also complex.



That together with the fact that nobody gets promoted and nobody collects revenue by simplifying or refactoring code.


People do get promoted and paid for simplifying and refactoring code. Heck, I got promoted and am currently being paid to do just that. It often involves adding value in other ways simultaneously, but what you said is just false.


I guess it's dangerous to use words like "nobody" or "everyone" or "always" or "never" on the overly pedantic Hacker News. I would hope that the sentiment of my point came across either way. If not, let me clarify: it's generally preferred to spend engineering effort on building new features and optimizing code to improve performance etc. over e.g. rewriting code from scratch to simplify it's maintenance. I would venture to guess that an overwhelming amount of engineering effort is spent on effectively adding complexity to code.


Whoever is able to demonstrate the value of a sequence of work to the business will get their work prioritized. Product’s job is to shape and predict the value of adding new features. Customer complaints about slow reports help Customer Support justify performance optimizations.

If engineers want the business to pay them for simplifying maintenance, they can identify a collection of support tickets that have a compelling root cause, and propose refactoring that system to eliminate the bugs and maintenance issues.

What I usually see is us engineers calling it “tech debt” and complaining we never take time for it, which is about as effective as the bookkeeper complaining about the paperwork that debt payments create for him. Businesses love debt. It’s a useful financial tool. The business doesn’t get the issue.


Funny that I'm nobody again. I work for a big german retailer. A big part of my work includes simplifying and refactoring code, so that we have lower maintenance cost and can move faster as a organisation unit. This was also a big factor in my last promotion.

We also increased profit by lowering our runtime cost by some of those optimizations.


If I were a betting man, I would bet that the main reason why you're allowed to do that is because you lowered runtime costs by some of those optimizations, not because of the cleaner code you can move faster.


? not parent, but I am really surprised by that mindset.

A large part of my career has been telling my boss "we should invest 5h of cleanup time here to make sure that in the future we won't have those 5h worth of obstacles here before building a new feature on top of it".

In industries where requirements change on a weekly or monthly basis, agility is worth a lot.


I completely agree. My bet would be the bosses usually don't. So in a lot of places you need another "excuse" (or as another poster mentioned, spend the time saved to invest more into maintainability but cover it up).


You can trade on previous achievements to spend time improving your codebase (unless you have a micromanager that tracks every hour).


Not directly. But simplifying and refactoring can help you understand the code better than doing routine maintenance. This helps you solve bugs and write new features faster and with more stability, and also give better input during meetings.

So, indirectly, yes: you can get promoted and collect revenue by simplifying and refactoring.


I don't know if I agree with that.

Most of the complexity and bugs I see in software are not because of the problem domain, but rather because of over-abstraction, under-abstraction and abstraction leaks, and also because of limitations and complexities introduced by the programming model or environment.

(unless you consider that "supporting five operating systems and the language must be X" is part of "essential complexity")

Of course, the more complex your domain is, the bigger is the program. But the non-essential complexity that exists due to the bureaucracy of languages/libraries/frameworks is a much bigger factor in adding complexity, bug and lines of code. Some examples:

- Manual allocation and deallocation of memory is a good example of something that we might think as essential, since it's intertwined with our domain code, but turns out to be unnecessary (even though the replacement has downsides). The billion-dollar problem (nulls) is another one.

- Supporting multiple environments/browsers/platforms. Competition is good, but the cost is steep for third-party developers. Using multiplatform frameworks partially solves but also has drawbacks: performance, limitations, bugs, leaky abstractions. If you need to be closer to metal, then different OSs have different threading models or API styles. Sometimes they don't even expose the main loop to you. You need to work around those limitations.

- In most environments we still don't have a nice way of handling async operations without leaking the abstraction. The current solution is adding "isLoading" data everywhere (or creating some abstraction around both buttons and the fetching mechanism). Concurrent Mode in React is probably the best thing we have so far.

- Most modern Javascript toolchains need multiple parsing steps: in the transpiler (to convert to ES5), in the bundler (to detect dependencies), in the linter, in the prettifier, and in tests. Compatibility between them is not guaranteed, and you might get conflicts which have to be solved by finding a middle ground, and that sometimes take more time than writing features.

- Dogmatism is another issue. I remember in one workplace years ago there was a "ORM only" rule and most of us would work the SQL and then convert to Rails ActiveRecord (or worse: Arel). In the end it was a complete waste of time and the results were impossible to maintain.

- I also think that the old Peter Norvig quote that "design patterns are missing language features" still stands. Go has proven that it's possible to have "dumb, simple code", but in other languages our best practices involve adding non-essential complexity to products.

The only exception to that in my experience is SQL: if a query is too big is not due to some bureaucracy of the language, but rather due to the complexity of the domain itself.


For me what you're describing is more mess than complexity. I see your point tho, but I'd also say that some of things you describe here are direct result of real world problem domain being complex, and changing over time.

For example, wrong abstractions. As long as engineers writing the software are competent (if they aren't - that's a totally different story) they'll try to chose right level of abstractions for current understanding of the problem. Years down the road, a lot of their choices maybe end up to be a mistake, very often because understanding of the problem changed, or problems itself changed, and something that was nice and clean solution isn't one anymore. If problem isn't fully fixed and 100% understood, you'll never be able to make all the right, future-proof decisions about right abstractions.


Yes, it is "mess". But it's also additional complexity that is non-essential to the problem. It's what Fred Brooks called accidental complexity in his No Silver Bullet essay. It is important for us to acknowledge and differentiate between the two kinds of complexity, because we in the software industry can and should aim at reducing the accidental/non-essential type.

About abstraction, even when it's good, it still depends. For example: you can use a Visitor Pattern to solve a collision detection problem, but if the language had multiple dispatch you would have less complexity. So it is definitely non-essential complexity.


But multiple dispatch could also be argued as non-essential complexity... I would much prefer a visitor pattern for the abstraction benefits, for example.


But that's not the point, that's not an example to be picked apart. The point is if there's a less complex way to solve the problem, then it's still causing non-essential (aka accidental) complexity. Even if the simpler solution is ugly, the more complex one is still introducing non-essential complexity. If we claim that every single thing we do with the code is part of the "real world problem", then we're throwing up our hands in the air and giving up on the problem of complexity of software. It's a naive and simple justification that's very comfortable for us, but doesn't amount to much. I really recommend reading the No Silver Bullet paper and Mythical Man Month. Fred Brooks explains those things very well.




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: