Hacker News new | past | comments | ask | show | jobs | submit login
The nihilist and optimist programmers (2015) (bourgon.org)
114 points by ingve on June 3, 2017 | hide | past | favorite | 36 comments

What's being missed here is that it's perfectly possible to be an optimist that delivers, and does so reasonably fast. The problem is that it takes an excruciatingly long time to understand how to do this and most people simply don't have the patience to get there, so they get stuck in one of the two camps - do the right thing slowly, or do the wrong thing fast.

Or perhaps it's a luxury- you have to make the right career moves and only allow yourself to work for organisations and people who actively support you while you develop your skills. You need to convince people to really invest in you, that is. And that's hard to do.

Think though- what's the alternative? If you work for employers who believe that everything you do is always going to be a bit shit, what can you expect from them? You can certainly expect your pay to be a bit shit also, and then your say in anything that matters. Way to go to become a useless, incompetent, irrelevant, cost-center drone, there, buddy!

I'm not saying you should strive to be a rockstar. But you can get better at what you do, and one day, even get to be good at it. Like, really good. People do that in every craft, in every trade, in every art, even. Why is programming any different?

Well, it ain't. The "nihilist" programmer in the article is really a pessimist programmer. The stack is always half full for them (get it?). But if it wasn't for "optimists" we'd never have tail-call optimisation. See? It gets better.

This is so well written, I just wish it expanded a bit more in the end. I'll tell my experience rocking from one side to the other:

When I started as a self-taught programmer I was basically fighting the code all the time and reading about these better practices and all. I followed a top-to-down learning focusing first on the deliverables. As I started learning more and more and constantly struggling with my own code, the ideal implementation (of course involving OOP) seemed further and further far off, always elusive. You could always add an extra layer, an extra abstraction here and there.

At some point I realized I was lost in an abstraction sea and not getting anything done. I abandoned some of the projects at mid-size and made https://picnicss.com/ as an example of the opposite. Oh boy, what a difference. A single stylesheet made in few days with great adoption and feedback from the community. I just saw a video of Google IO 2017 and they used it there in a demo! It also helped that I switched from PHP to Node.js around that time.

So I kind of got hooked to that. I have made quite a few tiny-sized, one-off projects ( https://github.com/franciscop/ ) and learned a lot about this quick-iteration coding. I wouldn't say it's the same as the OP's description of nihilist since that seems to be based on a large codebase. What I made was nihilist in the sense that some projects superseeded the previous ones. Example: first I made https://umbrellajs.com/ , then decided to re-implement it all and created https://superdom.site/ with an alternative syntax.

Now I think I've found a balance in the middle as I'm finishing https://serverjs.io/ ; the library's public API should be fairly stable, but the implementation details can have their shortcomings and be kind of messy at places. To finish off with a great saying for the situation:

Perfect is the enemy of good.

"Perfect is the enemy of good"

Could not agree more. Self taught programmer here too. For such a long time chasing "perfection" had me stuck where I was not finishing any projects.

Taking a step back I decided that finishing projects is what really gives me happiness. They don't have to be perfect or world changing. That coupled with detachment from how the project is received has helped me so much.

Congrats on all your projects. Inspiring!

Same here. Although it was rewarding to write "perfect" code, getting constantly hung up on the tiniest details was quite a soul-drainer.

Nowadays I see more beauty in the end product and refactoring. I still keep that idea of perfection in my mind and do my best to write good code from the start, I just don't let any of it become a blocker.

I'm more efficient, stress-free and productive as a result. And I don't feel as repulsed when working with other people's code.

Good thing you do not work on security or real time critical or life critical applications then.

Seriously, the only kind of perfect code is the one that has been proven correct. Or in fact the proof itself.

Otherwise you're talking about "code we think does the thing and looks nice".

In many, many circumstances, code that "does the thing [well enough]" is more than enough. Not everyone works on avionics or pacemakers.

I enjoyed your comment, and just want to point out that there are two separate issues at play here:

1) The quality of the end product (what the target audience sees and interacts with)

