
How to Build Good Software - jingwen
https://www.csc.gov.sg/articles/how-to-build-good-software
======
mr_tristan
This struck a chord with me: "Software Is about Developing Knowledge More than
Writing Code"

I've experienced more issues caused by management passing around tasks between
teams and never paying attention to knowledge and knowledge transfer.

What's amazing, is that in over 18 years as a software engineer, I've seen
this so many times. Teams will function well, then the institution tries to
change. Often they will try to open up the "innovation" by throwing money at
R&D, basically trying to add bodies in order to grow. Then you have tons of
teams, and communication becomes very challenging, so then they grow some kind
of "task management" layer. Management that never understands who actually
_knows_ something, just tracks how much "theoretical bandwidth" they have and
a wishlist of features to create. And then the crapware really starts flowing.
And then I get bored and move on to the next place.

~~~
clumsysmurf
> "Software Is about Developing Knowledge More than Writing Code"

The company I work for uses Scrum. They consider the User Stories + the code
to be everything you need. I struggle with this, but my manager says they
don't want to get tied up doing documentation "because it goes out of date".
Beside, they are being Agile which "prefers working code over comprehensive
documentation".

I am wondering what other companies do to capture this "distilled knowledge".
The backend services I rely on are undocumented beside some paltry swagger
that leaves much to be desired. The front end has no product-level "spec", if
you want to rebuild the thing from scratch. There isn't even a data
dictionary, so everyone calls the same thing by different terms (in code, and
conversation).

There are just user stories (thousands) and code.

Does anyone have any suggestions on how to fix this?

~~~
PaulRobinson
"prefers working code over comprehensive documentation" does not mean "don't
do documentation".

Documentation is essential. How things work is an important thing to document.
Ideally it should be in version control and be generated from the code,
because then it's less likely to go out of date. It still has problems (What
do you do when the code and the documentation disagree? Which is correct?),
but they're not as severe as the problems that arise when there is no
documentation at all.

What is less useful is having comprehensive documentation for those things
that are yet to exist. Writing a few hundred pages of specification and
handing it over to the dev team is waterfall, and it is _this_ that the Agile
manifesto signatories were interested in making clear.

I'd fix it with strategic DDD - I'd develop at least a "ubiquitous language"
(or a UL): I'd get others to work with me on having clear terminology and
making sure that is used consistently both in user stories and in the code
base. That's table stakes.

I'd then event storm the contexts I'm working in and start to develop high
level documentation.

Even at this point relationships between systems emerge, and you get to draw
circles around things and name them (domains, contexts), and the UL gets a bit
better. At this point you can start to think about describing some of your
services using the UL and the language of domains and contexts.

By that point, people should start to click that this makes life easier -
there is less confusion, and you're now all working together to get a shared
understand of the design and the point of DDD is that the design and the code
match.

The first part (all 100+ pages of it), of the Millet and Tune book on DDD will
pay you dividends here.

If that doesn't work, look around for somewhere else to work that understands
that software development is often a team sport and is committed to making
that happen.

~~~
JohnBooty

        Documentation is essential. How things work is an important thing to 
        document. Ideally it should be in version control and be generated 
        from the code, because then it's less likely to go out of date. 
    

My solution to this is old and fairly unpopular, but I stand by it: _anything
in the codebase that 's not obvious to a new maintainer should have a brief,
explanatory code comment._

Generally, this falls into two categories.

1\. Hacks/kludges to get around bugs in hardware, external services, or
included libraries. These manifest in code as incomprehensible, ugly bits of
code that are difficult to distinguish from code that is simply "sloppy" or
uninformed. More importantly, they represent _hard-won knowledge._ It often
takes many programmer-hours to discover that knowledge, and therefore many
dollars. Why throw it away? (Tip: include the version of the dependency in the
comment, ie)

    
    
        # work around bug in libfoo 2.3, see blahblahblah.com/issues/libfoo/48987 for info
        # should go away once we can upgrade to libfoo 3..
        if error_code == 42 reset_buffer()
    

...so that future programmers (including you) can more easily judge whether
the kludge is still needed in the future.

2\. Business logic. This too is difficult/impossible to discern from looking
at code. Often, one's git commit history is sufficient. But there are any
number of scenarios where version control history can become divorced from the
code, or require a fair bit of git/hg/svn/whatever spelunking to access. And
this of course becomes increasingly onerous as a module grows. If there are
200 lines of code in a given module, it is a significant time investment to go
git spelunking for the origins of all 200 lines of code. Some concise internal
documentation in the form of code comments can save an order of magnitude or
two of effort.

    
    
        It still has problems (What do you do when the code and the 
        documentation disagree? Which is correct?), but they're not as 
        severe as the problems that arise when there is no documentation at all.
    

This is pretty easy to enforce at code review time, prior to merging.

In the first place, only a true maniac would intentionally update

    
    
        # no sales tax in Kerplakistan on Mondays
        return nil if country_code==56 and day_of_week==1
     

...without updating the associated comment. If they do neglect to update it,
that's an easy catch at review time.

~~~
irishsultan
While I still would add a comment about the why, your last bit of code
probably should be written without magic constants.

    
    
        # Some countries have sales tax rules dependent on the day of the week
        return nil if country_code==KERPLAKISTAN and day_of_week==MONDAY
    
    

The exact comment here could probably be more specific (e.g. where do you find
these rules), but it also most likely shouldn't repeat the code (and the code
should make clear what it represents).

