
Code Is Never “Perfect”, Code Is Only Ever “Good Enough” - joeyespo
https://www.exceptionnotfound.net/code-is-never-perfect-code-is-only-ever-good-enough/
======
makecheck
One of the depressing things about code is that it is astoundingly easy to
build something that does amazing things in controlled circumstances but is
otherwise practically garbage. Promotions, venture capital, and all other
manner of rewards can result from said garbage. The “real work” is in figuring
out how to move forward from something like that, and lots of stress comes
from trying to do so without breaking anything. There is little reward in
maintenance.

“Good enough” is really the type of attitude that leads to this unfair balance
of effort.

Unfortunately, we live in a world where criticism is levied very heavily on
where you are now, and not on how you got there. What, version 2.0 of the
product sucks now? Screw it, “1 star”, boycott this; fire the team
responsible! Never mind the fact that version 1.0 was a rickety mess, all of
those guys left, and _anyone_ would be _lucky_ to get the thing working _at
all_ , much less in a way that does not introduce any new bugs.

One of the big benefits of open-source is having a chance to understand what’s
going on. Would as many people invest in a product, despite promising behavior
in version 1.0, if they could see a critical review of how that version was
actually implemented? Ideally, we can see not only how a product appears to
work, but how well-engineered it is according to experts.

~~~
cocktailpeanuts
What you say is indeed important, but I wouldn't say the work before that is
not "real work". It's just different types of work. Ask any successful startup
founder what their initial codebase was like and they would say--if they're
honest--it was shitty.

There's a reason for this. The "real work" you mention comes into play only
after the product has reached product market fit and needs scaling. Before
that phase, it's all about struggling to make things work, and people don't
have time to refactor everytime they need to make a small tweak and
experiment. So naturally by the time the "real work" guys come in they will
think "WTF the code is so shitty, whoever wrote this is an idiot". But they
should know that they're there only because of that shitty code. If they were
in that same situation (and rational) they would have done the same thing--
write a consequentially shitty code.

~~~
Retric
Early work is closer to a lottery than anything else. If you only look at
winners you will end up with a distorted view, but right product, right time,
right market is more about luck than skill. MVP is all about validation
because there is no way to judge good vs great before you build it. So, the
only way to improve odds is to just roll more dice.

~~~
im_down_w_otp
You can still write great code (meaning: clean non-leaky abstractions, proper
separation of concerns, functional testing, clearly organized, and unintuitive
bits documented) without having market validation, and I'd suggest that doing
so will actually make it a lot easier for you to shift the pieces of the
project, remove them, rewrite them, extend them, etc. as you start to hone in
on the marketplace fit, and doubly so as you need to start growing your
development team and need to on-board them effectively so everyone can be
productive without just rapidly accruing compound interest on the technical
debt that's already there.

It doesn't take _that_ much longer to write great code when it's just part of
the first-principles of your engineering process. You just do it as you go,
but best-practices need to be scaffolded and modelled for everyone beforehand
to give them a solid starting point for what "minimally viable" actually looks
like. A single well-placed sentence that describes something necessary, but
non-idiomatic or non-obvious, that takes 10sec to write can save you hours or
days of tracing and debugging at that crucial moment right before you're
onboarding a pilot customer or pitching investors.

Very often the bar of "minimally" is set way, way too low and the trope of
that just being "startup life" is usually just laying problems at the feet of
engineering that don't belong there by justifying, sometimes horrifying,
technical debt which are really process and management failures, and later
eventually scapegoating engineering for it.

~~~
cocktailpeanuts
I agree with you in theory, but from experience it is extremely hard to
achieve when you're actually in that position.

Unlike what you say, it _does_ take much longer to write great code when
you're trying new things every day. Every time you try something new, by
definition you're building something that you hadn't planned when you first
started. Which means if you really wanted to be perfect you would end up
refactoring every day. This is not a small effort in total.

You could say you should have prepared for that scenario from the beginning,
but I don't think it's a good idea to believe that you can predict the future
especially when you're building something that hasn't existed before.