2) The quality of the underlying implementation (the hidden stuff that makes it work)

They are not completely independent (e.g. uncertainty in the product design has strong implications about time spent polishing the code). But the distinction is important, and it can be worthwhile to analyze them separately.

I've cottoned on to the idea of focusing on feedback loops instead of "practices" lately as a way to deal with the kinds of evolutionary changes projects tend to go through.

Practices tend to emerge within a specific project situation as a pragmatic way of addressing concerns. When the practices are communicated across projects a game of telephone is played, the nuances lost, and the meaning is eventually replaced with dogma.

Consider which would be more useful: a workout log that suggests how much additional difficulty you should add each week, or a fixed plan found in a magazine that says that you should be performing an exact workout in each week?

This is the struggle I think programmers really face, because the codebase at any moment in time needs an appropriate "workout plan" to successfully reach the next stage. Sometimes a form of cheat can be used to accelerate it towards a goal, but the concrete progress is reliant on a similar formula to progressive overload cycles.

This focus on feedback also guides healthy cutoffs between prototyping and production solutions: the production solution only makes sense once prototype learning has been done, and the prototype likewise stops making sense when it conflicts with the demands of feedback.

Besides "perfect" and "good" there's also "better" and as long as you can do that, your results are guaranteed to improve.

I would even go as far as to say that, if you do the same thing over and over again, you can only avoid getting better at it if you try, really hard, to be worse at it.

The original English saying was with "better" instead of "perfect". That said, both have the same meaning: you can keep improving it forever, there will always be a "better" way of doing it.

What I think it means is that you have to know your objectives, as everything is a trade-off. Time you spend refactoring is time you don't spend testing or documenting it, for instance. Or it might be better to have two features at 90% "perfection" than one at 99%. Or spend that time with better marketing/landing page/etc.

And then there is being the nihilist because the company and project managers won't allow you to improve or fix anything anyway.

Well I was thinking the nihilist programmer gets fired a lot less often than an optimist programmer does. Mainly because he gets the job done, while the optimist programmer often finds he's bit off more than he can chew and is choking on it... and the company is not happy because they are not getting RESULTS, which is all that they care about.

This may seem logical, but in practise it doesn't work that way. Optimists make for a better mood in the workplace, which interestingly is more important on a day-to-day basis than achieving results (barring any obvious negligence).

The thing is that the nihilist and optimist are not different persons but different mindsets and that in some circumstances, one or the other is right.

Sometimes, management dooms a project and as a programmer there is only so much you can do to make it forward. Interestingly, poor technical quality does not prevent a project from being commercially successful.

Other times, especially at the start of a project, or as a project manager, you have the ability of making it right. Do not pass on it! Have some realistic expectations about how far people will go with recommendations and best practices, but recognize opportunities to improve a design, as they are rare and valuable.

tl;dr: be the nihilist 95% of the time, but do not miss the optimist's opportunity that will happen 5% of the time!

Sometimes I wish I was a nihilist programmer. They seem much happier, and in my experience optimist programmers slowly get all the life sucked out of them when on a team of mostly nihilist programmers (which seems to be most in the industry).

I learned not to be overly optimistic, but that doesn't make me a nihilist. I think most experienced programmers are pragmatists.

> If a thing is undefinable, you will naturally resist efforts to define it. If a thing is forever in flux, you will resist efforts to freeze it. If a thing is composed exclusively of compromise, you will resist efforts to make decisive decisions. And if a thing will never be good, you will resist efforts to make it good.

Isn't that a good way to approach software development? You probably shouldn't make decisive decisions, you probably shouldn't freeze your project, and if you define it you risk missing opportunities outside that definition.

> Isn't that a good way to approach software development?

Not if your software needs to actually meet users' needs--in other words, not if you want to make a living at it. To meet users' needs, your software has to ship, which means you need to make decisive decisions, you need to freeze your product, and you need to define what it does.

