Two types of software engineers
registerspill.thorstenball.com
registerspill.thorstenball.com
In my experience there are far, far more Type 3s: Software engineers that completely ignore the system that the software is a part of, and myopically assume that the only solution to any problem is more software.
My take is software is a new form of literacy- not some neat technology like lasers or combustion engines. It's about human knowledge and human co-orindation - and we will all have to code just as we all have to be literate.
As such how many human systems today have not been fitted and overtaken completely by the written word? Some maybe but precious few
-some guy who was wrong about cars in 1980 probably-
There's a lot of language in formal math and science that isn't talked about in a way that assumes everyone will learn it. If you don't know how to code you aren't illiterate.
The issue I find is that the last decade of free VC money and "growth & engagement" means that there were a lot of companies that were given free money regardless of their profitability or even basic sanity-check of the proposed business models, instead rewarding them based on hype or some unspecified potential to turn some vague idea of "growth" into profit (hint: if your "growth" is based on giving away free stuff, those users will leave as soon as you attempt to monetize them), or "engagement" (engagement is a very uncertain thing to monetize in a world already saturated with advertising).
As a result this has funded entire careers based on what is effectively mental masturbation as opposed to actual tangible improvements in the software's ability to drive actual business value (in many cases it is negative value if you account for the salaries spent on it), only made possible because the free money sidestepped normal market dynamics that would usually encourage businesses to reduce overheads and focus their efforts on profit-generating operations (or go out of business).
My personal experience with technology is that the collective effort spent over the last decade over things that are considered "modern" didn't actually improve the customer experience in the vast majority of cases. Ordering food for example is still ultimately browsing a list of items and submitting a form of what you want, yet nowadays despite orders of magnitude greater bandwidth and processing power, I had to sit through seconds of stuttering while megabytes of JS load, execute and make dozens of subsequent requests to get data that the backend could've embedded in the initial server-side-rendered HTML. Same with Microsoft boasting about how their new Teams taking only 9s to load while Skype from 2009 delivering the same functionality faster on much more constrained hardware.
Latest instance: ChatGPT and the hype around it.
In one sense they are myopic. In another sense they are thinking further than anyone else.
Now, if you think machines are better off than the human race at a next evolutionary stage then... that's a totally different story. That might actually be true, and we might be the wrong species to continue on. In that case, software would be a solution.
But you cannot convince me that software for the sake of software is a solution to human problems.
No it will not solve all problems and AI will certainly solve many problems that were previously unsolvable.
At most people working on LLMs are gambling on the idea that AI can solve every problem solvable by something as intelligent as a human.
The economic side effect is a different story to the problem at hand.
I think the only way you can avoid that is by almost annoyingly probing to find the root of problem (because it is often some broken or stupid human process). Most of the time, it does not require more software to fix, and the problem is to do with process complexity. If you can simplify that, any software you write will be more minimal.
So yes, the problem as always is with people IMO and having to educate/convince them to change their ways (or at least, open their eyes to a different solution). I guess this makes me a Type 2 as described by the article (although it naturally oversimplifies each archetype).
What some people might not want to hear is that, yes, I think you unfortunately can only excel at problem solving as an engineer if you also are good at the "product" management part.
I have a way more controversial opinion in industry that is a bit spicy... I think if you aren't coding the solution to the problem, you shouldn't be allowed to define the solution or get anywhere near it. In other words, even to my favorite PMs I've worked with - I think your job exists because many engineers are anti-social and don't want to talk to people. For the ones that do collaborate well, a PM is unneeded on the team and would be a detriment. It's not a personal knock - I just believe that to be the truth. The original agile manifesto got it right and we have collectively fucked it up.
That said, good product management is still worth its weight in gold. Someone who is willing to put in the work in terms of analyzing user behavior, has good UX instincts and respect for engineering can add a lot of value and magnify the impact of the team. It’s rare, but definitely a force magnifier for the team.
I think you're on the right track here, but from the wrong direction. You pretty much stated it earlier:
> the only way you can avoid that is by almost annoyingly probing to find the root of problem
I approach this as: if someone brings a solution, mostly ignore it and start asking "why?" until you're back at a root answer like "so my business can make money". I can't even count the number if times someone has proposed a solution where I've done this and not only ended up with something simpler and faster to build, but a better or more complete solution.
This often comes in like "just build a button to export this data to csv", which if you probe is actually "..So I can get it into Excel easier" ... "So I can reformat it to bring to this other system". The result is something like "what if we push the data to their API, that we already have integrated with, once every hour?"
Sometimes it's software, sometimes it's not, mostly it ends up being a mix -- but importantly if you don't ask "why" enough, you'll solve the wrong or at best only an intermediate problem.
Type 3 - Junior Engineer - I write software.
Type 1 - Intermediate Engineer - I write software for people.
Type 2 - Senior Engineer - I write software robust to the idea that people make mistakes.
So, for some software "I write software" can be better than type 1 and type 2. What if that were the case for the majority of software that would make money?
However, I propose that this doesn't matter, since another type of engineer is higher than these 3 types.
Type 4 - Principal Engineer - I write software and I have Virtue: I get to speak words; maybe you can speak too but I won't listen, but I'll make sure you don't think negatively (enough) of me to try to reduce my Virtue. For example, I'll spend time carefully listening and explain truthfully how things are complicated until our time to chat is up.
The truth is that there are big differences in techie types. The hardware people are radically different from the software people, and on the software side alone, there are at least three subspecies of programmers, two of which we are interested in here.
Forget about the first subspecies, the lumpenprogrammers, who typically spend their careers maintaining mainframe computer code at insurance companies. Lumpenprogrammers don’t even like to program but have discovered that by the simple technique of leaving out the comments—clues, labels, and directions written in English—they are supposed to sprinkle in among their lines of computer code, their programs are rendered undecipherable by others, guaranteeing them a lifetime of dull employment.
The two programmer subspecies that are worthy of note are the hippies and the nerds. Nearly all great programmers are one type or the other. Hippy programmers have long hair and deliberately, even pridefully, ignore the seasons in their choice of clothing. They wear shorts and sandals in the winter and T-shirts all the time. Nerds are neat little anal-retentive men with penchants for short-sleeved shirts and pocket protectors. Nerds carry calculators; hippies borrow calculators. Nerds use decongestant nasal sprays; hippies snort cocaine. Nerds typically know forty-six different ways to make love but don’t know any women.
Hippies know women.
In the actual doing of that voodoo that they do so well, there’s a major difference, too, in the way that hippies and nerds write computer programs. Hippies tend to do the right things poorly; nerds tend to do the wrong things well. Hippie programmers are very good at getting a sense of the correct shape of a problem and how to solve it, but when it comes to the actual code writing, they can get sloppy and make major errors through pure boredom. For hippie programmers, the problem is solved when they’ve figured out how to solve it rather than later, when the work is finished and the problem no longer exists. Hippies live in a world of ideas. In contrast, the nerds are so tightly focused on the niggly details of making a program feature work efficiently that they can completely fail to notice major flaws in the overall concept of the project.
Conventional wisdom says that asking hippies and nerds to work together might lead to doing the wrong things poorly, but that’s not so. With the hippies dreaming and the nerds coding, a good combination of the two can help keep a software development project both on course and on schedule. The real problem is finding such superprogrammers in the first place. Often they hide.
- Robert X Cringely, Accidental Empires
https://www.cringely.com/2013/02/10/accidental-empires-part-...
The takeaway for me is that managers who think they can offload to people have missed the tide - coders are the new managers because their workers are silicon, don't complain and so as they are told
coders are the new managers because CPUs are the new workers.
The push for AI isn't even trying to reach further than can be grasped; it's the ultimate lottery ticket to the well-to-do.
"Equity" feels like a mirage, often.
I mean yeah. That's everyone.
Engineering managers think horizontally in an organization, with enough depth in intra-team individuals and inter-team dependencies. There's a lot of similarities to software engineering: understand the product, know enough depth for what you're building, and understand dependencies on the edges.
Core pieces of these for an EM are fundamentals of human behavior, motivation, and process. There are global-ish truths about humans and global-ish truths about complex human hierarchy. For the former: individuals are more likely to get defensive when confronted in public.
For the latter: the same way there is a compounded risk of latency and failure with multiple network hops, there is a compounded risk of mis-alignment with multiple human hops.
I recently worked at a larger company (Stripe) where I was 5 hops from the CEO. Coming from startups, the information loss/skew between the CEO and my team was incredible. I found myself very much aligned with the CEO, which I could confirm by Slacking them. But by the time it trickled down to our team the incentives, motivations, and direction were mildly fucked. Navigating that is part of the craft, which we can feel any kind of way about but doesn't feel entirely avoidable.
"[X] will read [Y]" is a human fallacy, not simply a manager one. See: "just read the docs", "did you read the article you're commenting on", "the code is self-documenting", etc.
Engineers read code when they have to work on it. If naming and structure are good, it will be self evident what that code does and why.
Unfortunately it takes a lot of time to learn how to code in such a way that the author and coworkers can come to that piece of code six months from now and understand what it does.
A corollary is that everything should be automated or made impossible to do, because even looking at the company's wiki is something that most people prefer not to do.
Unfortunately it's difficult to know which automatic process is doing something, given that that something is a known unknown.
Further investigation certainly makes sense
Just some ideas:
- speed (obvious) - capacity (that's fairly obvious too) - reliability (MTBF, incident count) - The Google Speed vs stability metric - usability (starts out as a toughie but if you record users mouse / UI activity then it becomes measureable - and this is kind of the point - the more HCI is captured and available to the "virtual world" the more these problems are within reach. the more software eats, the more it can eat. - scalability : scaling up or down? Measureable
In early greenfield software, sure, but given the test of time this assumption will always fail. The reason is that each team that works on a given software has an operating context that's often undocumented. They use lingo and rhetoric that likely aligns to that and is illuminating now but when that lingo isn't as common it'll likely die off. The very idea that words of a contextual language will be exactly relevant in the future is a short-sight in its own.
Writing a lot of docs has its own tradeoffs, but I do think it's worth pursuing principles of writing good notes. I'm oft fascinated by reading the comments on old code that remain durable.
The two organisations are merged and confused in most places - even the hierarchies probably should be seperate.
The point being that four of the hops you had weee probably not in the first org. The alignment was perfect for what stripe actually is / does. The politics lies in what it wants to become - and that is a function of whether te people in the second orgabisation will keep power in the new place.
Software means we can I think seperate the two orgs.
Yes, this feels partly correct. There is a meaningful part of all layers that skew towards self-interest. Every hop amplifies the skew and has fewer checks because it is less visible/accountable to the top level.
The local maximum for someone reporting to the CEO is much more closely aligned with the long-term best interest of the company than someone 3 or 4 hops away.
Something I learned was just how much success is dependent on one's manager. In early startups, executing on what's best for the long-term success of the company (including when that is short-term optimization) is a good career strategy. Maybe the best. In larger companies—or at least in this single anecdata point, though others have said similar things about other bigger companies—that's not so true.
I found that sad.
In general this kind of attempt to automate humans is what kills companies as they get bigger.
More rules and policies, written assuming the humans involved are all idiots and need to not think for themselves.
And then instead of doing the hard work to standardize the systems, just offload all the quirky little differences that have accumulated over a decade onto the humans to try to keep straight, accumulating in a bunch of incredibly poorly written and maintained runbooks or whatever.
I was much more of a type 1 engineer when I was young. I read my email, I read instructions... doesn't everyone?
Most programmnig jobs force you to spend most of your time editing config files and trying to figure out why when you tried to use the library to do X it doesn't work properly! And then it turns out that you "just" have to configure Y and Z in particular ways, and you also need to make sure K is setup correctly at time T.
Here's the official Ubuntu documentation about how to install WordPress on your Ubuntu server.
https://ubuntu.com/tutorials/install-and-configure-wordpress...
I want to focus on steps 2 through 6
They are all about configuring the system/envnironment.
There are some tools that automate some of that. For example, you have to install about 10 packages. The installation of each package is mostly automated, except when it breaks for random reasons, but aside from that, even if it was perfect, you still have to know which packages to install and type out the commands to install them.
Type 1 in the OP is the type that thinks this is very simple and is not a problem that needs solving.
Step 4 in the guide has you edit config files in specific locations and execute some commands in a specific order.
Again, each step, on its own, would sound "simple" to the type 1 programmer in the OP.
Step 5 would have you configure a database.
Again large parts of the process are automated .. but ..
The whole process is complicated because at each step along the way someone thought the task is simple and their job is done and they just move ball down the field: it's not their responsibility anymore.
A type 2 engineer in my book would try to design the system so that they _avoid_ the need for all this cruft.
So a go developer that reimplements all of that in go, using rewritten buggy libraries?
If you create difficult solutions, you need to create a lot of documentation. And there is nothing that people hate more, than writing documentation :).
„But we can scale from 500k to 50 million users now“, which usually doesn’t happen. But what does happen is, that the system gets too complicated and too hard to extend or fix bugs.
1.) No one writes blog posts about using old boring stuff and meeting expectations. And such blog posts can contribute to recruiting and even, indirectly, sales, by helping your company get general press for being "on the cutting edge."
2.) You can potentially get better overall results even if the new tech has more gotchas and unknowns, because certain developers will knock themselves out to deliver on time and prove you were right in trusting them with the platform/language decisions. But you have to pick very wisely on this and keep in mind such devs may immediately lever their experience on the new tech to get a new job and leave you with a team of juniors that wander lost without their guru.
One thing I found useful is: try to build something that is boring old tech, but the boring tech can be switched out easily. Like a monolith that can be also split up into micro services (via a build flag).
Typescript and Golang for example, are relatively new-ish but still solid and boring, and have significantly much less gotchas than older established tech like, say, Rails.
I don't do Java, but I see it getting a bit of a renaissance. Either because of new features or because people are moving to Kotlin (yep for backends), which is a different language but still has the "solid boring" feel to it.
It is tough to hire for devops, though. The currently experienced people want to work with more complex infrastructure. Maybe we need a few more years to see those people getting burned and deciding they don't want to life an exciting work-life anymore.
I'm also one who uses boring old technology. Mostly relational databases and LTS operating systems. May not make for interesting blog posts but I'll take that over being called at 3:00AM because some microservice isn't working.
So I tend to build a system that can handle the load that is expected, and some reasonable scaling (maybe 5x to 50x more load).
If your product grows way faster then expected (1000x), you will probably have way more budget, and be able to do it even better.
Also, unlike sales/PMs ideas (well, at least a few of them), those complications created by developers aren't really helping sell the software. Nobody is buying software simply because it has 50 microservices, all the design patterns and needs Kubernetes plus a few thousand-bucks per month of cloud to run.
If only sales and dev drive product direction, with neither of them having explicit focus on what the end user needs, you end up with overly complicated, half-assed products, that kind of work, but not really, and nobody wants to touch.
On the other hand, what matters is money in the bank, so doing stupid shit like this is fine if the cash flow looks good.
It's usually the developers telling the sales guy "Sorry man we can't deliver this feature on time because our Elastic Search cluster is on Fire All The Time and we need to fix it before we can start adding new features".
"No, a junior can't add a filter to this column because the current system doesn't support filtering aggregates, so we have to partially rewrite it. No, we can't add this directly to the controller or model because there's no controllers or models anymore! Or more like: there's just one! Why? Because we wanted a future-proof system and decided to make a GraphQL simulacrum that allows adding new features without almost no cost! Sure, almost nobody understood it and sometimes it requires rewriting, but who wants to working on a fucking CRUD system?"
You could not make sophisticated HTTP-requests, because you had to use the in-house library. And off course it had much less functionality than some commonly used libraries.
So what I learned from that: abstractions can be nice, but they are useless if you can’t escape them. They must have „escape routes“ everywhere, to do things that are not covered by the abstractions.
There's unfortunately no known way to make good software other than keeping it simple, concise and without too many components.
The thing you can do to prevent it: continuous refactoring. It’s better to ship features on time and clean up afterwards, than cleaning up a lot before and never ship things.
As I said, using escape routes for some time, for speed, is acceptable. The problem is making this into a rule.
Refactoring a bad abstraction is easier than refactoring an abstraction that is messy and bad. So either refactor sooner (and create proper abstractions) or skip the “ball of gold” altogether (eg: use the original framework directly).
That still implies writing to an audience other than yourself, and the Curse of Knowledge still applies.
In many ways, it's much worse, because it's easy to assume that because the document is for a technical audience that the reader will know as much and have the same context as the author, and easy to include less supporting material. I look at StackOverflow and see how many questions are technically answered in the documentation, but in fact do not prevent the question from coming up. It's not the the questioner can't understand or the question is stupid, it's that the mental model of the reader and writer don't match up.
Of course it's much worse if, as in your example, the knowledge is in one person's head. That's a related problem, and having something is better than nothing. Even with some documents, cases still arise where there's a missing piece of information that the document author didn't record. The author understood what the document meant, not realizing it is only understandable given some knowledge the author did not provide.
The entire point of writing software is to communicate complex ideas to others.
Most programers are no good at writing code the communicates to other humans. They write code that computers can understand, which is a completely different skill.
Yes, there is - keeping huge documentation up-to-date.
It can be a hard pill to swallow to realize that we may have reduce the best possible outcome of our work, in favor of the best likely outcome.
YMMV, but I've run into plenty of Type 2 engineers who absolutely use it as an excuse to not do something or draw out what is often just a 15 minute conversation and a 15 minute coding session. It sucks to work with them.
Nope. Almost every time it's just a lack of drive to actually go and have that conversation. And almost every time, the conversation for a thing that's "complex" is short, there's no blockers, and the thing isn't actually that complex.
If the author just wants to stop at "Type 1 bad, Type 2 good", you could just as easily say "Type 1 cares about shipping and Type 2 doesn't".
He looked at me baffled, then responded, "then we'll fire them." And as brutal as it sounds, he was right in that case, at that company. There were rigidly defined process rules for the front line workers, and as long as instructions were clear, people followed them.
So I think there's a balance to be reached here, and I've had to come to peace with the idea that sometimes the answer is to hire an army of temps for a week to do some slogging task, rather than automate it. Sometimes.
The "how do we ensure they read it" we make it a requirement and if they don't get rid of them.
The 2nd type isn't smarter and wiser as the author wants to protray. They're just someone constantly worried about what ifs. There are always what ifs. And often these what ifs are minor problems if they do happen.
In the most extreme case they will leave the company and talk about how terrible the processes are. More likely they will be somewhere on the spectrum from doing the bare minimum to malicious compliance. Even for a rigorous and required process you still have to get some buy-in or you won't get the results you want from people.
And while experience may often involve lowering that weight over time, it's also important not to get too cynical (set weight to 0), and continue to attempt to estimate the parameter accurately: maybe the "ask people to do X" solution will give you a 30% probability they'll do X in any particular instance -- then ask how ok that is, etc.
"false positive" and "false negative" are easier to understand than "type 1 error" and "type 2 error".
What the author gets at though I do think is important. I've seen a lot of programmers fall into what I'd call the bureaucracy trap. Bureaucracy is often very attractive to a certain type of engineering because it's essentially programming the behavior of other humans. Even if the tradeoff is that overall, an organization is less productive but more consistent that's a very attractive proposition to these engineers. Anything that makes other people behave predictably is welcome.
Of course humans are, at best, faulty in their rule adherence (there's a subreddit called "malicious compliance" for a reason). So engineers who assume that everyone will just follow the rules end up surprised when someone breaks them. Part of being a "hacker", at least in my definition, is being able to diagnose the actual dynamics of a system whether technical or social.
That doesn't mean I submit to the view that you should go around paranoid forsaking the tool of bureaucracy entirely. Nor do I think there's any social status conferred by openly breaking rules (a mistake that I see a lot of young hackers make). As XKCD (https://xkcd.com/1494/) might say, "That cool hack you just thought of is called fraud and we already know about it."
Rather I'd suggest that if you feel inclined to write formal rules or policies for the behavior of humans you should instead write guidelines, define principals, and create incentives. Focus your time on aligning everyone on the goal not the process to achieve it. Accept the things you can't control.
That is very insightful and reading it now I wonder whether this isn’t the point I’ve been trying to make (author of post). Thank you!
this... is 99% of times missing. Even the "We'll fire them" mentioned elsewhere in some comment, does not always work.
The "we'll just do X" developer tends to think about codebases as they do the customer. "We'll just refactor <huge system>" or "we can just include <major new subsystem>". Type 2 devs, in contrast, are far more careful in their approach to the codebase itself.
The two balance each other out in the right ratios. Left to their own devices, Type 1 will bring innovative changes to a system while Type 2 naturally improve the stability of the system. I just think you want 3-4 Type 2's for each Type 1 you have on a team.
There is no one rule for that. Sometimes it is fine to assume that the user will "do it right" (it is fine to assume that a military pilot learns how to fly the plane before taking off), sometimes it is not (it is not fine to assume that a customer using an ATM knows how to build a Linux kernel).
The whole point of software engineering is to build an abstraction that makes sense for the targeted user. This requires experience (which is tricky considering that most developers have less than 5 years experience :-) ).
those who wrestle the world into neat, tight dichotomies
and those who realize that's not how things work.
1) Engineers who work on the external-facing side of the interface (possibly involving using many interfaces to build something with a user-facing interface, e.g. many app writers)
2) Engineers who work on the internal, engineer-only side of the interface (maximizing performance, optimizing at a low level, e.g. library writers)
3) Engineers who design systems by building interfaces at the correct points in the overall design that separate (1) from (2) (network engineering might fit here).
IMO. None of this really matters. What matters is correctly diagnosing the problem in the first place. And correctly diagnosing the capabilities of your tools and your employees. Once you have an accurate picture of the problem, the solution will come readily. The problem is no one wants to admit their short comings or limitations. They will always say they can do everything you ask of them. Then you tell them about the budget and limited time frame. And they still say they can do everything. What we need is productive candor.
You can have manual or half-automated processes when there are very few people. For me the threshold is 3 devs. Then you need to codify the processes.
Some people don’t bother setting up CI when they are the only developer. Others don’t ever leave the “I’m the only developer” mindset.
There are problems not worth fixing with telling people - if they fall in such ways we get support ticket and someone will explain to the user what just happens.
If this happens too often only then we know it is becoming worth fixing.
So for me article is wrong because author assumes there should be answer or solution for each and every problem.
So 1st type of dev might be right a lot of times because how often does it happen that people deploy at the specific time?
If it never happens in reality you just waste time solving it. On the other hand if it happens you will have to solve it then you might need action plan for it but … most likely you can just let people make mistakes and fix them on the spot.
I assume nvidia video card designers can be type 1, because other technical people will be interacting with their system. And if those people don’t do read the docs, and interact exactly how they should, it just won’t work.
Now if you work at adobe and are designing the video editing software that deep down actually uses those video cards, well you need to be type 2. The success of your product is more dependent on how well “the software does what the user intended” where intended might be a very subjective thing, likely based on other features that other similar software has, not related to anything technical.
We have to know our target audience well and always question our assumptions about them, because sometimes it may be surprising to see what users are willing to learn if they feel it is worth the effort. And sometimes it may be worth losing a part of that audience while the ones that stay will be much more convinced about what the product can give them back.
Saying “yes” is easy, everything else not so much.
Personally, Type 2 resonates with me, but I can see how this can be generally conflated with pessimism.
This is only true for justifying the "work" and some of the high level definitions of the "problems".
The same challenges exist on personal projects where the justification is arbitrary and can be nudged to get optimally simple problems (well made products) to fall out of it instead of ugly tangled knots (poorly made products).
The problem is that each type thinks they are the solution, and the other type is the problem.
it does puzzle me how programmer culture is to over generalise as if its some epiphany or fundamental principle
in fact this blog just diagnoses two common viewpoints or perspectives
perhaps its just a style thing to get engagement with a blog
I do think there might be some value (insight?) into trying to generalise things sometimes. In this case it’s me trying to split all software engineers along a single axis and seeing whether it fits. I don’t think it’s a neat split, but the more I think about it the more I think I could, if pressed, sort a lot of engineers into one of these two buckets. Not at all times, but sometimes.
Generally speaking: over-generalisation can be lazy and it was in this case — I write these posts very quickly, as a braindump, and you shouldn’t read too much into it, except that it might be food (snack?) for thought.
Proof: Those who believe this statement and those who do not.
Type 2: people who live in code and understand the needs and dynamics of the larger business
How do you think people fit in thee who want to build "self-healing" systems?
A solves easy problems with complex solutions.
B solves even complicated problems with simple solutions.
And your "root cause" is still a problem which you have to fix, it's not like your way of doing things allow you to not have to solve problems ever.