~~~
im_down_w_otp
In my experience, when you're in the "invention phase" is when it's most
critical and beneficial to have and demand more discipline around your output
artifacts. Precisely because keeping context and content around your fast
iterative decision-making and implementation phases is critical to avoid
wasting time on duplicated effort or needlessly repeating mistakes over and
over again.

Literally every situation I've ever seen in 20 years across all manner of
marketplaces and every imaginable stage of development has had the immediate
faux-gains made from ignoring spending 10%-20% more time now (to produce
something at least coherent, commented, and composable) ultimately overwhelmed
by the soon-to-be-immediate costs of having to live with the consequences of
the dubious "shortcuts" taken.

I agree with you that it's extremely hard to achieve maintaining that kind of
discipline when under the gun, but that's a people management and expectations
problem, not an engineering effort problem. I'm 100% certain that in any given
window of time, no matter how crunchy that crunchtime is, that if my team
spends 10-15 out of every 100 man-hours producing a higher-quality "minimally
acceptable" artifact that they'll both materially accomplish more in that
first 100 hours than if they'd spent all of it hacking together a barely
working dumpster-fire in the same window of time, _and_ that it will pay
glaringly obvious dividends for their productivity in the next 100 hours
after, and the next after that, and so on.

Lacking that discipline is neither a necessary condition nor a near or long-
term benefit to a prototyping or product development cycle. It's purely a
function of leadership, expectations management, and experience.

 _(I 'm even giving the benefit of the doubt that what's being done "hasn't
existed before", which is overwhelmingly not the case. More typically it's
different people and different teams just painfully learning the same hard
lessons in parallel, often because there's an assumption/delusion what's being
done is a legitimate pioneering effort instead of the probable reality that
it's really a minor variation on something else that already has well-
established successful models available to learn from and mimic.)_

~~~
sangnoir
> I'm 100% certain that in any given window of time, no matter how crunchy
> that crunchtime is, that if my team spends 10-15 out of every 100 man-hours
> producing a higher-quality "minimally acceptable" artifact that they'll both
> materially accomplish more in that first 100 hours than if they'd spent all
> of it hacking together a barely working dumpster-fire in the same window of
> time, and that it will pay glaringly obvious dividends for their
> productivity in the next 100 hours after, and the next after that, and so on

The problems is at the very beginning, all (or most) of that code will be
thrown away because you really don't know what works. How many cycles of
wasted extra 20% effort would it take for you to change your mind?

~~~
im_down_w_otp
You missed the point. In that same 100 hours, spending 15-20 hours applying
best-practices has universally resulted in actually getting _more_ out of that
100 block. The 100 hours spent on the spaghetti mess has always produced less,
provided fewer insights, and often exactly nothing that can be soundly
iterated on.

This is because the friction and pain of technical debt doesn't wait until the
end of the 100 hours to create problems. It's biting you every second of every
minute of every hour and dragging down your productivity and velocity as
you're just plowing forward soaking the noodles.

~~~
cocktailpeanuts
It really depends on what one's standard of "shitty code" is, but in my case
my shitty code does perfectly fine until it reaches significant scale (as in
millions of users). My thought process is: when I reach millions of users i
better hire someone to help me with coding anyway and it's not too late to
take care of it then.

On the other hand, I have also made mistakes of over-engineering to make the
code maintainable. What happens then is I can't really detach myself from the
original idea no matter how much evidence there is to show me that it's not
working, since I've invested so much in the technology. In that case the time
I spent to make the code maintainable becomes a mental liability rather than
an asset.

I don't doubt you are a great developer and have great experience, and I don't
doubt that spending 15-20 hours out of 100 hours when you've reached product
market fit is something you should do, but I can say from my own experience
and experiences from other successful/failed entrepreneurs I've met that it's
absolutely a bad idea to do so when you're just 1-3 guys bootstrapping. In the
beginning the only thing that matters is getting people to actually use your
product, so you should spend 100% of your resources on getting there, not on
optimizing maintainability at all.

If you have actually been in that situation (a founder who's built his own
product from scratch by bootstrapping) and still think it's best to spend
15-20 hours out of 100 hours working on maintainability, please let me know. I
personally don't know any founder who thinks that way.