What you don't need to do is stop doing those things once you've done them once. You can always update your software, you can always make new decisions, and you can always redefine what your software does, in response to changing user needs or changing understanding on your part of what user needs actually are. But the only way to do that is to do it, which means you have to start somewhere. And never making decisions, never freezing anything, and never defining anything means never starting anywhere.

As I was reading the post, I kept thinking that the nihilist sounds like they're following the recommendations set in "The Pragmatic Programmer."

If you make decisions reversible or abstract away the interface from the implementation, you may be doing it for nihilistic reasons, but still a decent idea.

Also, "good enough" is underrated.

The "nihilist" described here is a person that sees implementation as means towards an end, and in this perspective, functional requirements are at the center. Because of this, for these people software is a black box where the only important things are the touching surfaces.

The "optimist" described here is a person that sees software in a more broader sense: functional AND non-functional requirements. Non-functional requirements include maintainability, scalability, performance, security, configuration, etc. and will strive to implement them.


Now, my opinion:

My name for the "nihilist" programmer are "feature fairies" or "duct tape programmers". The problem with feature fairies are that they create more problems than they solve, and never volunteer to fix them.

Feature fairies like to get credited with completed features, but never with the defects associated with their contributions. Therefore they will usually play dumb when a bug happens, or an incident is declared, and make someone else clean up after them while they implement the next feature.

So after a couple of years, you have someone credited with a lot of features, and a team of people that have been cleaning up after such person. The duct tape fairy is now a 10xer, a rockstar whose time is very valuable therefore needs to be paid more, even promoted, even though this person is responsible for wasting 90% of the engineering payroll in fixing trivially avoidable defects.

The way to prevent that is to leave a trail of evidence that can link commits to bugs. When an incident happens, make sure to identify the commit id causing the problem and put it directly in the ticket. Make it very clear where the defects are coming from and who they're coming from.

Never volunteer to clean up after a feature fairy. By the time you do this, the feature fairy marked their task as complete and from the eyes of management you would be wasting your time working on a completed task. Rather than doing that:

- When the feature fairy wants to take on the next task, ask if they have fixed one of the defects caused by them as per evidenced in the commit id.

- Rather than opening a new ticket, reopen the original ticket. This better reflects the situation: you are completing the work the duct taper failed to complete, you are not adding new work. This also denies the duct taper of their prized fake task completion.

When a feature fairy volunteers to be in a hiring committee, prevent it at all costs. They last thing you need is having to clean up after more people.

Be careful while doing this to not be perceived as negative.

I've been programming professionally for a decade and I've yet to see a "feature fairy" like you describe. I have seen a lot of crab mentality though -- mediocre developers and managers trying to use process to bring everyone back to the mean. Humoring the idea for a moment though: isn't anyone that writes a high volume of code also going to create a (proportional) high volume of bugs as collateral? If someone has written twice as much of a system as others on the team, it wouldnt be weird if they were responsible for twice as many bugs.

Productivity is not writing more code, but rather finishing more work, and while there's an overlap, they're substantially different things.

If you are taking less time than the rest, there are a couple of possibilities:

- You are a legit virtuoso of software. <- this is possible, but less likely.

- You are cutting corners and leaving work for others to do. <- this is much more likely

In the first case there's no problem. In the second case you are not truly finishing your work and the team has a legitimate reason to ask you to finish your leftover work.

If everyone starts contributing code leaving left-overs to inflate their productivity, it quickly becomes a race to the bottom: technical bankruptcy.

If you are not able to explain what your code does word by word that means for a start that you did not read the documentation, you repurposed code you don't really understand. Therefore your time savings are at the expense of compromising the quality.

If you didn't handle errors, if you didn't write tests, if you hardcoded magic numbers and strings, if you didn't test your code, if you didn't stick to the coding standard, if your identifiers don't reflect the code they represent, if you coupled unrelated code and performed actions at a distance... you are also saving time at the expense of the product quality because you cheated to finish earlier. All those problems add up to technical debt.