~~~
arethuza
But don't do what one memorably awful project I had to maintain did - to use
that example they would have done:

country_code==FIFTY_FIVE and day_of_week==ONE

~~~
spuz
But what if the definition of 55 changes? You'll be glad to have your table of
constants then.

~~~
arethuza
The project also defined HTTP, COLON, SLASH, WWW and DOT so that you would
have:

    
    
       string url = HTTP + COLON + SLASH + SLASH + WWW + DOT ...
    

I swear I'm not making this up....

~~~
rpmisms
Sounds like a PHP codebase I'm currently working in. I shit you not, $LI =
'<li>' is in the functions file, along with $LI_END.

~~~
arethuza
It was a _very_ enterprisey Java codebase from the bad old days of J2EE - it
had somewhere over 30 layers of abstractions between the code in a JSP and a
web service call.

[NB 30 isn't an exaggeration - I think the vast team who wrote it were paid by
the abstraction or something].

------
stygiansonic
Some good tidbits from the government perspective on software development:

“ _Beware of bureaucratic goals masquerading as problem statements. “Drivers
feel frustrated when dealing with parking coupons” is a problem. “We need to
build an app for drivers as part of our Ministry Family Digitisation Plans” is
not. “Users are annoyed at how hard it is to find information on government
websites” is a problem. “As part of the Digital Government Blueprint, we need
to rebuild our websites to conform to the new design service standards” is
not. If our end goal is to make citizens’ lives better, we need to explicitly
acknowledge the things that are making their lives worse._ ”

~~~
dehrmann
This also very much reads like something from Singapore.

~~~
solveit
A quasi-Orwellian dystopia Singapore may be, but their government is
effective.

~~~
bsder
Only for certain strained definitions of "effective".

And, if you are on the wrong side, it is very "effective" at ruining your
life.

Most of us would take a bit less "effective" in order to avoid that, thanks.

~~~
solveit
I don't understand the point of replying like this. Clearly we agree that the
Singaporean government is very good at getting things done, and we agree that
the things it wants to get done are horrible. Why are you speaking as if our
opinions differ? Why manufacture conflict where none exists? Is calling
something a quasi-Orwellian dystopia now too subtle an expression of
disapproval?

~~~
ValentineC
> _Clearly we agree that the Singaporean government is very good at getting
> things done, and we agree that the things it wants to get done are
> horrible._

Singaporean here. The government's mainly effective for tasks that are on a
happy path. If your particular case falls through the cracks, it often takes
phone calls, printing, postage, and weeks or months of waiting to get stuff
done.

(Personal experience trying to get business stuff done _not_ as a Private
Limited company.)

~~~
cuddlybacon
> If your particular case falls through the cracks, it often takes phone
> calls, printing, postage, and weeks or months of waiting to get stuff done.

That sounds like the happy path for dealing with the Canadian government.
Well, except the months part.

------
jrumbut
I thought "what a bold title, if someone's figured it out we can just close
HN" and upon reading, hey it's not far off.

The following is a wonderful point I have hardly ever heard said directly:

"The main value in software is not the code produced, but the knowledge
accumulated by the people who produced it."

~~~
unityByFreedom
weird, I've heard it said frequently for decades in various forms,

"value your knowledge workers"

"your employees are your most valuable asset"

Some companies don't treat employees well, and some employees at good
companies feel they are not treated well enough

If the above quotes do not strike a chord with you, you might just be a
software engineer who thinks you're more important than non-SEs.

~~~
jrumbut
The difference, for me, is that neither of those quotes explain why you should
value knowledge workers or why employees are valuable (maybe hiring is
expensive, maybe turnover reduces morale, etc), nor do they suggest the
mechanism that creates this value.

I'm sure another author has put the same sentiment out there before, but it's
not every day I see such a nice phrasing of it.

~~~
unityByFreedom
> neither of those quotes explain why you should value knowledge

I mean, the point of short quotes is to be memorable and get future listeners
to hunt for the reason behind them. "The sun will rise tomorrow" may also be
meaningless for some people on its own.

Nothing wrong with elaborating on this subject again via a blog post, I was
just pointing out to the commenter who's never heard this expressed before
that it has a long history, that's all.

------
iEchoic
> Reusing software lets you build good things quickly

It also introduces unknown amounts of debt and increases the likelihood that
you'll end up with intractable performance/quality/velocity problems that can
only be solved by re-writing large portions of your codebase.

This can be a dangerous cultural value when it's not presented with caution,
which it isn't here. I think it's best to present it alongside Joel Spoelsky's
classic advice: "If it’s a core business function — do it yourself, no matter
what".

[https://www.joelonsoftware.com/2001/10/14/in-defense-of-
not-...](https://www.joelonsoftware.com/2001/10/14/in-defense-of-not-invented-
here-syndrome/)

~~~
yowlingcat
Great article. I liked this quote:

```

The best advice I can offer:

If it’s a core business function — do it yourself, no matter what.

Pick your core business competencies and goals, and do those in house. If
you’re a software company, writing excellent code is how you’re going to
succeed. Go ahead and outsource the company cafeteria and the CD-ROM
duplication. If you’re a pharmaceutical company, write software for drug
research, but don’t write your own accounting package. If you’re a web
accounting service, write your own accounting package, but don’t try to create
your own magazine ads. If you have customers, never outsource customer
service.

```