~~~
im_down_w_otp
I'm also not sure why we're narrowing down that 15-20 hours focused entirely
on maintainability.

It can also be 15-20 hours making sure you're following language/tool idioms
and conventions so that you can iterate quickly instead of fighting against
yourself and your tools being used incorrectly.

It can be about making sure you aren't making leaky abstractions so that when
you suddenly realize you need to make big or small changes to address market
needs you're able to do it quickly and efficiently rather than having to
rewrite a big brittle pile of al dente noodles with every shift and change
you're presented with.

It can be about making sure that the little idiosyncratic things you had to do
have some explanation around them so when your fellow boot-strapper has to
come in and make a change or understand something you worked on, but you're
home sick as a dog because your kid sneezed straight down your throat, your
fellow boot-strapper can understand what you did, why you did it, and can
carry forward with that change without depending on your availability holding
everything up, and because you didn't make a bunch of leaky abstractions on
top of it all they can make that change without breaking 99% of the rest of
the prototype/product.

It can be about making sure a sufficient amount of what you're doing is done
so with composability in mind, so that when you figure out that thing you did
that you ended up throwing away, but now turns out would be supremely useful
to meet current demands, both still exists someplace and can actually be used
without having to spend 10x as long rewriting it.

Having great scaffolding, best-practices models, and good process makes
everything go faster... not slower. Learning how to properly use your VCS is
an enabler, not a drain, but it takes time away from just hacking away on
something. Setting up a CI pipeline is an enabler, not a drain, but it takes
time away from just hacking away on something. Building scaffolding tools that
can just generate for you the first 20% of a project template are an enabler,
not a drain, but it takes time away from just hacking away on something.
Learning your tracing and debugging tools is a _massive_ enabler when trying
to understand and prototype something, but it takes time away from just
hacking away on something.

I should add the caveat that all those things are enablers... only if you do
them well... otherwise they're a giant drag because they're hurting you, not
helping you, and they become a part of your technical debt.

Do you spend literally no time on any of that because it takes time away from
hacking? Do you think having none of those enablers in-place is helping you
all work faster?