This discussion sets up my problem with the article. Of the two, the 'optimists' in e article have the darker world view.

I've had a lot of discussions and arguments with the 'pragmatists' you call feature fairies over the years, and the impression I get is that their world view is skewed to protect their own egos. They don't create bugs, some of them will tell you. It's supposed to work that way. They assume ther is a magic later when they will get to fix all the problems they created (but some will complain about "nothing to do" when there's a gap in the schedule). They plan and write features as if their luck will hold.

The optimists in the article on the other hand tend to be closer to realists. They don't traffic in luck. They know that people make mistakes. They see all the time frittered away on tech debt (we call it tech debt because it is accidental complexity that slows us down) and they know if you don't chip away at it constantly you'll drown. Fight the chaos or lose your way.

Process never trumps communication. IME speaking up is a valid approach. If you can't convince management either you are wrong, or the management is (you might not know the whole story, f.e. cash flow issues and knowing you can only close a client if you have feature y). Figure out what the situation is, and either realize you were wrong, try to convince them with better arguments or GTFO.

> The way to prevent that is to leave a trail of evidence that can link commits to bugs.

Or have a code review step in the workflow, so that the buggy commits don't get merged in the first place?

You can, but while you do so be extremely careful to not be perceived as conflictive, negative or nitpicky.

If they are reasonable and take feedback well, you can work with them and iron out any issues effortlessly.

But if they're toxic, don't antagonize them.

An example of in the middle: realize things have flaws, but work to improve them. Realize that perfection cannot be achieved, so work with the stakeholders to come up with something acceptable. Programming here is just one other set of tasks that has to be done. Check out http://meaningness.com for deeper insight on the philosophical side.

That's basically the optimist view in the article, I think. Optimism in this case isn't about pretending the thing is good, it's about believing it can be good.

It's not even that, I think. It's just a... "Trade-offs exist: Deal with it." type thing?

If I can offer an anecdote which is tangential: I like to say that I'm actually an Optimist, but it's just that I've been disappointed so many times that I may sound like a Pessimist.

Honestly, I think it requires a certain amount of optimism/hope for the future to keep working in this industry. The people are usually great, but the systems (both technological and organizational) are mostly just awful. Awful, awful, awful. I take a little solace in the fact that I can (most of the time) fix the technical systems.

I read the optimist view as more idealistic – "not rock forever on a sea of changing assumptions", "the thing out rightly be defined", "shouldn't contain compromise".

Or even simply about believing that it can be better than it is right now. That may eventually lead to it being good but that's not a given.

> The nihilist programmer starts from these axioms and then decides what to do. What to do? The least amount of change possible.

I don't think there's a deductive chain from those axioms to that choice of action. If you're a "nihilist programmer" (not a fan of this usage of nihilist/optimist) in this sense, there's nothing in your ethos that says it can't be better. Sure, it will always be crap, but you can make it better crap. You can do that in small bits or big bits.

The analogy I use for legacy production software is that it's a tire fire, one should endeavor not to make it worse (by unnecessarily adding more tires or fanning the flames), and if possible make it better (spray water on the thing), but it's never going to be an Eden even if you managed to put out the fire since you've still got a stack of tires that could reignite at any moment. If you start out with an Eden in the beginning, maybe you can preserve that, but even if it's ever been done it's not done most of the time.

The best is the enemy of the good, but the good is the enemy of the better. There are few things more irritating to someone with a "nihilistic programmer" mindset as seeing some self-satisfied "optimistic programmer" with their Good crap, that's still crap and could be made better. Not seeing any chance or value of improvement from good is the inverse to seeing no chance or value of improvement from broken, the problem with either view is that doing better isn't tried.

>What to do? The least amount of change possible. Limit exposure, limit effect. Get to the next checkpoint.

If it ain't broke, don't fix it.

I'm either a nihilistic optimist, or an optimistic nihilist depending on what and how much I consumed the day before.

We need both.

TL;DR: nihilist programmers should be fired as soon as possible.

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