Programming: Doing it more vs. doing it better
kevinmartinjose.com
kevinmartinjose.com
I do find that a lot of programming stuff that used to be hard is easier for me now that I've been progrmaming for 38 years. But that doesn't mean I spend all my time doing things I can do without thinking, and it certainly doesn't mean I write code that doesn't need refactoring. Maybe my designs are better than they used to be — I think so — but often that's because I developed the design more incrementally through refactoring, rather than less incrementally by planning.
I do avoid a lot of errors by thinking through the consequences of a choice before taking action, in a way that I couldn't always do. But often that choice is specifically the choice to plan out a big design at the start of a project.
Also, though, what counts as "big" has changed for me. What I can hack together in an afternoon now might have taken me a week ten or fifteen years ago. So I can explore alternatives with less risk, in a way.
The author describes a lot of anxiety and guilt about doing things imperfectly. I think that's a big obstacle to improvement — other people can pick up on that and will be reluctant to give you feedback, and feedback from other people is a really fast way to improve. Also, it tends to shunt you into tasks that don't challenge you enough — it pushes you to avoid risk, and pushes other people to not ask you to do things that are at the limit of your abilities. This is precisely the dynamic Atwood was trying to combat by telling his story.
Did you notice any skills/traits in those people who were "unbelievable" in those 3 years? For instance, did they do "test driven development"? Also, did they keep good log habits?
So, basically, they are good in certain tasks, so as long as they do these tasks you won't notice their lack of experience in other stuff.
> any skills/traits in those people
There are no patterns, to be honest, otherwise everybody would do it. There are best practices (some of them are debatable, like mentioned TDD) which you can read and try to incorporate, but don't treat them as dogmas.
Solve challenging tasks, reflect on your code, try different stuff, actively talk and discuss solutions with more experienced engineers, and you'll learn (relatively) quickly.
And that point you write: "They also work with limited number of technologies, which makes them good in them. So, basically, they are good in certain tasks". An interesting observation, thank you.
There are things you can do that will, like the author said, give you faster feedback and thus let you get better _if_ you use that feedback. You might write a lot of code and read a lot of code and internalize good patterns. Eventually you will have enough experience and the confidence that comes with it, to take on bigger and bigger challenges. I don’t know what happens after that for I am still in that stage. But I have observed more experienced programmers and one thing they’re very god at is _really reading_ others’ code thoroughly and being able to spot better ways of doing things (which I imagine is through experience) and also thinking a little bit in the future rather than simply the assigned task. e.g. if assigned to create a new system, they won’t just follow the design specs blindly, but will question the design choices rigorously, helping improve the design a lot, and then implement something a tiny bit better than the eventual design.
Maybe I’m making it a bigger deal than it is, but I’ve worked closely with senior engineers and it’s _always_ a fascinating experience. They will question your design and code very very deeply but all of them will be good questions and will help you either improve your design or not add spurious code.
It also makes me think of the importance of stepping back, questioning the scope of "design choices" available, and anticipating things other "than simply the assigned task", possibly for some long-term aim, as you write. This is neat, thanks.
If I had to go back and modify the code, if I didn't understand it straight away then it was usually worth refactoring. It was my own code so I had no one else to blame if it was crap.
That probably has expanded into reading others code and seeing better ways of doing things like you say.
Here's a sample of things you can do to vary your programming knowledge fast.
Learn multiple languages C, asm, forth, lisp, prolog, any OOP
Code a card game, blackjack, cribbage, poker Code a board game, checkers Code a puzzle game, tetris Code an adventure game (text) Code your own text editor Code your own interpreter (BASIC or your own language) Code a network server & client (not REST, socket programming & threads) Code a basic CRUD app
They are deeply curious about a lot of things and soak up as much as they can, that's all I can say.
And will consider this: "Maybe out of their many projects, they really took one or two all the way and polished, but most were fast, done and the lessons learned. ... They also stayed deep in the language and didn't rely much on frameworks & libraries."
This is also useful: "Code your own text editor Code your own interpreter". I find these types of things intrinsically motivating, thank you.
I think generally you are correct, but these might be the exceptions to the rule.
Something I see with most IT folks is that they think they are so special and feel very threatened when other's can learn what they can and faster too. Being an expert in 3 years is possible in most fields, all you need is dedication and deliberate practice.
We are not special, let's get over it. The only crap getting in the way of youngster's today is filtering out the noise since there's too much crap. But once they sort it out, they will move 10x faster than most of us old timers ever did.
Do you have anything other than a personal anecdote to back that up?
> But once they sort it out, they will move 10x faster than most of us old timers ever did.
So instead of 36 months, youngsters today can become experts in most fields in 3.6 months? That sounds preposterous. I assume you think that because of the internet and modern tech enabling much faster learning. But then old timers have access to the same tech and knowledge. So why can't they move just as fast?
I've met or worked with programmers with 3 years of experience who demonstrated competence, but never proficiency.
Some programmers have a strong natural intuition, and a competent programmer with a strong natural intuition may appear proficient. It's a tricky distinction, but important to recognize (especially for the programmers themselves and anyone mentoring them).
However, I think most people with 3 years of professional experience programming are advanced beginners reaching competence in a few specific areas.
I’m basically an old fart who has learned and forgotten a lot of stuff.
It really depends on what you need. I think the 3 year programmer will struggle when moving out of their experience.
The person with decades of practice have faced and failed at a dozen core cs problems. They’ll probably fail, but they can explain their state at any given moment.
The 3 year person will fail or fail and self destruct. It’s bad for everyone involved.
Every once in a while your lottery ticket wins. That has nothing to do with experience. A kid can win and good for them.
I guess my biased opinion is, you get a small advantage with people with our track records.
Newbs can do amazing stuff. Old farts, like us, can also do amazing stuff. You can’t know up front which to pick.
I dunno man, be good to your coworkers. They often end up being amazing.
This is a pretty critical point in my opinion, but it also depends on the individuals drive. I personally put a distinction between programmer/scripter and computer scientist. One knows how to write code to get stuff done, the other knows some much deeper algorithmic and structural concepts that they can use to explain what they are doing and why they are doing it. And in today’s world it is much easier to be a programmer than a computer scientist.
It may be a broad oversimplification, but that’s my general purpose take on it. Currently, I know I’m a programmer/scripter but it works for what I do in my sysadmin and pipeline work. In the future I plan on revisiting some of the more core concepts to edge back into the CS world, but for now I need to do what I can.
usually, my spidey sense kicks in, and i inform my manager what they're asking is hard, like multiple people for years with no guarantee of success hard. Mostly, they cut the feature. rarely they say keep poking at it for a while. I've probably messed that up a few times. But at least once, i felt that the problem was 3sat. i'm not a doctor. i'm not a moron. the problem seemed really hard, and i think i mapped it to 3sat. Perhaps i messed it up, and it wasn't really np-complete. Either way, it's not like i could look up the answer in a book.
nobody wants to pay for original research. Very few people should do original research. I'm not a person that should do original research. I think i saved the company a lot of money by cutting the feature.
By the way, packing problems are 70% optimal by putting the largest in first and keep going till the next largest won't fit. (It's like the old fart description - I cannot quote the source but the spider sense remembers the shape of the problem)
That being said, I don't know the details of your situation
1. There's a difference between 3 years of experience 4 hours a day 5 days a week and 9 hours a day 7 days a week. That's 20 hours vs 63 hours per week. Furthermore, the 63-hours-per-week person has all of that experience in the last 3 year context. A 20 hours-per-week person would take 9 years to get the same amount of experience in terms of time. Technology changes much more in 9 years than 3.
Now, 9 hours of actual programming per day is very unrealistic. It's also the case that the 9 year person has much more varied experience due to technology changing, so they end up with different skills.
2. If you work on one project/system then after a while what you often deal with is specific to that system. It might not translate well to general programming or other tasks.
I've done programming for at least 9 years, but most of it has been on and off. I would certainly consider somebody with 5 years experience to be better than me in most circumstances.
Although it's not guaranteed, it's likely these kind of people are significantly better than their peers.
but it's a counter to the popular idea that "more work" is what it takes to become better at something. Two people in the same group will find that the one who tries more will get better results, but training for more time won't get them to a better group. Instead, qualitative changes are needed - probably many of them - people to work with, ways to think about work, habits of work, adopting the styles of those who are better, etc.
What if it applies to programming also?
Quantitative would be "I write more lines of code", "I solve more challenge problems", "I write and release more programs", "I code for more minutes each day, more days each week, more weeks in a year", "I suffer and endure more". This might get you further up in your friend group or class ranking, but won't take you to a new level (so claimed).
Quantitative changes would be things you suggest, like "I use different tools", "I approach problem solving in a new way", "I lean towards hard problems instead of retrying easy things", "I work with different people to learn new ideas", "I use languages which let me do more with less code", etc. (so claimed) those can take you to better output, even if your quantity of practice overall decreases.
We always say "practice makes perfect", but "do what winning people do" seems better advice than "do more of what you are doing, when you aren't winning". Phrased like that it's almost tautological - training longer with bad form, won't give you good form.
Sure, someone with 3 years experience could easily be better in some narrow way, but any programmer worth anything after 30 years experience has forgotten more than a 3 year coder could have possibly learned if he was literally reading white papers all day long for those 3 years and retaining 100% of it. There just isn't enough time in 3 years to cover the breadth of knowledge needed to be "better" than someone decent who has 30 years experience.
I’ve seen one or two rockstar developers in my time, but even they, would have had trouble keeping up with the silver foxes I know.
I think young programmers have an easier time picking up X framework because they have more time. That’s not really as valuable as knowing computation though, and I frankly think a lot of the YouTube and MOOCs you praise are to blame for the general lack of CS knowledge among a lot of young programmers. Some of them (the college ones) are great introductionary courses, but the majority of MOOCs are amateurs teaching amateurs.
Maybe that works in software because software is in high demand. I mean, I build a RPA process in a few days by google programming. It certainly works, sure, but I also know that it could have been build a lot smarter and more efficient by someone who knew how. That’s the thing with software though, you can get by if you deliver something that works okish. At least until you have to work in a field like medical software, where you code is quite literally never allowed to fail. Because someone will die if it does. At that point you’ll want the 25 years of experience, every time, and if that’s true for medical software, I don’t see why it wouldn’t be true everywhere.
For me, part of being "expert" is having broad experience, and that takes time. I think I would have used "expert" to describe my abilities after somewhere between 5 and 10 years.
I can believe that.
Yeah, there are; I've had the privilege of working with some of them. Probably they're even better now than they were then, though.
But you do, or at least give the appearance of it:
> Also, though, what counts as "big" has changed for me. What I can hack together in an afternoon now might have taken me a week ten or fifteen years ago. So I can explore alternatives with less risk, in a way.
I'm pretty sure that's the core of the idea. What you're doing in an afternoon looks just like being able to code without thinking to someone who would still take a week on it.
> code [...] is much more sophisticated and gets a lot more work done > [familiar with] more and more libraries > I've [...] learned more tips/tricks/shortcuts
I'd even throw something like "code is closer to correct on the first revision" into the productivity column.
In the original "10×" study, some programmers were never able to finish the assignment at all (within the allotted time); probably they either couldn't figure out a workable attack on the problem (like Ron Jeffries on Sudoku: http://ravimohan.blogspot.com/2007/04/learning-from-sudoku-s...) or they wrote their code as cleverly as possible so that debugging it was beyond their ability. The 0.1× programmers in the study were the ones who almost didn't finish in the time that the researchers gave them. Presumably you can think of problems that you know how to solve now that you didn't know how to solve in any finite time seven years ago; presumably also you've learned how to avoid introducing bugs that you would have introduced then, costing you, again, unbounded time to diagnose.
Or maybe not. Maybe I just learn slowly. I've certainly worked with programmers with only a few years of experience who were better than I was; maybe they'd already hit their performance ceilings. But I doubt it.
Could you elaborate on that? Maybe with an example of something that would fall into this "hack together in an afternoon" category?
I am still a beginner with less than 5 years of professional experience, but usually there seem to be rather large overhead to putting together new projects/services and getting everything up an running.
I can imagine being faster to proof of concepts in some environments (like a very involved framework - RoR/Django..), but not in others..
One night last year I wrote http://canonical.org/~kragen/sw/dev3/usql.py, a toy SQL database supporting queries that join up to two tables. I would have implemented more of SQL, but I had set myself a two-hour time limit, and there isn't a parsing engine in the Python standard library.
Last month I wrote a Mandelbrot set renderer in Python, but it was slow, so I rewrote it in Lua using LuaJIT, which made it extremely fast. That took less than an hour, but I subsequently added some more features to it, so it represents maybe a few hours of work now: https://gitlab.com/kragen/bubbleos/blob/master/yeso/mand.lua
(That one will only run on Linux right now, or MacOS with X11, because it uses my GUI library Yeso, which I haven't ported to Quartz or GDI yet. The others are portable.)
aspmisc, dev3, and bubbleos are Git repos you can clone if you like. You may need to append /.git to the URL.
Those were all purely programming exercises, not drawing on frameworks and libraries and whatnot beyond the very basic stuff that comes with the languages in question (and, in the Mandelbrot case, the Yeso library), but of course I've also learned how to use a bunch of tools; I can spin up a new React project with an Express server and get something working in an hour or two, I can hack together a visualization with D3 in minutes, I can spin up a test server on Bithost in a few minutes, I can import stuff into SQLite or LevelDB in a few minutes, I can write a website scraper using Beautiful Soup and urllib2 in half an hour or so, and so on. So if there's something that's easy to do in SQLite, I don't waste my time doing it the hard way in Python, and vice versa.
I think there's enormous value in investing in tools like Docker to reduce the overhead in spinning up a new environment. There's also a lot to be said for improving low-level skills like typing, text editing, and writing and debugging simple code. It allows you to devote more attention, and more uninterrupted attention, to higher-level tasks like system design. But mostly programming more productively is not about writing code faster, although that sure helps; it's about writing less code.
The Talent Code of Coyle is a good book to start reading about deliberate practice.
I've seen the both extremes, the programmers who are so serious about the style of the code that nothing really satisfies them (and consequently progress happens at snail's pace). Then I've seen those, who'll write the ugliest of hacks just to get the thing working and move on. I think there's a deliberate balance between the two, where you feel you're not wasting time on useless things but actually get something done, which you can then comfortably show to your peers without beginning to blush.
And only way of getting there is practise and being mindful of what you are doing. Similar to sports, music - whatever. To know where and how you did wrong is key, often you'll need a very good teacher to show you that. Criticizing yourself works too, but often you either become too strict to yourself or too lenient.
Just starting to code without worrying if this is the "best practise" or not will allow you get into a flow which is much better than over-thinking your approach. Because once you start to do it, like a good warm-up it allows you to see the problem much clearer as you become aware of the problems as you encounter them. Then if you have time, you might want to refactor your solution or just move on the next most important thing. Sometimes it's better to just write awful code to get to that MVP or other important milestone, only after which you start to review your code. Experience will tell you, when is the right time to move fast and when it's good to slow down and enforce a particular paradigm to your codebase.
From purely
I've seen the both extremes, the programmers who are so serious about the style of the code that nothing really satisfies them (and consequently progress happens at snail's pace). Then I've seen those, who'll write the ugliest of hacks just to get the thing working and move on. I think there's a deliberate balance between the two, where you feel you're not wasting time on useless things but actually get something done, which you can then comfortably show to your peers without beginning to blush.
And only way of getting there is practise and being mindful of what you are doing. Similar to sports, music - whatever. To know where and how you did wrong is key, often you'll need a very good teacher to show you that. Criticizing yourself works too, but often you either become too strict to yourself or too lenient.
Just starting to code without worrying if this is the "best practise" or not will allow you get into a flow which is much better than over-thinking your approach. Because once you start to do it, like a good warm-up it allows you to see the problem much clearer as you become aware of the problems as you encounter them. Then if you have time, you might want to refactor your solution or just move on the next most important thing. Sometimes it's better to just write awful code to get to that MVP or other important milestone, only after which you start to review your code. Experience will tell you, when is the right time to move fast and when it's good to slow down and enforce a particular paradigm to your codebase.
I have mixed feelings about the ceramics anecdote because I've met some people who have been coding a long time and producing large quanities of code but it's not good quality. To write high quality code, you need to enjoy the process and be adaptable. You need to have been exposed to a lot of different kinds of projects and management cultures.
Also, the most frustrating thing is that other people who are not good coders don't recognize straight away who is a good coder. Often, it takes a whole year to prove yourself. However, good coders usually know straight away who a good coder is.
Because of this effect, our industry is currently in a bad state. Many of the big popular tech stacks are mediocre compared to some of the alternatives that are available. There is a lot of misinformation and misplaced hype.
Most people who have the power to make hiring decisions are not sufficiently good at coding to be making those decisions. So good coders tend to find themselves smothered in most work environments...
It is simply 10x more valuable. And that depends on the organisation you work for, the state of the code base and so on.
Look at it this way - sports stars are regularly 10x, 100x more valuable to their team management than A.N.Other professional player. Take football (soccer) - Ronaldo is a waaaay better player than I am easily 100x, but take the newest signing in league 3 or whatever it is - can Ronaldo run 10x as much, is he 10x as likely to put in a penalty or a free kick? No. it's probably not even a question of twice as likely - it's percentages better.
It's just that those percentages matter when the cup is on the line. I am sure that Baseball statistics probably show this - the spread from top of the league to bottom is unlikely to be 10x more runs scored
So more and more it's worth remembering that the value provided to an organisation (and remember that's what you can charge for) is based not on your intrinsic qualities but what you can do for them in their current state.
I agree with your argument but I think your analogy is bad.
I think moreso than most careers, a single software engineer is capable of a tremendous amount of good or harm.
A spouse is capable of a tremendous amount of good or harm, but that doesn't mean marriage is a competition.
I once did some consulting work for a popular technology startup. I was appalled when I saw the hacks they used to get their stuff working.
But their marketing was perfect and all the devs raved about how performant and nice to work with their product was.
But when you looked at the internal code it was clear that a lot of it was written by clueless programmers who did whatever they wanted to get it somehow working. They used the worst hacks to get around the fact that the original product wasn't really built for the area they pivoted into.
That taught me a valuable lesson: everything I thought was important about building a good tech product is irrelevant. As long as it kinda works, you just need someone to sell the thing.
Now, markets aren't always zero-sum. But they are often competitive.
> When I write better code today than I did yesterday, you, my teammate, will be happier, not sadder.
That's also true in football...
Bad analogies suggest different mental models being discussed - what would you suggest is a better analogy - I would be interested in your mental model.
Facebook's biggest threat is not dying on its own, but the possibility of future programmers disrupting it. They're fine with paying billions for companies like Instagram and WhatsApp, because of the possibility that these companies would target the same market and hurt their profit margins. They pay very high amounts to poach employees from other large companies as well.
Compare this to programming. A programmer who makes good decisions early on the project will likely save his company a lot of money down the line. A few poor decisions here will cost them a lot of money.
Experience gives you exposure to other solutions and can give insights and alternative ways of approaching stuff which as you say can make a huge difference. Sometimes you do just have to grind things out though.
I could never have been as good as Ronaldo. I could never have even been a professional soccer player, I'm simply not athletic enough.
I don't really agree, since I consider myself a 10x engineer.
I have countless of examples of guys struggling for 2 months on some project. They get stuck, ask for help and I look at it and build it from scratch in a week.
It's not I'm typing faster, it's more about choosing the right architecture and libraries. You can save insane amounts of time by making the right descisions.
Besides the overall architecture descisions there are a lot of small day to day choices to make. If this value is not valid, do I throw an exception, or silently log something?
In both the small and big design descisions there is always a tradeof. Talent and (years of) experience makes that these descisions come from intuition, which can make you a 10x developer.
Have you ever wondered why the engineers don't come and ask your advice before they waste a couple of months?
I'd much rather be known as an approachable and helpful engineer who juniors can ask for advice, even if it means I'll never be known as a 10X engineer.
But the ones who don't are more difficult for me. I think some might be shy or unaware things can go better. The most trouble I have is with the really stuborn who don't want to learn, and think they know it all.
I try to avoid these engineers as much as possible, by hiring the ones I think are eager and willing to learn.
Where do you draw the line?
How often can a junior approach you before you grow tired of them constantly asking you for help/guidance?
The hardest problem with mentoring juniors is that most companies don't recognize the work put in. Still too many places judge purely on your direct work-in to work-out ratio.
Personally, it would depend on if they're learning from my guidance or not: if they keep coming back with the same problems I'd get frustrated that they (seemingly) weren't attempting to learn or improve. On the other hand, it they usually come to me with new problems they've encountered and gotten stuck on, I don't expect it would bother me nearly as much.
Of course, IRL it'll probably be somewhere in between.
Are you a 10x engineer or are they 0.1x engineers and how do you differentiate the two?
The only thing I know is I worked on many projects at many companies for the last 15 years. This gives some confidence :)
Here is a Steve Jobs interview that hopefully will explain it:
Take, for example, the median level 1x programmer. Perhaps a Java programmer working at a large tech corporation on a team of 1000+ in Indonesia or Brazil.
That guy isn't visiting HN. That guy doesn't read tech articles at home. He may join a few programmer groups on Reddit or Facebook. But his main concern is that he gets paid and feeds his family. He doesn't care so much about doing his work well, but he cares that he does it well enough to make a 10% salary raise each year.
He can probably reverse a linked list. But his searches are all O(n^2), and he can't do any less. The company that hires him doesn't really care - they're unfamiliar that things can be better, and as far as they know, they'd rather get hire ten $15k guys than a single $150k star programmer.
Is it possible to code 3x faster than that guy? Certainly. Especially when it comes to harder parts of the work.
Is it possible to code 3x better? As in code that's more efficient and doesn't crash as much? Also very likely.
And someone who codes 3x faster also reduces the cost of the project drastically - you can pay a team one month wages instead of three.
Now you put these multipliers together, you get easily more than 10x, quantifiably.
Sports players may try to run 100m a second faster, but star programmers can easily build a project faster and cheaper.
The next best would be understanding that there are many different ways to do "linked lists", and it's important to control the choice. Software dependencies have a huge cost.
The next best advantage would be recognizing that if you need to reverse a linked list in practice, you're probably doing it wrong.
Writing a linked list implementation isn't hard. There aren't many things that are hard to implement. What's hard is making good decisions what to implement. No library can help there.
Also, if he gets a 10% raise every year, he'll be making 73x as much (21x as much with 3% inflation) at the end of a 45 year career. If he starts out at $15k, he'll end up at $1.1MM/year, $315k in 2019 dollars assuming a hefty 3% inflation. Not half bad for someone who doesn't care about doing his work well and can't google a sorting algorithm!
If you do want to make an outsourcing agency, the good ones in a developing country make about $60k, which is enough to live in the top 10%. Companies like Accenture specialize in it, but they're not known for good treatment.
Well, three years is really not a lot when it comes to developing an intuition. Just enough to grasp some basics.
> a writer is someone for whom writing is more difficult than it is for other people
Yeah, I seem to recall Douglas Adams saying that the easier it is to read a text, the harder it was to write it.
At the beginning of my career I was constantly being praised for how fast I work. Well, I did stuff that worked, the effects were quickly visible, everyone was happy.
Even though there were code reviews to weed out the ugliest stuff, I wouldn't want to go back and maintain that software today :P
Or as some smart person once said, "brevity is the soul of wit."
Because only then, i don't fear refactoring later.
So i'll get my goal: Easy refactoring for fun and profit.
Refactoring is often underrated. Actually i learnt more from refactoring rather than "just make it work perfectly since day 1.
https://maximilianhoffmann.com/talks/programming/the-art-of-...
I had a boss once who was dumbfounded that I actually wanted to refactor code. I guess a lot of people want to write things "perfect" from the very start, but that perfection seems to be a delusion most of the time. The best way to know perfection is to see it in hindsight.
The first thing that's drilled into a new programmer is DRY. It's easy to understand and it works reasonably well. The next step up seems to be knowing when _not_ to roll stuff up, and how to tell when you're looking at a distinct piece of logic that needs to be reified into it's own entity or function.
EDIT: The Sandi Metz talk I mentioned: https://www.youtube.com/watch?v=8bZh5LMaSmE
It's more about having only one place where the logic is defined than anything else.
It's why I can't really take a regular job. There is no relationship between the quality of my work and what I get paid.
It's about how we could improve our life as a developer in general.
Lately, however, I've been trying to shift my approach to design when doing paid work: I try to make things that seem like they should be easy, easy. This is quite challenging in itself, but it's subtly different than trying to write high quality code. My goal is not so much highest possible throughput, or even programming ease. It's to make the process of programming less surprising to the paying customer. Of course, most paying customers have expectations far above what I could possibly achieve, but I see this has allowing myself room to improve.
I believe that if you are able to consistently achieve a result of "projects with this person tend to have fewer problems than projects without this person", it will translate into more $$$.
Bingo.
I think that the ability to partition code in such a way as to think about each bit in isolation is the mark of high quality code.
Real engineers spend most of their time learning, thinking, designing, and planning. Coding for them is mostly exercise for fingers, something which needs to be done but ultimately providing no challenge. They learned not only from textbooks but also from their own mistakes, and know what to watch for and where to double-check themselves.
The outcomes are strikingly different: code produced by real engineers usually simply works. No need to babysit it in production. It also solves the real problem rather than "improving" on something which was adequate in the first place (face it: most new software replacing the older one is worse - more bloat, more bugs, harder to use). The real engineer understands that complexity is THE enemy, and breeding (or dragging in) unnecessary complexity is a hallmark of a freaking amateur.
Oh, and academia doesn't teach engineering. Your C.S. degree means shit. Old codgers who remember punching cards and incantations like //GO.SYSIN DD * may be tired of learning the shiny new toys and aren't up to the speed on the latest jargon, but over the years of wrangling code they acquired wisdom, and you'd be very well advised to listen to them.
I used to think I’d get to the point where I could just sit down and breathe out perfect code, but that doesn’t happen. As I’ve thought about the reasons why, I came up with the following reasons:
1. Writing code is an act of inventing. If what I’m trying to build already existed, I could just go buy it and save myself a lot of time and money. It doesn’t exist though. I’m being paid to create something new and unique. This requires thought, trial and error, and multiple iterations to get right.
2. The software development landscape is not a static one. I used to build commercial buildings with my dad. Once I learned that studs should be set at 16” on center, how to measure and cut complex angles, and how to finish cement, I never had to learn those things again. They were pretty much static and I got to where I could breathe out a plumbed wall without thinking about it. In the software industry, developers are constantly having to learn new things. New languages become popular, companies jump on things like Kubernetes because everyone else is, the JavaScript community cranks out new libraries and frameworks on almost a daily basis. While the fundamentals of recursion, looping, and conditionals remain the same, the syntax, idioms, and best practices are constantly shifting. After 30 years of programming, I don’t think I’ll ever stop being an apprentice in at least some aspects of my career.
Here's another dubious analogy: when learning music, you do need to practice, but playing a song all the way through a bunch of times is a rather inefficient way to practice it.
For example (personal mnemonic to cover my own blind spots) when designing my feature, consider:
* Flighting, especially protocol changes, will this change cause clients to be unable to talk to services?
* Risk: if this change breaks its service, what else breaks? What is the recovery path?
* Security: does this unintentionally relax or circumvent existing security boundaries? How much damage can an abuse of any code that writes/modifies do?
This is not a complete list on purpose. I use it to shore up the things I tend to forget to think about.
Each of these things will branch out into different areas. You may need to write a text parser. You may need to design a USB protocol to relay packets. You may need to learn a processor architecture, calling convention, assembler mnemonics.
Over time you'll gain a lot of knowledge and you may be able to cross-apply plenty of it accross the domain boundaries.
Not that I think one should never do any hands on practice, but if you spend a large chunk of time learning the concepts of different mathematical fields related to programming, as well as the teaching of other programmers, you'll become a much better programmer than you ever could otherwise.
If you've only been programming 3 years, you're definitely going to make a lot of mistakes. That's good! That means you're pushing your boundaries and learning. Peer review feedback isn't a mark of shame; and being attached to your code is a _bad_ thing. At the end of the day, coders vastly overvalue code beauty and aesthetics, and overestimate how long their code is really going to live. (I've been a professional for about 11 years, and while I take pride in my work, a lot of the companies I worked for either folded, pivoted to a new product, replaced some of the things I wrote with open source solutions after the problem space had become less novel and a proprietary solution didn't make sense anymore, or a billion other reasons why the code didn't need to live anymore. I'm not saying that's an excuse to write shabby code, but a lot of times "it works and it solves the problem at hand and the code isn't a disaster" is when you should stop working on it).
I think coding is a lot more like creative writing than it is like engineering, and if you want to get good at creative writing you make a point of writing a lot of stories, even though a lot of them won't be good. Or if you're composing music, you write a lot of music, you don't focus on one piece forever. Anything where you make, the more you make, the quicker you get better at it.
If I have to pick, I’d err on the side of doing more than trying to slow down and write perfect code. When you’re junior, your definition of “perfect” code might be very different from others’. You might be reinforcing bad habits rather than learning. I’ve seen junior SWEs insist on spending hours eliminating a couple lines of duplicated code by pulling them out into functions to achieve their perfect code. At the same time, they neglect basic coding hygiene, put defensive nullptr checks everywhere, and not design for readability and testing.
I am experiencing something similar as I continue to study the classical guitar.
I agree that the importance of deliberate practice over just coding and coding really does matter - in my day job I will write many lines of code doing the same string processing etc. (I work in Data Science) but when I am trying to learn I really want to think if I am doing it in a Pythonic way, how I might make the code more reusable and so on.
That truly was quantity over quality. Oftentimes I had to wade through piece-of-shit code that really made my soul hurt. Really. Bad.
But in hindsight that was good. It's good to have spent 4 years ONLY writing code 8 hours straight 5 days a week.
But I never, ever, want to go back to anything like that.
There were some projects in the company lead by developers that were some of the best I ever worked with. They upheld very high standards and the code was some of the best I've seen. Most projects were a total mess and nobody asked questions or reviewed code.
I worked on both type of projects. I think it really helped me. Some projects I just wrote code hours and hours on end without little regard to quality, but later on other projects within the company I was exposed to people and code that was significantly better.
By that metric George R.R. Martin is on track to be the greatest writer of all the time :)
I'm definitely a little bitter about it, but I've accepted it. Parris needs the royalties.
/salt: Somehow, within that time, Robin Hobb managed to spit out a trilogy seemingly once a quarter. Thankfully, Steven Erikson came along and wrote The Malazan Book of the Fallen, which, if you like books, honestly puts ASoIaF to shame on numerous levels (and has the benefit of being done).
One of the biggest mistakes (the biggest one is probably not writing tests) I see junior engineers make is trying to optimize before fully understanding the required functionality.
James Joyce wrote Ulysses at the rate of a hundred words per day if you only consider the finished product. However, I doubt every word that Joyce wrote ended up in Ulysses. I'm sure he did quite a lot of cutting and rewriting.
The takeaway from me from the two quoted stories was that quality and quantity are not at odds, but instead are the yin and yang of productivity. They reinforce each other. The more things you produce, the more patterns you are exposed to which in turn leads to higher quality since experience leads to efficiency, giving you more time to get things right.
Once you get a good enough big picture then you probably will start to realize where how to optimize the data and create better methods, but even there it still never stops, you now know the system, and can figure out what you need from the technology to construct a better platform.
The databases I've worked with for over 20 years have evolved as I have added more functionality, I have been able to identify where the priorities were as well as how to make it function more dynamically. I didn't really get the big picture for a decade as they were sill doing part of it analog and only requested (revealed to me) more functionality as the system grew more capable.
You may think you know it all now, but I would think there's still a lot more road to be covered after only three years.
Yes—write a ton of code.[0] Just do it. Make your favourite couple languages extensions of yourself.
Yes—think through your code really clearly. Spend a day on your migration or other data-structure altering changes. They're going to echo throughout your whole application and, ultimately, organization.
[0] The closer you get to the API, the faster you should code. Not the interface definition itself, that should be thought through, but the code that responds to a call to the interface. The serializer, the part of the controller that calls the render, these parts are easy. Just roll them out. The models and migrations are much more important. Spend time there. It's not an all or nothing thing.
Taking my sweet time is definitely not productive either.
I find the balance is to treat it like sketching. Instead of trying to "print" out code, well designed from scratch, from top to bottom. It's better to sketch out the main "lines" of it. It involves a lot of erasing past lines and old code, or even making redundant code at times. You definitely need a lot of scaffolding and placeholders, especially early on.
(Also three years is a really short time, though the author seems to be using that time well in order to learn and meta-learn).
The master potter does not churn out pots that need to be fixed. He focuses on quantity to get to quality faster, that is the whole point of that story in my opinion.
Also, "refactoring code" should not be seen as such a separate activity that it can (or should) be done by other people.
> Programming system builders have also been exposed to this lesson, but it seems to have not yet been learned. Project after project designs a set of algorithms and then plunges into construction of customer-deliverable software on a schedule that demands delivery of the first thing built.
> [...] plan to throw one away; you will, anyhow.
Fred Brooks, The Mythical Man-Month (1975)
That being said, I definitely don't pretend to be the Thomas Mann of software engineering.
This is not the case in the industry, we cannot change everything in a product at each iteration. This is why at least a little care and architecture have to be done before doing it and trashing must be made with care.
Does this happen? I've programmed daily for ~11 hours/day between 2 companies, but at 15hrs/day I feel like there is diminishing returns.
"Being able to balance those two core things to meet client needs."
Any kind of extremisms is bad, no matter where applied.
How to recognise the former group: they obsess about coding and other standards and processes, plan and discuss too long how to implement something (plan what to implement, do it, then improve it when it's done; inspiration comes from working on something, not from thinking about it) and never even meet their own estimates for how long it'll take them to deliver. They will tell you they are taking so long because they haven't decided yet how to best implement something, but they don't even have a straightforward implementation (there's always one). If they were truly concerned with "the best way", they'd have several solutions implemented already, together with metrics and benchmarks. They haven't, because they're vain impostors and not capable programmers.
I have worked for a company that eventually went down because there was absolutely no separation between business logic and user interface. When no one any longer wanted to pay for a system with an ASCII-interface (this was about 1995), they had to throw out about 5 million lines of code and never recovered.
I've worked with systems that had to be thrown out because no one any longer wanted to pay for a week of work for something should be possible in two hours.
Either extreme is stupid. Of course you have to ship. And in early stages it often makes sense to accrue debt to get fast to the market. But of course you also have to be able to be nimble and move fast even after two years and five. You can't do that if all your resources are tied up in interest payments.
Kinda obvious what their actual mistake was then...
> I've worked with systems that had to be thrown out because no one any longer wanted to pay for a week of work for something should be possible in two hours.
I see a pattern there.
> But of course you also have to be able to be nimble and move fast even after two years and five.
You can also go broke while chasing this illusion, twice. Whether as startup or established company with a "big ball of mud" codebase.
I'd rather tackle the "no one wants to pay" problem in a profitable company than a complete rewrite, or even trying to boot up a new company while, in addition to all the other problems involved, trying to write "beautiful code", thank you.
Maybe I wasn't clear enough, but "no one wants to pay" and profitabitity just don't go along very often.
The non-refutable answer is you should spend an adequate amount of time thinking about stuff before doing them. Anecdotally I've found that people are not very good at thinking well while simultaneously coding, so thinking a bit before opening the code browser works pretty well
Being able to distinguish avoidable technical debt and reasonable tradeoffs at the time can save you a hell of a lot of time. And yeah working in messy codebases suck! But more importantly it can cause people to lose time they could spend working on more features and shipping stuff
In the end, all code is debt. The only thing is whether you earned anything from the debt. If you never earn anything it doesn't matter that you didn't take on that much debt.
False. Sure, technically, this is true, but in practice there are lots of variables at play here. Who is going to pay for the rewrite? Is the company profitable enough to do that while maintaining legacy code for current users to use? I'm not saying the only way to develop a product is to get it right the first time, but ideally, organisations shouldn't have to pay for the same product twice.
[1] Examples I can think of off the top of my head: KHTML/Webkit, Hanami.rb, the Go standard library, sqlite...
Ousterhout uses the term "tactical tornado"s, which I quite like (source: https://twitter.com/johofer/status/1035442341199446017 apologies I don't have a better source handy).
It seems best to defer architecting just long enough to see that some component is becoming problematic, but not much longer. Do it too early and you waste effort. Do it too late and you have a much larger mess to clean up.
A very good rule of thumb to recognize the former group is to simply ask "when is this best practice not valid"? This will tell me whether they are consciously proposing it or mindlessly adding complexity. For every single "best practice" I can find you a case where it's not valid, and if you cannot then there's something very wrong.
It looks like you add purposeful breaks, experiment, and then see what happens. I wonder if you also talk with your colleagues, self-reflect, think about the big picture rather than just the task at hand when you're doing this?
Since I am self-taught and everyone was talking about "best practices", I started to learn and follow those around 1-2 years into coding. I built beautiful abstract glass houses that didn't get me any closer to my objectives! So I was curious why these best practices were slowing me down and started digging deeper to be able to know how, when and why to apply them. Lots of conflicting info online, so had to start thinking about those by myself and not just follow random articles. I even started searching conflicting info to see the two sides.
But yeah, you are totally right, devs get stuck into that pixel and forget about the larger picture. I switched my thinking to a purely "ROI" for the business, and I am convinced it's been a strong win-win. But you have to learn about the real, implicit and explicit, business objective, which is something 99% of devs do not really care (or need to, in this market). I also started realizing how code was many times not taking me closer to my objectives, but that's a topic for another day.
Also like your view: "I switched my thinking to a purely "ROI" for the business, and I am convinced it's been a strong win-win. But you have to learn about the real, implicit and explicit, business objective, which is something 99% of devs do not really care (or need to, in this market)." I find this increasingly important, too, thank you.
Not sure about that - the applications I'm most proud of actually came from extended periods where I was involved in maintaining an existing system, carefully thinking about how it could be improved, so when a chance came I could propose a new application with a well defined list of benefits. Note that by "extended period" I mean a couple of years!
Whenever I feel bad, sad or just in need on some enlightenment, I go to https://github.com/fogleman and browse Michael's repos.
You can still write beautiful code and be productive. OpenBSD contains some examples.
Of course, as you say one should not talk about writing beautiful code. Just do it.
Yes, by all means - if you can, do it. But please try to become as productive as John Carmack first before you aspire to write similarly beautiful code.
Your thoughts seem to be very subjective. I hope you don't write your code as naive as you wrote this comment.
I code for over 30 years now. It has always been my desire to write beautiful code that reads well, scales well, has no bugs and performs good. Does this makes me a vain imposter and not capable? At this very moment I am working on a total rewrite of an unmanageable codebase that was written by a very 'productive' guy.
How I take the article, and what I think most in this entire comment thread agree with, are the following principles:
[1] code quality IS important. I define 'code quality' here as how many bugs are introduced to do a given feature, how resilient this code base is to requests for additional features/changes, and how easy it is for new hires to grok it / for you to grok it after a few months have passed working on something else and you've lost familiarity.
[2] Whilst it is important, it is not the only concern. In fact, a shipping product is MORE important. That's not to say that code quality isn't important. Any project that has deplorable code quality even if it ships is in trouble.
[3] So far the most effective strategy for producing code with high quality, is experience (that's subjective; my opinion. But I bet you share it). The best way to get experience is to write lots of code. In fact, writing code of LOW code quality should help MORE: The 8th feature request that comes in that initially sounds like a job of a few hours that turns into a weeklong exercise in frustration with stapled onto the end of that process another week or two chasing bugs - and maybe you learn something about where you went wrong in your code that powered the initial shipping product. This sounds like a much better way to learn these lessons than reading a bunch of blogs and listening to a bunch of presentations theorising about what 'beautiful code' means.
[4] extremes are bad. This more or less is already concluded by #1-#3, though. However, the 'beauty' extremists tend to present, blog, and in general act like they hold all the answers, more than the cowboy extremists do. That's entirely subjective opinion, of course. It's just my experience, and yours may well be different. But _IF_ it is indeed true that you're far more likely to run into a beauty extremist than a cowboy extremist, then it stands to reason programmers who are irritated by extremists of any colour will tend to exaggerate somewhat more on the _other side_ of the beauty extremists.
In the end it's a pendulum, isn't it? A presentation or blog post that comes across as authored by a beauty extremist probably was a capable, 'well adjusted' (in the sense that they would agree that shipping code is at least as important, and experience is very important) – but decided to exaggerate a tad on the beauty side to address some perceived notion that the audience's balance was too far towards the cowboy end of the spectrum.
Enough of those kinds of presentations, and a few are bound to perceive that the pendulum has now swung too far out towards the beauty end, and start exaggerating the value of the cowboy end.
Of course both extremes are bad. I lean towards the perfectionist camp, so I actively seek to work with someone result-oriented. I've found this teaming to bring great results, where both my partner and myself end up happy with the outcome and fulfilled in ways neither of us would by ourselves (for me because I produce more givem the same time, and for them because they feel much more confident in the resulting programs - corroborated later by the much lower number of bugs found in them).
I know this is the case because I've been told many times by many different people (and most of them actively seek to work with me again afterwards if the opportunity arises).
I think the key here really is mindfulness. Developers read code significantly more than they write them, and one of the primary goals of best practices and clean coding guidelines is to help teams communicate effectively through code. Writing code well is a skill, but that doesn't start and end at taking all the "rules" to heart; that's just the first step. The next is really to recognise that there aren't any rules, but more heuristics based on collective experiences. Software development is not an exact science, and just like the Agile Manifesto, clean coding guidelines only provide framework upon which to build any team's practices: a starting point from which to find what actually works for their project.
ability_to_beautiful_code ---V------------ ability_to_deliver
Programmer should be described more like:
ability_to_beautiful_code: 0%---V-----------100%
ability_to_deliver: 0%----------V----100%
And both metrics should have certain threshold for you.
People who push "mostly working" code are hell on earth. Sure you spend 5 hours less on it right now, but it's going to cost literal days or weeks down the line.
How many times have I seen developers push some "good enough" code that they didn't discuss with anyone because it looks good to have XXX commits for their quarterly feedback. They knew "what" to implement but not "how" to implement it or even "why" implement it in the first place, which ends up in hours of useless discussions that would have been avoided by a 1hr meeting before starting coding. How many times have I seen people going for a DB, stick with it for years because "that's what google/facebook/whatever uses" and end up having to migrate everything to another DB because they went to fast and didn't spend 1/10th of the time on analysing their needs and writing specs.
Do you spend 10 years designing a plane and then 6 months actually building it, or do you spend 6 month planning it and 10 years fixing broken, hacky, "mostly working" parts ? What works for school or hobby projects doesn't work in most professional environments, especially nowadays when developers stays 1-3 years in a company and move to the next job leaving a pile of unmaintainable "mostly working" code.
Coding is the last stage of the process, it's the easy part, a monkey could implement the code if the specs and processes are solid.
People who want to deliver at all cost are not role models, don't listen to them. They are vain and not productive. They might be capable coders but they're not capable engineers for sure.
“Programs are meant to be read by humans and only incidentally for computers to execute.” ― Donald Knuth
Wildly exaggerated, but I'll bite: it's still better to save 5 hours while you are bleeding money (before your product works) and spend 1 week to improve the "beauty" of your code while it's already paying your salary.
> “Programs are meant to be read by humans and only incidentally for computers to execute.” ― Donald Knuth
That's a fine attitude for someone who wants to teach CS or explore programming as a hobby. For professionals, programs need to execute correctly and go into production ASAP. Emotional and mental cost to the programmer is of less importance.
Only if you want it to be like that.
It's as if an assembly worker from 1930 was telling his mates that working 90 hours a week and wasting his health for a few $ is ok because it's good for their bosses.
Might be ok if you're the #1 in a SV startup, sure, but everywhere else I doubt it'll take you very far.
[0] I call this the Neo Architecture. They're looking for "the one". The architecture that will allow for any CR to be handled elegantly and beautifully, where all concerns are completely separated, where all data is perfectly abstracted. There's no such thing. It doesn't exist. Just ship already!
Because people who write "beautiful code" don't often achieve anything that can be seen. Successful companies are based on quickly written code that delivers.
Also, ability to write beautiful code implies the ability to deliver code much more then vice versa because there is a good chance that someone who actually is capable of writing beautiful code had to get to that level by actually also delivering stuff to production in the past.
So yes, in my world, someone who writes a beautiful code (meaning - correct, performant, maintainable, understandable, clever and so on) is a pretty good candidate to be a role model.
My favourite part of this is how often these criteria are essentially at odds.
- Understandable *and* performant?
- Clever *and* maintainable?
But, you know, I'm also bad at all this so maybe it's just me :pAgree entirely that they're all things that contribute to "good"
Part of it is using the tools others aren't aware of, so simple things become simple (counterexample on codinghorror, someone not knowing that XML has libraries to parse it, and started parsing it manually with regeps. From my own experience taking over a web-scraping project, I used XSLT where they previously used regexps). I have plenty of other examples of people doing things the hard way because they didn't read the docs.
Part of understandability is recognising a simple solution exists instead of a tangled ball. The simple SQL solutions are often most efficient, with tweaking, and the most understandable (which does NOT get you out of writing comments, BTW!)
Performant? The easiest code to optimise is that which is well written and nominally 'less than efficient'. This separation of layers allows me to put in new layers easily as I can see what's going on. Example: for an SQL + pascal product I got a minimum 10X speedup on the GUI, which really made a huge difference to the users, by sliding in a 3rd layer between 2 existing layers. It was simple and quick to do (3 days).
Other example: if someone had thought for a moment about creative use of SQL indexes they'd not have written another complex - and slooooooow - feature in the product I just mentioned.
So IME understandable = clever = performant = maintainable surprisingly often.
(disclaimer: I'm no coding god, I make plenty of mistakes too).
The only little nit-pick I have here is the use of the word "clever". Maybe you and I define clever differently in a software engineering context, but to me, "clever" is a dirty word in programming.
For me, "clever" means undefined behavior, one-off hack, difficult to parse, shortcut, etc. The difference between "clever" code and "bad" code is that "clever" code is written by someone with a lot of knowledge and experience. Their knowledge and experience has allowed them to work with the undefined/undocumented behavior of languages, libs, etc in order to come up with a solution that has the least lines of code/uses the least memory, etc. Not to say that those things are unworthy metrics, but "clever" code doesn't seem to consider maintainability or stability.
I think a better descriptor to strive for is "elegant", defined in my opinion by code that is beautiful in it's own simplicity, succinctness, reliability, and correctness.
Generally done by people who don't think through the requirements or know why they're doing what they're doing.
"I just copied pasted the example and hacked it until it did what i wanted. I'm still not sure why it works lol"
Completely fucking over the next person who has to work that code.
I like ideas from the systems thinkers like Russell Ackoff about this.
> Ackoff expands by suggesting that doing things right is about efficiency but doing the right thing is about effectiveness. He makes a strong case for the connection between wisdom and doing/identifying the right things. He notes further that when we try to do things right about the wrong thing, we actually make things worse. Such attempts at improvement actually take us further from both the recognition and accomplishment of the “right thing”.
https://ackoffcenter.blogs.com/ackoff_center_weblog/2018/04/...
I think it's between spending some time and thinking about the problem you are trying to solve vs brute forcing a quick prototype to get it done.
I think your code will look beautiful by itself if the engineer fully understands the problem at hand.
This process takes time and practice. I personally throw away my quick first solution and let the fog clear first.
Somethings that have generally given me good results: drawing stuff, taking small breaks, listening to my tests (if my tests hurt, it means my design is bad)
Would love to hear other thoughts on this !
I think you're right for some classes of problems.
For others, going slow and painstakingly seeking to simplify is the only way. Otherwise the complexity will eat you alive and the whole edifice will collapse on itself.
Freedom is slavery.
Worse is better.
Just for the record procedural programming and functional programming are the only two styles of programming to me that make sense. Procedural because its how the machine model works and functional because its how a mathematical description of computation works. WTF is OOP (how the over active imagination of a child works I would reckon).
The machine should also guide the programmer as much as possible. I wish Golang had refinement types like Liquid Haskell or ATS. Some simple static analysis to cut down on crufty slow runtime test suites.
But then again I mostly use Python and JavaScript which are multi paradigm so perhaps my mental model had evolved because of that.
Casey Muratori had a good quote with regards to it (paraphrased): "Having objects in your code is fine, it's natural. We've been doing it since before OOP was a thing. It's the whole phrase 'object-oriented' that's the problem. You're orienting your thinking around objects, not functions. It's the orientation that's bad about it, not whether you wind up with an object."
Re OOP, it provides a method to model what you term a "domain".