------
rrradical
I see things a bit differently. Some domains are well understood and it's
relatively easy to write perfect code (e.g. mathematical functions, list
manipulating functions, etc.), while in others it may be much harder (the file
uploading example he mentions). To me a good aim of writing code is to move
bits and pieces from the latter camp to the former, so that more and more of
your codebase is well understood (and perfect!). That usually involves finding
the mathematical meaning of the abstractions you're using. (Shameless plug- I
wrote a little blog post on the subject:
[http://asivitz.com/posts/programming_in_haskell](http://asivitz.com/posts/programming_in_haskell))

~~~
joe_the_user
Actually, I'd say writing perfect code in the mathematical domain is extremely
hard - floating point types are a minefield and infinite-precision arithmetic
is a minefield also if you consider the possibilities for running-times
exploding. For example, code for the mean of a list of numbers is a hard
problem when looked at in its full generality [1] - and that's using forgiving
definition of "perfect" \- alway correct and terminating, running at a
reasonable speed.

[1] [http://hypothesis.works/articles/calculating-the-
mean/](http://hypothesis.works/articles/calculating-the-mean/)

~~~
skybrian
Great link! But also, the mean is itself an imperfect summary of some
distributions. Any single-number summary will be misleading in some cases.

~~~
bradleyjg
Anscombe's quartet is a great illustration of that.

[https://en.wikipedia.org/wiki/Anscombe%27s_quartet](https://en.wikipedia.org/wiki/Anscombe%27s_quartet)

~~~
fbonetti
That's really cool! Btw, I'd love to drop that line into casual conversation
some time. "Anscombe's quartet" has a nice flow to it.

------
phaedryx
I had a manager that never used "finished" or "done". He always said "where it
needs to be right now".

------
beat
I have the start of a lightning talk on something similar, called "Why
Software Sucks". The idea is that we only make software good enough to get by
- we will always choose features over robustness if we possibly can. Every
project ends when it either fails, or hits feature-complete. No one sits
around polishing the pile of bugs and bad decisions that is a feature-complete
app unless they have to - much more fun to start something new!

~~~
jacobtr
It seems like most consumer apps incur a crazy amount of technical debt while
largely paying people in equity, then if they take off raise a bunch of money
to pay other people in cash to sort it all out... Pretty good system actually.

~~~
beat
Enterprise apps are no different. Lean startup is doing better in the
enterprise than it is in the "startup" world.

Early on, every app is laden with technical debt. They barely work. When
"barely works" becomes "doesn't work", we fix them just enough so they barely
work again, and start piling on more features and functionality. We may build
some scaffolding and do some refactoring to prevent dropping into
doesn't-work-land, but that's not the same as robust! So software - all
software - hovers around that barely-works/doesn't-work borderline.

~~~
lotyrin
Management doesn't invest in things they don't understand. They rarely
understand tech (even if they are technical people, tech is misunderstood).

If you care about the outcome of a craft, you'll get craftsmen, and they'll
produce things and you'll pick the best ones.

Imagine if a chef had to serve the first try at a new dish, if a photographer
had to use his first shot, if a director had to use the first take, if a
visual designer had to use the first concept. These processes are easier for
people to understand because a layman can tell if two flavors didn't combine
well, if a model blinked, or if something looks off. People (even technical
ones) can't experience technical problems immediately or directly in the same
way. Other fields solve for this with engineering, but ours rarely is allowed.

We often ship the first architecture that gets brainstormed, and the first
implementation that works. It's never "We implemented the MVP using
patterns/frameworks A, B, C, D, here's a table of the strengths and weaknesses
as we see them, statistical summary of the time to complete each feature, and
of defect rates. This next slide is a plot of the relationship between request
latency, capacity, and estimated infrastructure cost of each implementation".
It's rare to even have refactors scheduled. Just cleaning up your shit is
"wasting time", never mind how long it takes to ship new features given how
cluttered things are.

Sure, engineering is costly, so is not engineering - you just aren't
projecting or measuring the latter costs. It's all trade-offs, if you aren't
considering expected values of different options, with numbers, then you
haven't optimized, you just rolled some dice. Sure, of course it's always
worked, everything always have worked for the survivors. There's a big
difference between what's unforeseeable and what has merely been left
unforeseen.

~~~
beat
If my house is on fire, I don't want the fire department to wait for the
better firetruck for the job to show up.

Time to market and allocation of resources are serious issues for management.
They may not understand the tech, but I've found engineers rarely understand
the business context, either. "Good enough" is _good enough_. And we've seen
process get more and more focused on this since the late '90s... Agile, Lean,
etc. Get a product out the door, even if it's buggy and flawed. Get feedback
from actual customers. Find out what's really a problem and what we only think
will be a problem.

~~~
lotyrin
Right, there's a whole spectrum between "a prototype worked once on Bob's
laptop, how do we get that live" and "We invented 12 new declarative DSLs that
encompass our problem domain, and formally proved their implementations
correct."

Engineering isn't the latter end of that, it's precisely just the process of
figuring out the trade-offs, the diligence of figuring out where on that
spectrum (highly-dimensional continuum really) of process your project should
be to get the greatest chances of success. Of course it includes time to
market and concepts of "good enough". But it's math and planning and risk
accounting and not the cargo culting, handwaving, business platitudes,
salesmanship and politics of authority that get utilized in the majority of
cases I've seen for making those decisions. These result in monuments to
compromise -- the output of arguments between "captain cowboy" and "doctor
diligent" (neither of which correctly account for real-world incidence of risk
or what that costs the organization which employs them), arguments of
engineering without any engineering being done.

Engineering isn't disconnected navel-gazing perfectionism, it's how you
prevent it. Engineering is both why we don't live in Kowloon Walled cities,
and why most places have water and plumbing and transportation despite a wide
variety of obstacles and economic realities that would preclude "ideal"
solutions.

------
cisstrd
It might not be _" perfect code"_, but I find it fascinating what certain
institutions do to create _bug-free and easily testable code_ , institutions
which are involved in work where small errors can quite literally ruin
billions of dollars of investment.

For example Coding Standards from NASA's Jet Propulsion Laboratory (JPL) for
C[1] and Java[2]

This will also give you an idea of just how tedious it is to do so

I am not even sure if enforcing those strict standards leaves a Turing-
complete language

[1] [http://lars-lab.jpl.nasa.gov/JPL_Coding_Standard_C.pdf](http://lars-
lab.jpl.nasa.gov/JPL_Coding_Standard_C.pdf)

[2] [http://lars-lab.jpl.nasa.gov/JPL_Coding_Standard_Java.pdf](http://lars-
lab.jpl.nasa.gov/JPL_Coding_Standard_Java.pdf)

~~~
meta_AU
That's a good point. Safety critical systems commonly require loops to have
maximum iteration counters and also forbid recursion.

So what's left probably isn't Turing complete.

~~~
mikro2nd
From [2] above:

> important general differences from the JPL institutional C coding standard
> for flight software references (JPL-C-STD) are: (1) the Java standard allows
> dynamic memory allocation (object creation) after initialization, (2) the
> Java standard allows recursion, and (3) does not require loop bounds to be
> statically verifiable. Apart from these differences most other differences
> are due to the different nature of the two languages.

That said, the standard in question is explicitly only intended for ground-
based systems.

------
ambrop7
Perfect is subjective, but "correct" not so much. And when you get
sufficiently skilled, you realize correctness can, for sufficiently complex
software, only come together with the more subjective qualities, since it's
hard to make "ugly" code correct.

"Piece of [bleep]! I know you [bleeping] work! WHY WON'T YOU [BLEEPING] WORK,
MOTHER[BLEEPER]?!"

With that kind of attitude (trial-and-error?) you will never be able to
consistently produce correct code, let alone perfect whatever that is. Though
I think it's not typically the attitude that is the problem, but rather the
underlying lack of skill/intelligence which makes people resort to such
approaches.

~~~
RealityVoid
> With that kind of attitude (trial-and-error?) you will never be able to
> consistently produce correct code, let alone perfect whatever that is.

Sometimes software development process can be very frustrating and I fully
understand the feeling when you're overwhelmed and confused and feel
frustrated because you don't know how to approach the problem. Working with
black boxes usually causes the feeling in me, or having an elusive bug that
could come from literally anywhere from a huge system and having to debug it
with seemingly random reproduction steps, that always gets me.

------
010a
Code quality can only ever be as good as your understanding of the problem
domain. A more accurate statement would be "Problem domains are rarely
perfectly understood."

~~~
chadgeidel
IMHO This should be more highly rated. It seems that we write code to
understand the problem domain, and only by writing code do we truly understand
the problem. This is - again IMHO - why iterative techniques work so much
better than waterfall-style techniques.

------
cmillard
It's scary sometimes that previous consultants (I'm a consulting developer)
may have gotten an application "working", but have incurred so much technical
debt it is nearly impossible to make changes. They've escaped and taken the
biggest chunk of money leaving something built on a foundation of toothpicks.
Thus the project becomes a ticking time bomb and requires full-time programmer
maintenance. You wonder if the next feature request will become the impetus
for the collapse- Then you turn into Robert Gates: "I don't know where. I
don't know when. But something bad is going to happen!!!"

------
euske
I'll copy a Bruce Schneier's quote and say "Software is a process, not a
product."

It's no surprise that there's no such thing as perfect code because code is
mere reflection of a real-life requirement, which is always somewhat
inconsistent and ever changing. Sticking to one static point is, well,
pointless.

------
simonpure
I think today it's more useful to think of most software as a living organism
interacting with it's environment - it's constantly evolving and adapting to
external changes (user needs, dependencies, 3rd party services etc.).

------
dahart
I still haven't learned this lesson well enough. Code I think is near perfect
always turns imperfect over time. The main corollary for me is that I can
spend every waking second of my life making my code better, and I'll never be
happy. I want to better figure out how to enjoy 'good enough'.

~~~
mikekchar
Instead, I might suggest that you enjoy making your code better and to be
happy with the process rather than the result. Then every crappy piece of code
is an opportunity rather than a curse.

Improving code beyond the point where it gives material benefit is not really
a problem except for the fact that it deprives you of the opportunity to work
on crappier code. Especially when working with new code, I find it useful to
concentrate on process rather than end product. If you write tests like X and
refactor like Y, how does it affect the result?

In some ways this is really freeing because you get over the fear of writing
crappy code. If it's crappy, you just get to improve it. It also allows you to
explore ideas and ways of doing things without worrying so much about the
result. Concentrating on producing good code can often (in my experience) lead
to achieving a local maxima but not does not allow you to kick out of it to
achieve something better.

~~~
dahart
I was getting closer to that for many years -- enjoying the process -- until I
decided to try and start a software business. All of a sudden, there's a huge
downside to improving code without having a clear material benefit.

I'm with you on losing the fear of writing crappy code being freeing. At some
point I realized that everyone's code including mine is crappy code, and
there's no way around writing crappy code or introducing bugs. Realizing that
did make me a better coder and a better manager. It let me be a bit more
humble as well as empathetic to others, and led me to think more about the
importance of testing.

------
unimpressive
I wonder if this attitude will change once things like coq become more
accessible.

~~~
patrickmn
I don't know if we will ever have tools that are that safe and _as easy to
use_ as the alternatives.

~~~
SilasX
It depends. People were reluctant to give up a lot of bad coding practices
(goto, variable scoping, writing in efficient assembly rather than a high-
level language, mutable global state) until the better way had better tools or
was taught better.

Edit: Maybe one day people will look back and say, "you shipped code _without_
formal correctness proofs? Were you all high?"

~~~
ddaygold
There is code that pushes the boundaries of the human mind, complex systems
that cannot have any additional complexity if they are to succeed.

And there's other code that pushes against physical or economic limits:
processor speed, memory available, network latency. In those systems, writing
in an inefficient, high level language is just as wrong as writing the first
type of code in a low level one.

Fast, complex, difficult to fully verify code is not bad coding practice any
more than a rocket is a worse vehicle than a Volvo because it explodes more.
Volvos can't go to space.

~~~
SilasX
But one day our skill in "controlling explosions" (bad logic) may be as good
as our skill at doing so in a Volvo, where we can get the power, with the
efficiency and predictability.

------
BerislavLopac
The obligatory link to "Everything is Broken":
[https://medium.com/message/everything-is-
broken-81e5f33a24e1](https://medium.com/message/everything-is-
broken-81e5f33a24e1)

------
geebee
This reminds me or a reaction I had to a very old internet war about PHP and
Rails

[https://sivers.org/rails2php](https://sivers.org/rails2php)

"...The entire music distribution world had changed, and we were still working
on the same goddamn rewrite. I said fuckit, and we abandoned the Rails
rewrite."

It made a bunch of people mad, because (I think) they were reading "Rails
couldn't X, and Rails couldn't Y, and Rails couldn't Z, but PHP could totally
Y Z and Y, so I used PHP and it was a big success".

But having been in this situation, I think what he was saying was "I couldn't
X, and I couldn't Y, and I couldn't Z, so I said fuckit and did it the way I
know how..."

It has nothing to do with rails or PHP, or node, django, react. Programmers
who have never finally said "fuckit" and abandoned "the true and right way"
are programmers who haven't released.

Not saying you should stick with ancient technology, but "good enough" is an
inevitable ingredient in any software that ends up being useful to someone.

------
jfaucett
I think this is rambling about things that are largely unimportant (spaces or
tabs). At least that's what his "Perfect Code" definition seems to be to me.

The important part is the flipside, not the presentation: Given a problem
domain and a context there is an optimal or "best" solution or there is not,
and we can get at the answer for most cases.

So code can be perfect if we understand perfect to mean optimal. If we
understand it to mean spaces/tabs probably not, though given an input and
desired output we can even prove some of these as well (for instance,
underscored function names are more quickly processed than CamelCase :
[http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.158....](http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.158.9499)).

~~~
Others
I didn't read the whole paper you linked, but doesn't this sentence in the
abstract contradict your last sentence?

>Results indicate that camel casing leads to higher accuracy among all
subjects regardless of training, and those trained in camel casing are able to
recognize identifiers in the camel case style faster than identifiers in the
underscore style.

~~~
jfaucett
yes it appears that way without reading the paper. Basically the main factor
to me is speed which has a huge differential for untrained subjects "The model
finds that identifiers written in the camel case style took 0.42 seconds more
time." Doing the math you see how much wasted time that is. So I should have
been more specific in the parameters. Your quote is perfectly valid as well.

------
steego
It's important to know what kind of code you're working on before you start
setting low standards.

Some code is perfect, but it's only perfect because it was define with extreme
mathematical precision (Ex: Haskell Prelude code). The value of this type of
code is in direct proportioned to how often it's reused. Often the specs are
based on timeless and well defined ideas, and the implementation crystallizes.

On the other end of the spectrum is loosely defined ad hoc code. The
specification behaves more like a living thing and the code often tries to
adapt to the moving specification over time. This type of code tends to bring
a lot of value to the business and often relies on the foundations laid by
perfectionist code.

~~~
aurelianito
I wouldn't call Haskell's prelude 'perfect'. For a few examples of imperfect
things see [https://downloads.haskell.org/~ghc/master/users-
guide/bugs.h...](https://downloads.haskell.org/~ghc/master/users-
guide/bugs.html) (Find 'prelude' in this page, has several appearances).

~~~
steego
I didn't mean to imply all the prelude code was perfect. What I meant to imply
was some parts are insofar as the specification is complete and specific
enough that it yields one solution. An extreme example would be the id
function.

------
dman
I hope this attitude is used sparingly and in cases where either the problem
is supremely hard or where time is exceedingly short.

~~~
dwaltrip
You are missing the point. "Good enough" depends entirely on the context. In
some contexts, the bar for "good enough" will necessarily be quite high, while
in other context it won't matter as much. There is no perfect code -- because
no two humans could agree on such a definition.

Sure, people may disagree on what is good enough. But hopefully that
disagreement will be easier to resolve than one about what the perfect
solution might be.

~~~
dman
My only concern is that this line of thought can be used as an excuse to stop
trying. As long as we agree that one should strive for perfection given the
constraints at hand (money / time / problem difficulty / experience level etc)
I dont have any objection about the idea.

On a related note, I feel another analogous statement that I now see used
dangerously is "Premature optimization is the root of all evil". Yes
optimizing prematurely can be paralyzing but the other extreme where one
refuses to do back of the envelope calculations and wilfully writes code that
will be slow is damaging as well.

~~~
dwaltrip
I can appreciate that. I have some perfectionist tendencies myself. I think it
is a tricky balance that must we must walk. I like your idea of "as perfect as
our constraints allow".

Another important consideration is the level at which the quality exceeds the
needs of current and future users of the software. Past this point (which
might be impossible to determine or fully agree upon), one must acknowledge
they continue to iterate and polish for purely personal reasons. This can be
fine in certain situations, but it may be a detriment in professional
endeavors.

And of course, like always, one must consider opportunity costs.

------
softawre
Tooling is getting better. Ever looked at what Amazon does with formal methods
to "prove correctness" for some of their systems?

Of course you can argue that "good enough" for them is "damn near perfect".

[http://cacm.acm.org/magazines/2015/4/184701-how-amazon-
web-s...](http://cacm.acm.org/magazines/2015/4/184701-how-amazon-web-services-
uses-formal-methods/abstract)

~~~
kkarakk
got a link to a non-paywalled source?

------
hypertexthero
I [attended][1] a great lecture by [Alex Martelli][2] back in EuroPython 2013
titled "'Good Enough' is Good Enough!"

From the [summary][3]:

> Our culture’s default assumption is that everybody should always be striving
> for perfection – settling for anything less is seen as a regrettable
> compromise. This is wrong in most software development situations: focus
> instead on keeping the software simple, just “good enough”, launch it early,
> and iteratively improve, enhance, and re-factor it. This is how software
> success is achieved!

[1]:
[http://simongriffee.com/notebook/europython-2013-notes#goode...](http://simongriffee.com/notebook/europython-2013-notes#goodenough)
"My notes. Biggest takeaway was to use 'perfect' as a verb rather than
adjective."

[2]: [http://www.aleax.it/](http://www.aleax.it/) "Alex's homepage."

[3]: [https://ep2013.europython.eu/conference/talks/good-enough-
is...](https://ep2013.europython.eu/conference/talks/good-enough-is-good-
enough) "The lecture video is also on the page."

------
coldnebo
I think that might be paraphrasing implications of Gödel's Incompleteness
Theorem.

Non-trivial codes can either be consistent or complete, but not both (within a
system of abstraction).

This explains Joel's "Leaky Abstractions" essay as well as the conjecture that
code cannot be perfect.

However, "good enough" thinking is often just sloppy thinking. Even if
mathematics has boundaries, it doesn't mean you just shrug and say "a nod is
as good as a wink".

Craftsmanship and quality are perceived in terms of utility over time. "Good
enough" often doesn't meet that bar.

Engineers overbuild to support capacity and plan for the worst. "Good enough"
tends to under-build at or below capacity and hope for the best.

"Good enough" is a just reaction to over-engineering (the adding of
unnecessary fixtures and 'perfection'), so the warning has value and there are
some engineers who use it in this way.

But others often mistake over-building for over-engineering and cripple their
organizations and products by seeking "good enough".

------
WalterBright
Haha, there's some code of mine I've been regularly improving for 30 years
now. Even versions I thought had attained perfection I rewrote later when I
realized it was a POS.

The only software that is ever "done" is code that has been abandoned and is
no longer in use.

------
evoltix
I try to follow this mantra from Kent Beck: "Make it work. Make it right. Make
it fast."

I find that most of the development environments that I have worked in, the
focus usually ends up being on getting new features completed in order to help
facilitate the sales department to make sales. It's a never-ending cycle that
will gradually accumulate technical debt such that pushing new features out
the door will eventually come to a halt.

Yes, I agree that code can never truly be perfect. However, as developers we
should always strive to make our code better.

------
kluck
We should more than ever strive for perfect code. Perfect as defined by all
stakeholders in a software. There is really no point in striving for anything
less. Sure you maybe forced to stop at one point (time and money beeing the
limiting factors) but if you can, you should always continue making software
better!

"Good enough" is not good enough as a target. It's uninspiring and
unsatisfying.

------
jfe
I think the definition of perfect code depends on whether the computer is the
end or the means. If it's the end, then there may never be perfection.

------
okonomiyaki3000
Code is never "good enough", code is only ever "less in need of fixing than
other code."

------
njharman
Correction, code is at most "good enough".

I've seen (and written) plenty of code that was less than good enough.

------
karma_vaccum123
...and, problems change even if the solution doesn't. At this point I only aim
to build things that will durable and sensible for about four years. After
that, some other change seems to come along that invalidates the original
code, no matter how pretty it was.

------
andy_ppp
I'd love to see what YCs guidance on code quality is. My guess is "ship it if
you get users".

~~~
ben_jones
"If the building isn't on fire you're not iterating fast enough"

------
drwl
reminds me of [http://algeri-wong.com/yishan/only-god-writes-perfect-
code.h...](http://algeri-wong.com/yishan/only-god-writes-perfect-code.html)

~~~
BerislavLopac
Right on point. Furthermore, it just lead me to realisation that achieving
software perfection is like reaching the speed of light: the closer you get to
it, the heavier you are, and more effort is needed to go further.

------
ZiggyCrane
... like you could create anything and call it perfect. There is no perfect.

------
asciihacker
Does the work of Charles Simonyi and intentional programming change this?

------
dguido
Unless it is formally verified, then it is really perfect. Not sure why we
shouldn't strive towards that final state of evolution. Conceding the game at
"good enough" is a cop out.

~~~
sgift
Formal verification depends on frozen requirements. These are quite rare in
practice.

------
vermooten
And most of the time not even good enough.

------
jdironman
Insanity is doing the same thing over and over again and expecting a different
result.

------
centrinoblue
ha the Dick and Bob bit is pretty darn funny