This all rings true in my experience. You should write the software that's
critical to your core business competency yourself, because the maintenance
cost is worth paying if you can achieve better software. But if it's not a
core competency and your business isn't directly going to benefit from having
best in class vs good enough, then it may be worth outsourcing.

------
nneonneo
I found this to be an incredibly accessible and easy to read guide for
software development. It’s a very short read - just a few minutes - but it’s
full of practical examples and written in a way that speaks to non-engineers
(like bureaucrats). If you are a non-technical person handling software stuff,
this article should definitely be high on the reading list.

The author seems like an unknown in the software development world, but
they’re one of the managers for Singapore’s fairly successful digital
government initiative. So it does feel safe to say they have some experience.

~~~
angelsl
Li Hongyi is the son of Singapore PM Lee Hsien Loong, as well as a deputy
director in GovTech Singapore (the Government Technology Agency). (He's also
an MIT CS grad, and a past Googler.)

I suppose he wrote this for other people in the Singapore civil service.

------
tony
Nice post! Agreed on keeping the initial stuff simple as possible.

In python, I typically follow a pattern of keeping stuff in __name__ ==
'__main__' block and running it directly, then splitting to functions with
basics args/kwargs, and finally classes. I divide into functions based on
testability btw. Which is another win, since functional tests are great to
assert against and cover/fuzz with pytest.mark.parameterize [1]

If the content of this post interested you: _Code Complete: A Practical
Handbook of Software Construction_ by Steve McConnell would make good further
reading.

