1. Understanding how the language works. Additionally understanding how the language infrastructure interfaces with the computer.
2. Anticipating problems. Prefer solid foundations over veneers that appear to get the job done.
3. Organizing and designing systems. Essentially, SOLID.
Two things on this:
First, bad code often results from conflicting goals. Moving goalposts and on time shipping, for example. The result appears to have been written by a poor programmer, when this may not be the case.
Second, the most valuable skill a programmer can have isn't technical, but rater social: empathy. The best programmers I've seen have it and the worst completely lack it.
Lack of empathy leads to poor communication. If programmer can't anticipate or read his/her audience's perspective, there's no way s/he can communicate a complex concept to them. The temptation will be to blame the audience when in fact the failure lies squarely with the programmer doing the speaking or writing.
Lack of empathy also leads to disregard for the needs of users and future maintainers. Systems get built that don't need building, and systems that should be built aren't. Should the two happen to coincide, the system is a nightmare to maintain because the programmer simply didn't care about the people who would need to maintain the contraption.
A lot of the 10x programmer discussion focussed on people who lack empathy. For some reason, it's easy to conflate lack of empathy with technical skill.
Yeah, context and empathy are two things that I'm only appreciating more and more as my career goes on.
I once had this small but terribly written module written by an inexperienced developer who wasn't given the kind of feedback and code review that he should have been given. It was still running in production years after that person had left because it was in a corner of the code base that was basically never touched. What made it interesting to me was that it was badly written at almost every level from the high level separation of concerns to low level coding practices, while still basically getting the job done.
I started giving this module as an exercise during interviews for a certain position, with the framing of "This was written by an beginner developer on your team. What kind of feedback would you give them to help them improve?" This sort of thing was actually a major part of the job, as it was a position that would be a kind of consulting resource for other teams and would involve many code reviews and encouragement of best practices -- basically providing subject matter expertise to full stack, cross-functional teams.
The results were fascinating to me because it acted like a Rorschach test of sorts and told me a lot more about the focus on the interviewee than the code they were criticizing. More junior candidates immediately jumped on the low level issues like the boolean assignment example, naming conventions, or small snippets of code duplication, and spent all their time there. More experienced folks often mentioned the low level issues but spent more time on the higher level problems -- the class should be broken out into two, extending in the most obvious way would be hard because XYZ, this etc. Some of the best candidates would ask for more context on the situation and overall codebase.
It also helped weed out the jerks who, despite the prompt, decided that the exercise was an opportunity to show off and insult the original author (who was of course anonymous), venting about how stupid something or other was or using it as a springboard to attack their current co-workers. Everyone starts somewhere. It's fine to wince a little at something that's poorly written, but the point is to actually help them improve. The better candidates were there trying to understand what their gaps in understanding were that would cause them to make certain mistakes. The very best candidate was trying to map out a staged plan of more easily digestable things to work on so that they're not overwhelmed all at once -- extrapolating a whole technical mentorship model out of what they could glean from the code review.
> the most valuable skill a programmer can have isn't technical, but rather social: empathy
You should say "a programmer needs social skill as well as technical skills to be valuable". If a programmer doesn't have a basic aptitude for programming-like tasks, they won't be able to understand how the language works, anticipate technical problems, or organize and design systems. Until you've worked in a group that's filled with "programmers" who don't have the aptitude for coding, you won't really understand this. The social skill must complement the technical aptitude and skills, but is not more important than them. In fact, I'm even suspicious of people who say "the most valuable skill a programmer can have isn't technical, but rather social" because they often turn out to be aptitudinally-challenged programmers themselves.
"Social skill" and "empathy" are very different things. An awkward person can be empathetic. A charming person can be callous.
In fact, I'm even suspicious of people who say "the most valuable skill a programmer can have isn't technical, but rather social" because they often turn out to be aptitudinally-challenged programmers themselves.
In my experience the programmers who are saying that are usually engineering leadership. If you believe the endgame is becoming engineering leadership, then it's absolutely true that soft skills become more important.
While I don't agree that "social skills" are the most valuable skill for a programmer, I do sincerely think it is the most common reason why competent programmers hit an invisible ceiling in their careers. I've seen plenty of programmers who are technically talented and hardworking, but who get stuck in their careers at the junior end of "senior" because nobody wants to work with them no matter how right they are. If person A is right 90% of the time but nobody wants to deal with them, and person B is right 80% of the time and people are willing to listen, I would rather keep B over A because those junior developers who are running at 60% will turn into 80%-ers under B, but they'll stay 60% under A.
I think the difference is that empathy often correlates with teach-ability, and it's much easier to teach someone technical skills than it is to teach someone empathy.
>The temptation will be to blame the audience when in fact the failure lies squarely with the programmer doing the speaking or writing.
This is a popular claim on HN that I don't think is true. Where does the boundary end? Is it my fault they can't understand my program if they don't know any code at all? What about if they're a Python programmer hired onto a Java project? The point is you should make a good faith effort to write readable code, especially for your team members, but you're a programmer, not a teacher.
>Lack of empathy also leads to disregard for the needs of users and future maintainers.
This I agree with. Its a very underappreciated reason to build empathy as a programmer.
You’re assuming that the only way developers communicate is through code.
But it’s not. If you want your message to be understood, and the listener is making a good-faith effort but doesn’t get what you’re saying, the onus is on you to communicate in a way the listener understands.
> Second, the most valuable skill a programmer can have isn't technical, but rater social: empathy.
couldn’t agree more!
but the term you’re really looking for is perhaps a strongly developed theory of mind. whereas empathy really is referring to emotional awareness.
the worst and also most annoying programmers i know, to a person, consistently fail to see other points of view. their way is the right way, period. they tend to actually be smart, and right about very many things in a small problem domain. i dare say their raw intelligence is a double edged sword.
Maybe empathy comes in when trying to frame criticism in a constructive way that the receiver will internalize and find helpful?
In some cases, it might be better to ask them about reasoning around a particular bit of code than to offer alternatives right away.
In others, a good idea or anecdote about something you found useful in that spot, might be better received.
In my experience, there is a good amount of empathy (or emotional awareness) involved in offering advice that will be accepted in a constructive spirit, and not seen as an attack.
After all, we ALL write bad code sometimes. A bit of code might seem like a good idea at the time, but could just be overly "clever" upon later inspection. A good review comment that does not point fingers seems like it would fall under the "empathy" umbrella.
Second, the most valuable skill a programmer can have isn't technical, but rater social: empathy. The best programmers I've seen have it and the worst completely lack it.
+10
This is missed by 99% of articles and lists. And most programmers never stop to step on someone else's shoes.
I don’t think that social skills and technical ability are at all related. I’ve seen people with great social skills produce great code, and others produce a tangled mess. And I’ve had to deal with people with terrible social skills who produce great code.
One thing you don’t see often in the workplace are people who lack both social and technical skills.
As an addendum perhaps to the Organize and Design Systems section, I'd propose including mise-en-place as it applies to project maintenance and the development environment.
This centers on tooling and documentation, especially the README. I want a README that gets me set up and running as quickly and in as few steps as possible. Recently I needed to test out some stuff one of my teams was working on. It was a somewhat complex Wordpress project. I was able to get set up using our documentation, but a couple key steps were missing making it error-prone and unnecessarily aggravating.
Anthony Bourdain explains it as only he can:
The universe is in order when your station is set up the way you like it: you know where to find everything with your eyes closed, everything you need during the course of the shift is at the ready at arm’s reach, your defenses are deployed. If you let your mise-en-place run down, get dirty and disorganized, you’ll quickly find yourself spinning in place and calling for backup. I worked with a chef who used to step behind the line to a dirty cook’s station in the middle of a rush to explain why the offending cook was falling behind. He’d press his palm down on the cutting board, which was littered with peppercorns, spattered sauce, bits of parsley, bread crumbs and the usual flotsam and jetsam that accumulates quickly on a station if not constantly wiped away with a moist side towel. “You see this?” he’d inquire, raising his palm so that the cook could see the bits of dirt and scraps sticking to his chef’s palm. “That’s what the inside of your head looks like now.”
Inexperienced engineers sometimes find themselves in teams which don’t appreciate it. Because confrontation can be nausea-inducing, they sometimes don’t endure the discomfort to insist on it.
———
When a customer walks into a restaurant, does he ask about the temperature of the fridge the chicken is stored in? Does he ask if the kitchen is clean and organized? No. Thats the chef’s job to insist on. But the customer does care if his food is late or laden with salmonella.
Likewise, its an engineer’s job to care if she has automated tests and well-structured code.
I'd argue that missing on mise en place is symptom of a team leadership failure, as well. Allowing excessive tribal knowledge vs. repeatable process (docs, dev tools, tests, well organized code, etc.) is an organizational risk. There's the efficiency loss side, but also the possibility that an incapacitated team member becomes a critical business loss – the team becomes unable to meet goals or worst case, to ship at all. Not empowering new team members to efficiently onboard is just one facet of this. With new hires, there are also the power issues that result, particularly blaming new hires for poor onboarding performance.
I "fondly" recall one early job in my career starting with the promoted-from-the-ranks dev lead filling a whiteboard with boxes and acronyms... an overwhelming brain-dump to a newcomer that took hours of time spread over days. By the time I'd sorted out what we really did, months later, I could explain the whole thing to a new hire in fifteen minutes. One easily understood diagram, pointers to the two actually-important directories in our codebase, and some context – and they would be off to the races. Funny enough, I met a number of other people at that gig that thought of their work as "irreducible". One was, to use the recent meme, a "10x engineer" for whom the company maintained a rotating roster[1] of tech writers to follow around everywhere and try in vain to record what the heck they were doing.
It would also help if folks read READMEs. I write a lot of them for my projects at work. Most are detailed but also have a quick setup section in the beginning. Unfortunately people still don’t read them and if they do they miss steps specifically spelled out within markdown formatted code blocks.
Most programmers do not follow the Golden Rule, which is to write code you'd like to maintain with minimal training. It's a principle, but there are various skills involved in doing it successfully, including writing, automation, design, seeking quality peer review, and a few other things.
Similarly, writing code that can be deleted is an important skill.
Using "good design" and "knowing your language" are fairly nebulous and somewhat tautological goals out of context. What is good design? Design that works well, I suppose?
Most code is actually fairly easy to change in the future. Just slap another "if (isLeapDay(today)) dailyProfit * 28 / 29" wherever will solve the immediate bug. Is this a good idea? Nope. Why is it a bad idea? Well, it's the S in SOLID, probably, but the real reason is that someone would be surprised and chagrined to discover that design choice the hard way. Hence the Golden Rule.
Writing code that is well designed but not over-designed is a great skill.
It is in every engineer to write the gold plated car, as it is in marketing and sales to always need the future tomorrow to gain competitive edge.
The number of times I wrote beautiful code are quite numerous, the number of times it is still not used to its potential as well. In the end I spent too much time over engineering for a disastrous moment or extension that never happened, or was never requested by a customer.
I have written godforsaken shortcuts that are used so frequently it made me feel proud and ashamed at the same time.
Now, I have come to believe that knowing when to stop is the greatest skill of all.
There really needs to be a blog post about this. (I'm sure there have been, but I feel like this isn't talked about enough.) A good percentage of HN readers probably already know most of the advice about bad design, but once you're at that more experienced level, you run into the inverse problem of knowing too much for your own good and wasting cycles over-designing and over-engineering.
I've definitely been guilty of this, both at the level of high-level system/project/solution design, and at the level of code design and code abstractions. I've blown a ton of time and effort over-engineering things which never end up getting used or looked at at all years later, or even just to make things look nicer despite no one else ever using, reading, or modifying my code other than me.
It can sometimes be hard to really accept YAGNI and be able to just move on even if the code isn't quite as elegant or DRY or abstracted as you might have preferred. When you're creating abstractions upon abstractions, you can lose sight of the original goals.
I'm still learning to know when to stop, but I'm getting better.
While I applaud this and would love this rule to be in production, it tends to go against (the majority of) marketing's golden rule of, "I need this done in an unreasonable amount of time with unreasonable requests on functionality" and a management structure that tends to only flex to its subordinates instead of other departments, like they're supposed to.... though, I might be jaded =) I have seen a few very good managers/CTO's in my time and have left companies when they were forced out.
I saw it before. Deletion Driven Development is one of the many names. For me a good rule of thumb is: removal of a feature should result in a diff that deletes a bunch of files (classes in case of oop) completely, and only single lines in other files: the call sites to that feature.
Most programmers work in passes, and don't write everything in one shot. But a common mistake I see is not doing enough passes still. Programmers jump on making polished commits they can show off to their peers.
Instead, what should be use more often is what I would call "postit commits". Simple strokes of code that are certainly not final (if any code can be final) but achieve a purpose. Their postit nature makes it very easy to change. Those commits still need to point in the right directions though because they may stay here for a while (think 15 years). As long as they aren't hurting the customer or the codebase (like a supposedly-temporary hack, even though those are sometimes required), then it's all fine, a program is never finished anyway.
Working with more passes allows you to think more at every step and shape a solution that's more efficient. For example, take a piece of code that's too slow for the requirements and for obvious reasons. Don't necessarily jump on optimising it right away. You may find later that you will finally get the whole subsystem in which that piece of code is included better by using another more powerful idea. And when you come up with that new idea, the only thing that will stand in your way is "postit commits". You can change things now because you're not facing polished ones. You can change things now, not in 10 years when you find out every one of your competitors has finally implemented that idea, in which case you would take the cost of a full rewrite.
This is essentially how you do things well from scratch (and by extension, how you do anything well with code). Keep postits as long as you can, because it's a better strategic position. Only harden a solution when you can't give it more time or because it just hardened itself with cool ideas. At the end of the day, you will win time, if you worry about that. You will crush your competitors even. They will have 3 times more code with bad solutions, you will have 3 times less code with all the super cool stuff and nice subtleties (it doesn't always play out like that, but often enough).
This forms part of what Alan Kay calls “late binding” [see link below] and describes as part of what makes Lisp and Smalltalk great, which is something of a lost art today, mainly because most contemporary programming languages (the usual suspects in the statically-typed camp but also languages one would not expect, Python / Javascript) go out of their way to de-emphasize it. I feel that Perl was the last, massively popular language that promoted late binding.
> Programmers who only work on small temporary
> projects (like an agency) may get by without
> ever improving how to design programs.
Amen to this. We recently ended our engagement with a very well-known Ruby consulting shop for exactly this reason.
Their engineers were very smart and wrote very pretty code.
However it was not suitable for the real world once even a little bit of scaling was required, and this was an app that needed to store and move a fair bit of data as a Day 1 requirement.
The real tragedy is that they were fairly arrogant about it. They didn't know what they didn't know. It's OK to not know how to build things at scale.... as long as you know that's not one of your core competencies. I don't know how to fly a plane, or create a design system, or write assembly code. That's OK, because I know my limitations there.
However, these folks were arrogant and dismissive about scaling concerns.
Well, they were dismissed as a result of their dismissiveness.
Which is a shame, because they did have some talent there.
This is the problem I've got at my current job. While I try my best to write code in a way that it'd work many years ahead, the lack of scale requirements and relatively freedom I've got on my own decisions are double edge sword most of the time. Would love to work in a large shop with more senior people than am.
Both kinds of experience are so valuable. "Consulting shop" experience where you get to play with a lot of stuff, often very cutting edge stuff.
"Long lived legacy app" experience where you really get into the nuts and bolts of engineering some software, but you are often locked into a particular stack and the cutting edge is your enemy and not your friend. Can suck big time when you look for your next job and your skills are 5, 10, whatever years out of date...
Which part? The inability to write code that scales, or the arrogance/ignorance about what they don't know?
The "arrogance/ignorance about what they don't know" part most definitely exists everywhere, including people who work on long-lived legacy apps. Definitely agree with you there, if that's what you mean.
"You may have seen code which misunderstands how expressions work:
if isDelivered and isNotified: isDone = True else: isDone = false;
Instead of:
isDone = isDelivered and isNotified "
I think that's a matter of style, I prefer the isDone = isDelivered and isNotified style myself, and I think the people who write the other way have very poor style but as arrogant as that sounds I don't think I would be so arrogant as to say they don't know how expressions work.
I agree, and that's a fantastic point (about arrogance in particular). Without asking the author of the code, it's impossible to determine why they wrote it as they did. It's easy to make assumptions about who write it, but it's much more difficult for some of us to step outside our own judgmental views long enough to consider that they might have had their reasons. When I was younger, I was certainly guilty of this; e.g. "What kind of idiot wrote this?" It takes a certain degree of mental maturity to recognize you may not have a complete picture of why the code was written the way it was. (Admittedly, it also helped me when I realized the idiot who wrote said code years and years was myself, but that's another story!)
This discussion reminds me of the ternary operators. I personally don't like using them except for very specific applications. Not because I don't know how they work, but because I think their overuse can lead to mistakes and maintenance issues as the conditional complexity grows. For simple statements, sure, but once you get into territory where you see 2 or 3 nested ternary statements with complex conditionals, it's easy to lose your mind (and much harder to follow the author's intent).
I'm with the other poster (humanrebar) too, in that one should strive toward writing maintainable code whenever possible. Make it clean and readable. The poor bugger who has to maintain it when you're gone will thank you!
First, it doesn't necessarily imply that someone writing code like this doesn't understand how expressions work. The author is trying to psychologically model people who code in this manner. I could similarly claim that the else there is unnecessary since the boolean is false by default. If it's a language that doesn't require variables to be declared first, I could claim that the assignment is itself unnecessary. I could then make a further claim that a person who codes like this doesn't understand expressions.
Second, the problem is taken out of context. What happens next? There'll be an if(else) statement somewhere to determine what happens next, and then the if(else) the author has painstakingly avoided will be back.
In college they taught me that every line of code should do one thing and one thing only. So doing both a test and an assignment on one line would not be prefered over the first example(split over multiple lines).
I don't have a lot of experience with programming so for now I do what I was taught. :)
that every line of code should do one thing and one thing only
Taking that at face value results in something like Asm written in a high-level language: very short lines with not much on each one, and it's a pain to read and understand because you have to scroll two pages to see what could be accomplished in a dozen lines. I've seen code written in that style and it was not easy to work with. (What often goes along with that, "every function 'should do one thing and one thing only'", is even worse when taken to its logical conclusion --- it turns lots of scrolling into lots of jumping around.)
I don't have a lot of experience with programming so for now I do what I was taught.
Reading the code for lots of other successful open-source software will probably tell you far more useful things about how to write code than the "indoctrination" that passes for teaching these days. I'd recommend older codebases; the newer ones tend to unfortunately show the same bad habits due to the reasons above.
The most lacking skill that I tend to see is an inability to think in types, and to design software accordingly. Too many software developers never progress beyond primitives and basic control structures - I call them Int, String, and For Loop Developers.
Second biggest issue I see is failing to incorporate our cognitive shortcomings into code design, assuming that you'll remember these dozens of little details from today forever, and failing to enforce or make explicit one's "today knowledge" in the code.
Let's say, for example, that we need to handle distances in on our code with different units (meters and inches, for example). I've seen code bases that use integers or floating points for this and it's always confusing and error-prone what is the unit. In fact, you could accidentally use some other values (money) as distances.
Instead, if your programming language allows this, you could define a type Distance and make sure that all the code that handles distances only use this Distance type. Everyone is forced to think about distances when maintaining the code, conversions routines are implemented and instantiated in one place etc.
Could you explain the consequences of not progressing beyond "Int, String, and For Loop" development? Are you suggesting that these engineers don't understand or apply Design Patterns [0]?
That would be part of it, but since was talking about inability to think in types I suspect they were taking aim more at things like excessively stringly-typed[0] code.
> Using sleep(), cron jobs, or setTimeout is almost always wrong because it typically means you are waiting for a task to finish and don’t know how long it will take. What if it takes longer than you expect? What if the scheduler gives resources to another program? Will that break your program? It may take a little bit of effort to rig a proper event, but it is always worth it.
While I understand the sentiment of this post, which I feel is mostly correct, it's interesting to see how divergent this statement is from my experience building "modern" microservice architectures, devops, and distributed systems design is from this view point that I used to hold so true. Async background tasks that self-heal and are entirely outside of the serving path? Yes, please.
I initially had the same reaction, but I don't think that's the author's intentions. He's saying don't use sleep() and cron to constantly poll if some asynchronous thing has completed, have a proper event fire at the end and handle that. Don't think that's in conflict with what you like about your systems :-)
Yes, but in the article author also argues that proper definitions are important. In more general case I'd say that expressing ideas in a non-ambiguous manner is important.
1. Understanding how the language works. Additionally understanding how the language infrastructure interfaces with the computer.
2. Anticipating problems. Prefer solid foundations over veneers that appear to get the job done.
3. Organizing and designing systems. Essentially, SOLID.
Two things on this:
First, bad code often results from conflicting goals. Moving goalposts and on time shipping, for example. The result appears to have been written by a poor programmer, when this may not be the case.
Second, the most valuable skill a programmer can have isn't technical, but rater social: empathy. The best programmers I've seen have it and the worst completely lack it.
Lack of empathy leads to poor communication. If programmer can't anticipate or read his/her audience's perspective, there's no way s/he can communicate a complex concept to them. The temptation will be to blame the audience when in fact the failure lies squarely with the programmer doing the speaking or writing.
Lack of empathy also leads to disregard for the needs of users and future maintainers. Systems get built that don't need building, and systems that should be built aren't. Should the two happen to coincide, the system is a nightmare to maintain because the programmer simply didn't care about the people who would need to maintain the contraption.
A lot of the 10x programmer discussion focussed on people who lack empathy. For some reason, it's easy to conflate lack of empathy with technical skill.
I once had this small but terribly written module written by an inexperienced developer who wasn't given the kind of feedback and code review that he should have been given. It was still running in production years after that person had left because it was in a corner of the code base that was basically never touched. What made it interesting to me was that it was badly written at almost every level from the high level separation of concerns to low level coding practices, while still basically getting the job done.
I started giving this module as an exercise during interviews for a certain position, with the framing of "This was written by an beginner developer on your team. What kind of feedback would you give them to help them improve?" This sort of thing was actually a major part of the job, as it was a position that would be a kind of consulting resource for other teams and would involve many code reviews and encouragement of best practices -- basically providing subject matter expertise to full stack, cross-functional teams.
The results were fascinating to me because it acted like a Rorschach test of sorts and told me a lot more about the focus on the interviewee than the code they were criticizing. More junior candidates immediately jumped on the low level issues like the boolean assignment example, naming conventions, or small snippets of code duplication, and spent all their time there. More experienced folks often mentioned the low level issues but spent more time on the higher level problems -- the class should be broken out into two, extending in the most obvious way would be hard because XYZ, this etc. Some of the best candidates would ask for more context on the situation and overall codebase.
It also helped weed out the jerks who, despite the prompt, decided that the exercise was an opportunity to show off and insult the original author (who was of course anonymous), venting about how stupid something or other was or using it as a springboard to attack their current co-workers. Everyone starts somewhere. It's fine to wince a little at something that's poorly written, but the point is to actually help them improve. The better candidates were there trying to understand what their gaps in understanding were that would cause them to make certain mistakes. The very best candidate was trying to map out a staged plan of more easily digestable things to work on so that they're not overwhelmed all at once -- extrapolating a whole technical mentorship model out of what they could glean from the code review.
i don’t suppose you could publicly share the module? this is a stellar interview question.
or maybe there’s a library of such code? (yes yes, jquery/openssl or your favorite true but not useful reference comes to mind)
You should say "a programmer needs social skill as well as technical skills to be valuable". If a programmer doesn't have a basic aptitude for programming-like tasks, they won't be able to understand how the language works, anticipate technical problems, or organize and design systems. Until you've worked in a group that's filled with "programmers" who don't have the aptitude for coding, you won't really understand this. The social skill must complement the technical aptitude and skills, but is not more important than them. In fact, I'm even suspicious of people who say "the most valuable skill a programmer can have isn't technical, but rather social" because they often turn out to be aptitudinally-challenged programmers themselves.
In fact, I'm even suspicious of people who say "the most valuable skill a programmer can have isn't technical, but rather social" because they often turn out to be aptitudinally-challenged programmers themselves.
In my experience the programmers who are saying that are usually engineering leadership. If you believe the endgame is becoming engineering leadership, then it's absolutely true that soft skills become more important.
While I don't agree that "social skills" are the most valuable skill for a programmer, I do sincerely think it is the most common reason why competent programmers hit an invisible ceiling in their careers. I've seen plenty of programmers who are technically talented and hardworking, but who get stuck in their careers at the junior end of "senior" because nobody wants to work with them no matter how right they are. If person A is right 90% of the time but nobody wants to deal with them, and person B is right 80% of the time and people are willing to listen, I would rather keep B over A because those junior developers who are running at 60% will turn into 80%-ers under B, but they'll stay 60% under A.
This is a popular claim on HN that I don't think is true. Where does the boundary end? Is it my fault they can't understand my program if they don't know any code at all? What about if they're a Python programmer hired onto a Java project? The point is you should make a good faith effort to write readable code, especially for your team members, but you're a programmer, not a teacher.
>Lack of empathy also leads to disregard for the needs of users and future maintainers.
This I agree with. Its a very underappreciated reason to build empathy as a programmer.
But it’s not. If you want your message to be understood, and the listener is making a good-faith effort but doesn’t get what you’re saying, the onus is on you to communicate in a way the listener understands.
couldn’t agree more!
but the term you’re really looking for is perhaps a strongly developed theory of mind. whereas empathy really is referring to emotional awareness.
the worst and also most annoying programmers i know, to a person, consistently fail to see other points of view. their way is the right way, period. they tend to actually be smart, and right about very many things in a small problem domain. i dare say their raw intelligence is a double edged sword.
In some cases, it might be better to ask them about reasoning around a particular bit of code than to offer alternatives right away. In others, a good idea or anecdote about something you found useful in that spot, might be better received.
In my experience, there is a good amount of empathy (or emotional awareness) involved in offering advice that will be accepted in a constructive spirit, and not seen as an attack.
After all, we ALL write bad code sometimes. A bit of code might seem like a good idea at the time, but could just be overly "clever" upon later inspection. A good review comment that does not point fingers seems like it would fall under the "empathy" umbrella.
+10
This is missed by 99% of articles and lists. And most programmers never stop to step on someone else's shoes.
One thing you don’t see often in the workplace are people who lack both social and technical skills.
This centers on tooling and documentation, especially the README. I want a README that gets me set up and running as quickly and in as few steps as possible. Recently I needed to test out some stuff one of my teams was working on. It was a somewhat complex Wordpress project. I was able to get set up using our documentation, but a couple key steps were missing making it error-prone and unnecessarily aggravating.
Anthony Bourdain explains it as only he can:
The universe is in order when your station is set up the way you like it: you know where to find everything with your eyes closed, everything you need during the course of the shift is at the ready at arm’s reach, your defenses are deployed. If you let your mise-en-place run down, get dirty and disorganized, you’ll quickly find yourself spinning in place and calling for backup. I worked with a chef who used to step behind the line to a dirty cook’s station in the middle of a rush to explain why the offending cook was falling behind. He’d press his palm down on the cutting board, which was littered with peppercorns, spattered sauce, bits of parsley, bread crumbs and the usual flotsam and jetsam that accumulates quickly on a station if not constantly wiped away with a moist side towel. “You see this?” he’d inquire, raising his palm so that the cook could see the bits of dirt and scraps sticking to his chef’s palm. “That’s what the inside of your head looks like now.”
https://books.google.com/books?id=XAsRYpsX9dEC&lpg=PA65&ots=...
Inexperienced engineers sometimes find themselves in teams which don’t appreciate it. Because confrontation can be nausea-inducing, they sometimes don’t endure the discomfort to insist on it.
———
When a customer walks into a restaurant, does he ask about the temperature of the fridge the chicken is stored in? Does he ask if the kitchen is clean and organized? No. Thats the chef’s job to insist on. But the customer does care if his food is late or laden with salmonella.
Likewise, its an engineer’s job to care if she has automated tests and well-structured code.
I "fondly" recall one early job in my career starting with the promoted-from-the-ranks dev lead filling a whiteboard with boxes and acronyms... an overwhelming brain-dump to a newcomer that took hours of time spread over days. By the time I'd sorted out what we really did, months later, I could explain the whole thing to a new hire in fifteen minutes. One easily understood diagram, pointers to the two actually-important directories in our codebase, and some context – and they would be off to the races. Funny enough, I met a number of other people at that gig that thought of their work as "irreducible". One was, to use the recent meme, a "10x engineer" for whom the company maintained a rotating roster[1] of tech writers to follow around everywhere and try in vain to record what the heck they were doing.
[1] "rotating" as in "hired, then fled screaming"
Similarly, writing code that can be deleted is an important skill.
Using "good design" and "knowing your language" are fairly nebulous and somewhat tautological goals out of context. What is good design? Design that works well, I suppose?
Most code is actually fairly easy to change in the future. Just slap another "if (isLeapDay(today)) dailyProfit * 28 / 29" wherever will solve the immediate bug. Is this a good idea? Nope. Why is it a bad idea? Well, it's the S in SOLID, probably, but the real reason is that someone would be surprised and chagrined to discover that design choice the hard way. Hence the Golden Rule.
It is in every engineer to write the gold plated car, as it is in marketing and sales to always need the future tomorrow to gain competitive edge.
The number of times I wrote beautiful code are quite numerous, the number of times it is still not used to its potential as well. In the end I spent too much time over engineering for a disastrous moment or extension that never happened, or was never requested by a customer.
I have written godforsaken shortcuts that are used so frequently it made me feel proud and ashamed at the same time.
Now, I have come to believe that knowing when to stop is the greatest skill of all.
I've definitely been guilty of this, both at the level of high-level system/project/solution design, and at the level of code design and code abstractions. I've blown a ton of time and effort over-engineering things which never end up getting used or looked at at all years later, or even just to make things look nicer despite no one else ever using, reading, or modifying my code other than me.
It can sometimes be hard to really accept YAGNI and be able to just move on even if the code isn't quite as elegant or DRY or abstracted as you might have preferred. When you're creating abstractions upon abstractions, you can lose sight of the original goals.
I'm still learning to know when to stop, but I'm getting better.
Deleted Comment
Are you saying "I can easily delete this code from the project" is a metric for modularity? That's really interesting, is it your own thought?
Deleted Comment
Instead, what should be use more often is what I would call "postit commits". Simple strokes of code that are certainly not final (if any code can be final) but achieve a purpose. Their postit nature makes it very easy to change. Those commits still need to point in the right directions though because they may stay here for a while (think 15 years). As long as they aren't hurting the customer or the codebase (like a supposedly-temporary hack, even though those are sometimes required), then it's all fine, a program is never finished anyway.
Working with more passes allows you to think more at every step and shape a solution that's more efficient. For example, take a piece of code that's too slow for the requirements and for obvious reasons. Don't necessarily jump on optimising it right away. You may find later that you will finally get the whole subsystem in which that piece of code is included better by using another more powerful idea. And when you come up with that new idea, the only thing that will stand in your way is "postit commits". You can change things now because you're not facing polished ones. You can change things now, not in 10 years when you find out every one of your competitors has finally implemented that idea, in which case you would take the cost of a full rewrite.
This is essentially how you do things well from scratch (and by extension, how you do anything well with code). Keep postits as long as you can, because it's a better strategic position. Only harden a solution when you can't give it more time or because it just hardened itself with cool ideas. At the end of the day, you will win time, if you worry about that. You will crush your competitors even. They will have 3 times more code with bad solutions, you will have 3 times less code with all the super cool stuff and nice subtleties (it doesn't always play out like that, but often enough).
https://ovid.github.io/articles/alan-kay-and-oo-programming....
Their engineers were very smart and wrote very pretty code.
However it was not suitable for the real world once even a little bit of scaling was required, and this was an app that needed to store and move a fair bit of data as a Day 1 requirement.
The real tragedy is that they were fairly arrogant about it. They didn't know what they didn't know. It's OK to not know how to build things at scale.... as long as you know that's not one of your core competencies. I don't know how to fly a plane, or create a design system, or write assembly code. That's OK, because I know my limitations there.
However, these folks were arrogant and dismissive about scaling concerns.
Well, they were dismissed as a result of their dismissiveness.
Which is a shame, because they did have some talent there.
"Long lived legacy app" experience where you really get into the nuts and bolts of engineering some software, but you are often locked into a particular stack and the cutting edge is your enemy and not your friend. Can suck big time when you look for your next job and your skills are 5, 10, whatever years out of date...
The "arrogance/ignorance about what they don't know" part most definitely exists everywhere, including people who work on long-lived legacy apps. Definitely agree with you there, if that's what you mean.
"You may have seen code which misunderstands how expressions work:
if isDelivered and isNotified: isDone = True else: isDone = false;
Instead of:
isDone = isDelivered and isNotified "
I think that's a matter of style, I prefer the isDone = isDelivered and isNotified style myself, and I think the people who write the other way have very poor style but as arrogant as that sounds I don't think I would be so arrogant as to say they don't know how expressions work.
This discussion reminds me of the ternary operators. I personally don't like using them except for very specific applications. Not because I don't know how they work, but because I think their overuse can lead to mistakes and maintenance issues as the conditional complexity grows. For simple statements, sure, but once you get into territory where you see 2 or 3 nested ternary statements with complex conditionals, it's easy to lose your mind (and much harder to follow the author's intent).
I'm with the other poster (humanrebar) too, in that one should strive toward writing maintainable code whenever possible. Make it clean and readable. The poor bugger who has to maintain it when you're gone will thank you!
First, it doesn't necessarily imply that someone writing code like this doesn't understand how expressions work. The author is trying to psychologically model people who code in this manner. I could similarly claim that the else there is unnecessary since the boolean is false by default. If it's a language that doesn't require variables to be declared first, I could claim that the assignment is itself unnecessary. I could then make a further claim that a person who codes like this doesn't understand expressions.
Second, the problem is taken out of context. What happens next? There'll be an if(else) statement somewhere to determine what happens next, and then the if(else) the author has painstakingly avoided will be back.
Deleted Comment
Taking that at face value results in something like Asm written in a high-level language: very short lines with not much on each one, and it's a pain to read and understand because you have to scroll two pages to see what could be accomplished in a dozen lines. I've seen code written in that style and it was not easy to work with. (What often goes along with that, "every function 'should do one thing and one thing only'", is even worse when taken to its logical conclusion --- it turns lots of scrolling into lots of jumping around.)
I don't have a lot of experience with programming so for now I do what I was taught.
Reading the code for lots of other successful open-source software will probably tell you far more useful things about how to write code than the "indoctrination" that passes for teaching these days. I'd recommend older codebases; the newer ones tend to unfortunately show the same bad habits due to the reasons above.
Second biggest issue I see is failing to incorporate our cognitive shortcomings into code design, assuming that you'll remember these dozens of little details from today forever, and failing to enforce or make explicit one's "today knowledge" in the code.
https://refactoring.guru/smells/primitive-obsession
Let's say, for example, that we need to handle distances in on our code with different units (meters and inches, for example). I've seen code bases that use integers or floating points for this and it's always confusing and error-prone what is the unit. In fact, you could accidentally use some other values (money) as distances.
Instead, if your programming language allows this, you could define a type Distance and make sure that all the code that handles distances only use this Distance type. Everyone is forced to think about distances when maintaining the code, conversions routines are implemented and instantiated in one place etc.
parent, student, address
While the unskilled would:
parentfirstname, parentlastname, parentaddress1, .... studentpostcode
[0]: https://en.wikipedia.org/wiki/Design_Patterns
[0] https://devcards.io/stringly-typed
While I understand the sentiment of this post, which I feel is mostly correct, it's interesting to see how divergent this statement is from my experience building "modern" microservice architectures, devops, and distributed systems design is from this view point that I used to hold so true. Async background tasks that self-heal and are entirely outside of the serving path? Yes, please.