Aside: If the domain .gov.sg caught your eye:
[https://en.wikipedia.org/wiki/Civil_Service_College_Singapor...](https://en.wikipedia.org/wiki/Civil_Service_College_Singapore)

[1]
[https://docs.pytest.org/en/latest/parametrize.html](https://docs.pytest.org/en/latest/parametrize.html)

~~~
ptx
I prefer putting the main code into a "main" function (called from the
__name__ == '__main__' block) fairly early, since otherwise the functions you
extract might accidentally keep relying on global variables.

~~~
tony
Good point

I like to do it early also, to make sure that the new script, if imported from
by a sibling module, is inert.

An example would be a scripts/ folder and sharing a few functions between
scripts w/o duplicating.

In some cases I don't have a choice. Initialization of a flask app/ORM
stuff/etc has to be done in the correct order.

I think the general rule of thumb I follow is: avoiding keeping code that'd
"run" in the root level. Keep it in blocks (normally to me functions) has the
added effect of labeling what is does.

What I don't do: I don't introduce classes until very late. In hindsight,
every time I tried to introduce a complicated object model, I feel I tended to
overengineer / encounter YAGNI

------
9nGQluzmnq3M
The article appears to be written by Singaporean prime minister Lee Hsien
Loong's son, Li Hongyi.

[http://theindependent.sg/li-hongyi-singapore-has-a-lot-of-
pr...](http://theindependent.sg/li-hongyi-singapore-has-a-lot-of-problems-but-
we-have-political-stability-and-resources/)

~~~
hnick
Now I'm wondering why the children romanized their surname as Li not Lee.

I came across this article: [https://mothership.sg/2015/03/lee-hsien-yang-
reveals-the-sto...](https://mothership.sg/2015/03/lee-hsien-yang-reveals-the-
story-behind-the-names-in-the-lee-family/)

> I have taught my children never to mention or flaunt their relationship to
> their grandfather, that they needed to make their own way in the world only
> on their own merits and industry.

~~~
9nGQluzmnq3M
Singapore's older generations speak/spoke Chinese "dialects" like Hakka (Lee
Kuan Yew's heritage), but there has been a massive government-led push towards
standardizing on Mandarin as the one true Chinese. Hence Lee Hsien Loong's
children all have their names officially romanized in Mandarin pinyin (Li),
not Hakka (Lee). The underlying character, 李, is still the same.

------
steventhedev
Regarding "Seek Out Problems and Iterate", it's a bit of an understatement how
important this is. I've invested a lot of time helping my coworkers understand
the distinction between tasks and problems. The end goal being only tracking
problems in the ticketing system. It's not easy to do this and it takes
constant effort, but it pays off very quickly. I've yet to see a real
"problem" ticket stay unresolved for a long time, whereas "task" tickets tend
to stay around until they're either irrelevant or they get closed after
getting kicked between a few people.

A good example of this is:

\- Add worker thread for X to offload Y

When the actual problem is more along the lines of:

\- Latency spikes on Tuesdays at 3pm in main thread

Which may be caused by a cronjob kicking off and hogging disk IO for a few
minutes.

A good rule of thumb I've found is that task tickets tend to have exactly one
way of solving them, whereas problem tickets can be solved in many ways.

~~~
Dumblydorr
Can you explain the 3pm on Tuesdays issue? My sister works for LLS and she
said their servers get very slow at a precise time every Tuesday. Not saying
it's the same bug, but what was the solution in your specific case?

~~~
codetrotter
The next sentence suggested that the cause of the problem in this probably
hypothetical situation might be “a cronjob kicking off and hogging disk IO for
a few minutes”.

So in that case, I guess either run the job with a lower priority and see if
that helps, or execute the job more often so it doesn’t have to catch-up all
at once one time per week, or rewrite it so that it performs I/O with smaller
chunks of data at a time and sleeps for a little while in-between reading or
writing chunks of data. Basically, do something so that you no longer have
this one huge job consuming all of the IO bandwidth for several minutes every
week.

------
ak39
Building good software requires mainly achieving two things:

1\. Making sure what you build is what was really requested (correct), and

2\. Making sure what you've built doesn't have a higher running "cost" than
the thing it replaced (either manual process or old automated solutions).

Everything else, IME, is ancillary. Performance, choice of platform,
frameworks, methodology to build, maintainability etc are sub-objectives and
should never be prioritized over the first two objectives. I have worked on
many projects where the team focussed mostly on the "how to build" parts and
have inevitably dropped the ball on the "what" to build of the projects.
Result: failure.

Sauce: personal experience with several years of different projects (n = 1;
episodes = 20+ projects that have gone live and have remained live versus 100+
projects lying by the wayside).

Writing software is _not_ easy.

~~~
0x445442
I agree with you but what I've noticed is for all the large projects I've
worked on it was impossible to get an official answer as to whether or not the
whole endeavor had a positive ROI. In fact, with a little back of the napkin
math and some knowledge of the project's resource allocation it was obvious in
most cases there would not ever be a positive ROI.

------
siempreb
> 3\. Hire the best engineers you can.

This is where most companies fail. Yes, they do want the best developers, but
for the budget of an average junior/medior dev.

For some reason most companies/managers I worked for do not understand the
financial impact of a not so good developer. Or the other way around; they
fail to value the best developers and are unable recognize them.

I've worked for plenty companies where they let mediocre dev's build a big app
from scratch (including the architecture), in an Agile self managed team..
These are the codebases that always need to be rewritten entirely because they
have become an unmanageble buggy mess of bad ideas and wrong solutions.

~~~
lelima
>"3\. Hire the best engineers you can."

If every single company wants that, where is he space to grow and learn from
mistakes?

Maybe I'm wrong but I think those "mediocre dev's" learned a lot building a
big app from scratch, solving bugs and refactoring.

~~~
matz1
They can learn them on their own time outside of work.

~~~
whynotminot
This is just an awful, awful mindset.

If you want great devs, you're going to have to invest in junior devs, and
you're going to have to expect them to be learning at work. This is also why
the best use of your senior devs is as mentors to your less experienced ones.

~~~
floriol
I agree that it is an awful mindset, but it's also true that they should not
be given a task that they can barely do. Instead the formerly mentioned great
devs should mentor over them, so they can become similarly good.

------
akersten
One of the principles the article highlights is that additional features make
a software complex and therefore more likely to fail. This is true, but I'd
argue it's not for the reason the article claims.

The claim is:

> Stakeholders who want to increase the priority for a feature have to also
> consider what features they are willing to deprioritise. Teams can start on
> the most critical objectives, working their way down the list as time and
> resources allow.

In other words, the argument is "competing priorities in a large-scale project
make it more likely to fail, _because stakeholders can 't figure out which
ones to do first_." Actually, in this very paragraph, the author glosses over
the real issue: _" Teams can start on the most critical objectives, working
their way down the list"_ \- treating development as an assembly line input-
to-output process.

I argue that it's not time constraints that complex programs bad, but instead
the mere act of thinking that throwing more developers at the work will make
it any better. Treating the application as a "todo list" rather than a
clockwork of engineering makes a huge difference in the quality of the work.
When developers are given a list of customer-facing features to achieve, more
often than not the code winds up a giant ball of if-statements and special
cases.

So yes, I do agree that complex software is worse and more prone to failure
than simple software - but not for the reason that there's "too much to do" or
that prioritizing is hard. Complex software sucks because it's requirement-
driven, instead of crafted by loving hands. No one takes the time to
understand the rest of the team's architecture or frameworks when just
throwing in another special case takes a tenth of the time.

~~~
Mertax
I’ve also seen the failures in requirement driven software. When engineers
receive unfiltered customer requests as requirements or tasks they tend to
focus simply on getting that functionality into the software. Most times not
understanding the job the customer is trying to get done.

There are different personalities of engineers, those who thrive on explicit
requirements and can accomplish difficult engineering tasks when they are
given clear requirements. But those engineers should only be given those
requirements once the job that the customer is trying to get done is clearly
understood. Some engineers have the ability to find creative solutions, that
customers or product managers can’t see, when they are provided with problems
and jobs rather than requirements and tasks.

Managers would be wise to distinguish between the type of engineers they are
managing and play to their strengths. Whatever type you have, understanding
the job the end user is trying to get done must occur, preferably by an
engineer that’s capable of articulating that, if needed, to team members as
technical requirements.

~~~
pure-awesome
Paraphrasing, you said

> There are engineers who can accomplish difficult engineering tasks when they
> are given clear requirements and engineers have the ability to find creative
> solutions when they are provided with problems and jobs rather than
> requirements and tasks.

I feel like I could perform adequately in either environment. The problem is
I've previously found myself in environments where I'm expected to come up
with creative solutions to a problem, but I have no access to the customer or
even a simulated environment where I could try to do something similar to what
a customer would do.

In this kind of case, it's impossible to really know how to articulate your
requirements, because all you can use is a fantasy model of hypotheticals. But
requests for more precise requirements are potentially brushed off as wanting
to be spoon-fed what you need to do and having inability or unwillingness to
think creatively.

------
andy_ppp
I've personally been thinking about this for some time and wondering if in the
real world this looks like building as much as possible at the database level
and treating your DB as a state machine for your app, aiming to disallow whole
classes of errors and communicating the design of the business logic at the
SQL functions/triggers/data layer, separate from the API, Services,
Programming Language, and Frontend layer(s).

This means that instead of lots of issues with business logic being separate
from the data the business logic and data sit together and prevent your system
from getting into bad states.

Thinking about this, maybe I just stole this thought from Derek Sivers:
[https://sivers.org/pg](https://sivers.org/pg)

~~~
dajonker
Yes, the data model is probably the most important aspect of your application,
it defines the relations and constraints. With a good data model, you don't
need to write a lot of code to deal with it. Having lots of code that deals
with weird situations in the database means your data model needs some serious
consideration.

A database in my opinion is not a good place to write business logic with
functions and triggers, since there is lack of tooling that would make
development and debugging easy. Let the database do what it does well, which
is storing and querying data.

------
crimsonalucard
Nice Post. But everyone needs to understand something. Even if you follow
these principles to the letter T, you can still produce very bad software. In
fact you can also find many cases where people did the exact opposite of what
this guy said and still produced great software. I'm sure many people can name
examples of software that just came together out of blind luck.

Why?

Because there is no formal definition for what is bad or good software. Nobody
knows exactly why software gets bad or why software gets good or what it even
exactly is... It's like predicting the weather. The interacting variables form
a movement so complex that it is somewhat impossible to predict with 100%
accuracy.

What you're reading from this guy is the classic anecdotal post of design
opinions that you literally can get from thousands of other websites. I'm
seriously tired of reading this stuff year over year rehashing the same BS
over and over again, yet still seeing most software inevitably become bloated
and harder to work with over time.

What I want to see is a formal theory of software design and by formal I mean
mathematically formal. A axiomatic theory that tells me definitively the
consequences of a certain design. An algorithm that when applied to a formal
model produces a better model.

We have ways to formally prove a program 100% correct negating the need for
unit tests, but do we have a formal theory on how to modularize code and
design things so that they are future proof and remain flexible and
understandable to future programmers? No we don't. Can we develop such a
theory? I think it's possible.

~~~
carapace
So you're not talking about "formal methods"?
[https://en.wikipedia.org/wiki/Formal_methods](https://en.wikipedia.org/wiki/Formal_methods)

The Applied Category Theory folks have some very interesting stuff, like
Categorical Query Language.

[https://www.appliedcategorytheory.org/](https://www.appliedcategorytheory.org/)

[https://www.categoricaldata.net/](https://www.categoricaldata.net/)

But it sounds to me what you mean is more like if "Pattern Language" was
symbolic and rigorous, eh?

~~~
crimsonalucard
Yes, this is exactly what I mean. Though I feel patterns can be formalized
within thr framework of category theory.

~~~
carapace
Have you read "Introduction to Cybernetics" by Ashby?

(PDF available here:
[http://pespmc1.vub.ac.be/ASHBBOOK.html](http://pespmc1.vub.ac.be/ASHBBOOK.html)
)

Cybernetics might be the "missing link" for what you're talking about.

~~~
crimsonalucard
I didn't dive to deep into this so I could be wrong but this looks like
control theory with elements of category theory.

I'm looking more for a theory of modules and relationships. Something that can
formalize the ways we organize code.

~~~
carapace
From my POV control theory is rediscovering cybernetics, but yeah.

It sounds like CT is what you're after (to the extent that we have it at all
yet...)

------
nine_k
All very good points. Don't write code, solve the problem. For that, first
understand the problem. Take time to reduce complexity, else you won't be able
to evolve. Gather knowledge along th he way.

This all takes a bird-eye view and a long perspective, very unlike quarter-
results-driven development.

------
hnick
This is great. So many quotable quotes. If only we could make it required
reading for our clients!

This one struck me, because as soon as I read it I knew it was true yet had
never considered it:

> Most people only give feedback once. If you start by launching to a large
> audience, everyone will give you the same obvious feedback and you’ll have
> nowhere to go from there.

I've been on both sides of that fence and it rings true.

~~~
joes223
Anonymous feedback (like really anonymous) is the answer. people can't give
real feedback and be nice at the same time.

~~~
hnick
I think feedback fatigue is a real thing though. The comment about only
leaving feedback once hit home to me. It's rare I bother reviewing something
twice even if asked, and especially if my original round of feedback didn't
seem to change anything (which I understand is totally reasonable in many
cases, but still a little disappointing).

------
DantesKite
Jesus Christ that’s a well-written article. There’s no fat to it. All signal,
no noise.

------
smacktoward
Write code. Not too much. Mostly test-covered.

~~~
ssijak
I like this Pollan reference

------
lifeisstillgood
>>> The hard limit to system complexity is not the quantity of engineering
effort, but its quality.

This article is full of good ideas, an antidote to creeping corporate take
over of software projects - make this required reading for software projects.

------
axilmar
The initial proposition of the article, that software is bad because it
follows the lifecycle "gather requirements - write software - deliver it" is
simply wrong. There are huge projects in specialized domains that are
delivered on time and on budget and use this approach.

The problem is lack of knowledge. The successful projects mentioned above did
not have a lack of knowledge, and so they were finished successfully.

When there is a lack of knowledge, then it makes sense to use the iterative
approach...as knowledge is slowly gathered, the software gets improved. As
with all things in life!

~~~
fbr
Yes, the lack of knowledge is definitively one of the issue.

But starting a "gather requirements - write software - deliver it" lifecycle
because you are confident that you have all the knowledge is one as well.

------
zero_k
I like the article, it gets to the point. I would, however, change this: " 3\.
Hire the best engineers you can." to: "3\. Hire and work hard to keep the best
managers and engineers you can." As they mention, accumulating knowledge is
important. Keeping that knowledge around is therefore also important (and
sometimes difficult). The best managers will know what technical debt is, how
to handle pressure from higher-ups, and how to keep a team happy, healthy and
productive.

------
lifeisstillgood
Years ago I wrote [http://oss4gov.org/manifesto](http://oss4gov.org/manifesto)
saying that governments needed to not only embrace OSS but that it is the only
moral option to take.

Now we have government digital systems leading the charge across most western
countries, and we have excellent polemics like this. I am just so happy to see
this level of insightful ness at top levels of government.

I am so glad they listened to me :-)

------
ptidhomme
> _Overall, good engineers are so much more effective not because they produce
> a lot more code, but because the decisions they make save you from work you
> did not know could be avoided._

This is spot on, and very much my experience (of the good engineers I've come
across).

Kind of : management had planned extensive and painful testing of a component
that turned out to be discarded entirely (not because of functionality
reduction but because it was actually unecessary).

------
acd
Keep it simple software should be open source. Government software often has
similar demands as other countries. Share and reuse.

Reusing good modules and software will make the software work.

Kiss engineering still works keep it simple stupid. Make it as simple as
possible. Simple software and systems are easy to maintain and understand.

Use modules as these can be swapped out.

Use proven boring technology such as SQL and JSON. Boring tech has been tried
by others and generally works well.

~~~
tester344
>Government software often has similar demands as other countries.

What makes you think so?

------
soup10
>The better your engineers, the bigger your system can get before it collapses
under its own weight. This is why the most successful tech companies insist on
the best talent despite their massive size.

Translation: the successful tech companies have so much poorly documented
legacy enterprise spaghetti code and tooling that they need the best talent
they can get just to make sense of it and maintain it

~~~
abacadaba
Alternate translation: Bad devs are worse than no devs and all your competent
devs will spend most of their time dealing with the former's crappy code until
they quit. (my code is of course perfect and free of all technical debt)

------
koevet
The article lists the characteristics of a good engineer:

    
    
      * has a better grasp of existing software they can reuse
      * (has) a better grasp of engineering tools, automating away most of the routine aspects of their own job
      * design systems that are more robust and easier to understand by others
      * the decisions they make save you from work you did not know could be avoided
    

I obviously concord with the analysis (not sure about the 10X myth). It also
states that:

    
    
      * Google, Facebook, Amazon, Netflix, and Microsoft all run a dizzying number of the largest technology systems in the world, yet, they famously have some of the most selective interview processes
    

This sounds a bit like a paradox to me. Given the current state of "selective
interview processes" (algo riddles, whiteboard coding, etc.), none of the
above traits can be easily evaluated in a candidate during an interview. On
the other hand, these companies _do hire_ stellar engineers: the technological
supremacy of FAANG is irrefutable.

~~~
unicornmama
Former Googler here.

Google views picking new engineers like picking quality construction metals.
In the end, the machine melts you down and hammers you into a pristine cog.

------
Silhouette
Excellent article, well grounded in the reality of software development. New
developers and managers would benefit from understanding the practical points
made here as early as possible.

I do think perhaps there is too much emphasis on reuse and particularly cloud
services. Ironically, this is partly for the reasons given elsewhere in the
article. If you rely on outsourcing important things, you also naturally
outsource the deep understanding of those important things, which can leave
you vulnerable to problems you didn't anticipate. Also, any integration is a
source of technical debt, so dependencies on external resources can be more
fragile than they appear, and if something you rely on changes or even
disappears then that is a new kind of potentially very serious problem that
you didn't have to deal with before. Obviously I'm not advocating building
every last thing in-house in every case, but deciding when to build in-house
and when to bring something in can be more difficult than the article here
might suggest.

------
einpoklum
> Software has characteristics that make it hard to build with traditional
> management techniques

Perhaps some software development techniques would work though...

> The main value in software is not the code produced, but the knowledge
> accumulated by the people who produced it.

Those people go on to work on other things or for other organization. So,
while that statement might have some truth to it, it's still the case that the
code has to be useful, robust, and able to impart knowledge to those who read
it (and the documentation).

> Start as Simple as Possible

That's a solid suggestion to many (most?) software projects; but - if your
goal is to write something comprehensive and flexible, you may need to replace
it with:

"Start by simplifying your implementation objectives as much as possible"

and it's even sometimes the case that you want to sort of do the opposite,
i.e.

"Start as complex as possible, leading you to immediately avoid the complex
specifics in favor of a powerful generalization, which is simpler".

~~~
AnimalMuppet
> > Software has characteristics that make it hard to build with traditional
> management techniques

> Perhaps some software development techniques would work though...

As you go up the management chain, you usually run into some layer where
people are traditional managers, who want to run a software project like a
traditional project. And behold, you're at this problem. Saying "software
development techniques would work" is useless unless you can get those
managers to change. And when you get them to change, the problem moves up one
layer.

------
einhverfr
One additional principle is this:

When faced with a standard solution, use a standard component if you can. If
you can't use a standard component, build a standard component. Keep your
components simple, well-understood, and easy to maintain.

------
pmontra
Hiring the best engineers, technically-wise, is a good thing but it's not
enough. In my experience it's better to hire somebody with a previous
experience in the domain. Somebody that already built something similar or
related. Those engineers will ask the right questions, make the customer think
about the system in the right way, not lose time on worthless details. Even if
the implementation is not shiny it will be working. It beats shiny but
misguided. And if you can find great engineers with great skills, that's even
better.

------
unicornmama
After a brief visit and further readings, I’ve learned to admire Singapore’s
1st world transformation. I’m a absolutely in awe that a government body can
produce such a high quality article.

------
opvasger
> The root cause of bad software has less to do with specific engineering
> choices, and more to do with how development projects are managed.

...While I do agree that "project-management" is important, I think the tools
we are using today are really underpowered to deal with complexity/human-error
- Which is the bigger problem IMO.

------
exabrial
> The main value in software is not the code produced, but the knowledge
> accumulated by the people who produced it

The problem is most CEOs see the binary as the asset, not the knowledge
gained. I've tried to explain this concept to multiple startup CEOs, who hire
outside development firms, for which it rarely works out for them.

------
zeckalpha
> Software has characteristics that make it hard to build with traditional
> management techniques; effective development requires a different, more
> exploratory and iterative approach.

Or the management techniques considered “traditional” are overlooking a
century of iterative development outside of software. See Deming.

------
fooblitzky
The author is very cavalier about open source licenses - they seem to be
implying you can just use open source code whenever you want, even for closed-
source, proprietary applications. Whether or not that is true depends on the
licenses involved.

------
driverdan
#1 web rule: Don't require JS to read an article.

This site is an empty page without JS.

~~~
davidperrenoud
Strangely, all the HTML elements are there but the opacity of <body> stays at
0 without JavaScript.

------
mcgwiz
The lead image features two laptops and a desktop. And three hardcopies of
code. All with a light-on-dark color scheme. I'd wager they had a bit of fun
taking this programmery photo.

------
k__
"Software Is about Developing Knowledge More than Writing Code"

This is also the real problem with vendor lock-in.

You are more often locked in by the knowledge of your employees than by your
tech stack.

------
edpichler
What excellent article. It summarizes things that sometimes need decades to
learn by ourselves. Reading books and good articles like this give us a
shortcut for such wisdom.

------
wwarner
`There is no such thing as platonically good engineering` +1

------
Oras
> 3\. Hire the best engineers you can.

What is the definition of "best engineers"? Those with extensive experience?
those who follow design patterns and coding standards religiously? those who
solve algorithms on a whiteboard? I would like to see if there is a definition
for this.

I would say build the right culture (collaborative, always learning from
mistakes and revise decisions and no blame or pointing fingers).

You can get a bunch of great _coders_ /engineers _who follow code standards,
break down codes to zillions of functions/methods ... etc_ but will fail to
work together and conflicts will raise quickly.

------
mychael
This reads like conventional wisdom. No one is going to argue against "Hire
the Best Engineers You Can" and "Start as Simple as Possible".

~~~
ikll
If only.

Industry this days is more about headcount than quality itself. Why hire two
good engineers when you can have three mediocre ones for the same price?

On simplicity, common wisdom these days dictate that we should use bloated
kitchen-sink backend MVC frameworks that generate dozens of directories after
`init`, because supposedly nobody knows how to use routers. Frontend compiler
pipelines are orders of magnitude more complex than the reactive frameworks
themselves, because IE11. And even deployment now requires a different team or
expensive paid services from the get go. We're definitely not seeking
simplicity.

The second point is also something that most developers and managers would
balk at: "To build good software, you need to first build bad software, then
actively seek out problems to improve on your solution". Very similar to the
Fred Brooks "throw one away" advice that no one ever followed.

------
known
I'd start from here
[http://0.30000000000000004.com/](http://0.30000000000000004.com/)

------
dajonker
This is beautiful, I feel like I should memorize the entire thing.

------
blue_devil
Impressive that this comes from a Civil service college.

------
Aeolun
Now, how do I convince my management this is a problem?

------
dwipurnomo
I think only hire the best is wrong

------
kitsune_
Except for the 10x myth a fairly good article.

~~~
dajonker
I disagree with that, if you describe it as stated in the article: "Overall,
good engineers are so much more effective not because they produce a lot more
code, but because the decisions they make save you from work you did not know
could be avoided."

I've seen plenty of poor decisions that cause 10x the work, and end up with
something 10x less maintainable.

~~~
kitsune_
I'm not disagreeing with the idea that there is variability in developer
productivity. However, quantifying the most productive engineers by throwing
around a specific random factor such as "10x" is rather idiotic.

You have entire blog posts by Steve McConnell of Code Complete fame devoted to
defending the 10x claim by citing 20 to 50 year old research that shows 5x to
20x differences across certain dimensions and then him falling back to the 10x
thing. Not one single sentence where he is being self aware enough to spell
out the most likely reason for "10x" being so prominent: 10 is the base of the
decimal system and as such psychologically attractive to use.

> Both Steve Jobs and Mark Zuckerberg have said that the best engineers are at
> least 10 times more productive than an average engineer.

I know I'm venturing into ad hominem territory with this, but first of all:
Steve Jobs wasn't a programmer. Mark Zuckerberg, well does he even qualify as
a programmer nowadays? How well can he quantify programmer productivity? His
decision to use PHP led Facebook to create HHVM and Hack. Is this the 10x
developer way?

Anyways, the question to me is: Is it possible for average software engineers
to write good software?

~~~
mrfredward
Perhaps "10X engineer" is just an easier thing to say than "5 to 20X engineer
as described by this paper." Perfect numerical accuracy is not needed to make
the point that there is a lot more variance in the productivity of engineers
than there is with most jobs.

If someone suggests you focus on the 20% of customers who make 80% of your
revenue, and you run the numbers and find a 75-25 distribution, should you
call the person making the suggestion an idiot?

------
apo
> Surprisingly, the root cause of bad software has less to do with specific
> engineering choices, and more to do with how development projects are
> managed. The worst software projects often proceed in a very particular way:

> The project owners start out wanting to build a specific solution and never
> explicitly identify the problem they are trying to solve. ...

At this point, it looks like the article will reveal specific techniques for
problem identification. Instead, it wraps this nugget in a lasagna of other
stuff (hiring good developers, software reuse, the value of iteration),
without explicitly keeping the main idea in the spotlight at all times.

Take the first sentences in the section "Reusing Software Lets You Build Good
Things Quickly":

> Software is easy to copy. At a mechanical level, lines of code can literally
> be copied and pasted onto another computer. ...

By the time the author has finished talking about open source and cloud
computing, it's easy to have forgotten the promise the article seemed to make:
teaching you how to identify the problem to be solved.

The section returns to this idea in the last paragraph, but by then it's too
little too late:

> You cannot make technological progress if all your time is spent on
> rebuilding existing technology. Software engineering is about building
> automated systems, and one of the first things that gets automated away is
> routine software engineering work. The point is to understand what the right
> systems to reuse are, how to customise them to fit your unique requirements,
> and fixing novel problems discovered along the way.

I would re-write this section by starting with a sentence that clearly states
the goal - something like:

"Paradoxically, identifying a software problem will require your team to write
software. But the software you write early will be quite different than the
software you put into production. Your first software iteration will be a
guess, more or less, designed to elicit feedback from your target audience and
will deliberately built in great haste. Later iterations will solve the real
problem you uncover and will emphasize quality. Still, you cannot make
technical progress, particularly at the crucial fact-gathering stage, if all
your time is spent on rebuilding existing technology. Fortunately, there are
two powerful sources of prefabricated software you can draw from: open source
and cloud computing."

The remainder of the section would then give specific examples, and skip the
weirdly simpleminded introductory talk.

More problematically, though, the article lacks an overview of the process the
author will be teaching. Its lack makes the remaining discussion even harder
to follow. I'll admit to guessing the author's intent for the section above.

Unfortunately, the entire article is structured so as to prevent the main
message ("find the problem first") from getting through. As a result, the
reader is left without any specific action to take today. S/he might feel good
after having read the article, but won't be able to turn the author's clear
experience with the topic into something that prevents more bad software from
entering the world.

------
johnfisher57
nice one

------
commandlinefan
How many more decades are we going to have to spend learning this lesson
before we learn it?

~~~
diafygi
There's a saying in most other fields of engineering (civil, chemical,
mechanical, etc.): "Regulations are written in blood." A whole lot of bridges
collapsed and a whole lot of people died before strong requirements were put
in place.

It seems we are on the path to repeat history with software engineering, what
with how software and the internet is being developed with such little regard
for public safety and long term consequences.

Unfortunately, it appears that the "free love" phase of software engineering
is coming to an end, as society now relies more and more on software and major
tech players for life and safety. It's starting to get real for software
engineering.

Luckily, other engineering fields have been here before, so this sort of
transition shouldn't be anything new.

Relevant Tom Scott video:
[https://www.youtube.com/watch?v=LZM9YdO_QKk](https://www.youtube.com/watch?v=LZM9YdO_QKk)

~~~
nordsieck
> It seems we are on the path to repeat history with software engineering,
> what with how software and the internet is being developed with such little
> regard for public safety and long term consequences.

> Unfortunately, it appears that the "free love" phase of software engineering
> is coming to an end, as society now relies more and more on software and
> major tech players for life and safety. It's starting to get real for
> software engineering.

Software will always be a spread of reliability requirements, from pacemakers
on one side to excel reports on the other. Part of being a responsible user is
choosing software with the right balance of economics and reliability for the
job.

------
ensiferum
"2\. Seek out problems and iterate;"

This is bad advice. It's like saying "go into a bar and start picking up
fights".

If some part of the software has problems, runs slow or has bugs but _nobody_
is complaining, then there's no problem. Why waste time improving it?

Almost 100% of the time when you solve a problem you just create new problems
of different kind in turn.

Be lazy. The less code you write the better off you are.

~~~
Silhouette
_If some part of the software has problems, runs slow or has bugs but nobody
is complaining, then there 's no problem._

This depends very much on context. To pick an extreme example, if you're
writing the control software for a nuclear weapon and you know you have a bug
that might cause it to activate unintentionally if you eat a banana while it's
raining outside, I think we can reasonably agree that this is still a problem
even if so far you have always chosen an apple for lunch on wet days.

~~~
ensiferum
In your example youd hope some stakeholder to complain and raise an issue.

