[HN Gopher] Developer Philosophy
___________________________________________________________________
Developer Philosophy
Author : todsacerdoti
Score : 140 points
Date : 2025-02-03 17:00 UTC (6 hours ago)
(HTM) web link (qntm.org)
(TXT) w3m dump (qntm.org)
| robwwilliams wrote:
| Great hard-won insight! Looking forward to many HN comments on
| this thread.
| AnimalMuppet wrote:
| Well, _there 's_ a gauntlet being thrown down if I ever saw
| one.
|
| For me? Maybe something like:
|
| 1. All rules have exceptions - have places that _should_ be
| exceptions. Rigidly enforcing a rule may be better than having
| no rule, but _thoughtfully_ following the rule (almost all the
| time) is even better. Know your rules, know _why_ they 're the
| rules, and know when it might be reasonable to make an
| exception. (Maybe this says that "rules" are really more like
| "guidelines".)
|
| Rules often come in opposite pairs. I think of it like this: In
| Zion National Park, there's a hike called "Angel's Landing".
| You wind up going up this ridge. On one side is a 1000-foot
| drop-off. On the other side is a 500 foot drop-off. The ridge
| isn't all that wide, either. If you look at one cliff, and you
| think "I need to be careful not to fall off of that cliff", and
| you back too far away from it, then you fall off of the _other_
| cliff.
|
| I think software engineering can be like that. There is more
| than one mistake that you could make. Don't be so busy avoiding
| one mistake that you make the opposite mistake. This takes
| thoughtful understanding, not just blindly following rules.
|
| 2. In general, don't repeat yourself. Early in my career, a
| coworker and I learned to ask ourselves, "Did you fix it
| _everyplace_? " It's even better if there's only one place.
|
| But... It is common that things start out the same, and then
| become slightly different (and it gets covered with an "if"),
| and then become more different (and now we have several "if"s),
| and then become even more different. Eventually it can become
| better to decide that these are actually different things, and
| split them. Knowing when to do so is an art rather than a
| science, but it's important.
|
| 3. The most general problem cannot be solved. The trick is to
| do something simple enough that you can actually finish it, but
| hard enough that it's actually worth doing. You cannot address
| this just by changing the lines of code you write; the problem
| is at the specification level (though it can affect the
| specification of a module or a function, not just a project).
|
| 4. Code that is "close to perfect", delivered now, may well be
| better than code that is absolutely perfect, an uncertain
| amount of time in the future. It depends on how many
| imperfections there are, how likely they are to be hit, and how
| damaging they are when they are hit. Code that is close to
| perfect may be perfectly usable to many people; code that
| hasn't shipped yet is currently usable to nobody. (Note well:
| This is _not_ an excuse for sloppiness! It is an excuse for not
| going completely hog-wild on perfectionism.)
|
| 5. You've got a perfect design? Great. As part of delivering
| the design, deliver an explanation/roadmap/tour guide for it.
| (If it were an electrical design, it might be called a "theory
| of operation".) Consider checking it in to the version control
| system, right beside the code - like, in the top level
| directory.
|
| 6. All these things take maintenance. You have to revisit your
| "don't repeat yourself" decisions. You have to revisit what is
| within scope and out of scope. You have to revisit which bugs
| are tolerable and which are not. You have to update your design
| documents. Take the time and do the work. If you don't, your
| program will slowly become more and more brittle.
| skrebbel wrote:
| Seeing the domain name I really hoped this was some way-out there
| SF story about computers philosophising about their developers or
| sth.
| parpfish wrote:
| the last three entries are great and need to be drilled into
| folks head. too much of CS training (and leet-code driven
| interviewing) encourages people to get clever. but reading
| somebody elses clever code sucks.
|
| write code that's meant to be easily read and understood. that's
| not _just_ about algorithms and code comments -- variables
| /functions named descriptively, formatting is consistent, things
| don't get too nested, design things to be modular in a way that
| lets you ignore irrelevant sources of complexity, etc
| zikzak wrote:
| Kernighan's Law - Debugging is twice as hard as writing the
| code in the first place. Therefore, if you write the code as
| cleverly as possible, you are, by definition, not smart enough
| to debug it.
| bilekas wrote:
| I feel as an outlier to this I need to make a comment..
| Debugging (with source) to me at least, it's so much more
| easier as you have all of the stack with you along the
| chain.. It's very rare, not impossible though, to find crazy
| behavior during correct debugging.. This law is new to me
| though.
| marcosdumay wrote:
| That, of course, is only valid if you are using your
| cleverness to optimize for something that isn't readability.
| cies wrote:
| "Do not write today, that what you cannot debug tomorrow."
| LegionMammal978 wrote:
| I'd be a bit wary of taking 'simplicity' as a goal. Some people
| read that and think to write shorter, cleverer code instead of
| longer, more straightforward code which might have a few
| redundancies. (E.g., people often praise FP languages and Lisp-
| like languages for their very flexible control flow, but adding
| custom abstractions can result in shorter code that is
| difficult for newcomers to understand.)
|
| On the other hand, too much modularity and factored-out code
| can also obscure the behavior of a program, even if each module
| has a well-defined role and satisfies its interface. (E.g., big
| Java programs can have hundreds of classes with small method
| bodies and lots of calls to other classes and interfaces. If
| you see an interface call, but the object came from somewhere
| several classes away, then good luck figuring out which
| implementation gets called.)
|
| I'd say that the ultimate moral is "Keep the flow of logic and
| data relatively linear (or at least, no more complex than it
| needs to be to solve the problem). Avoid dicing it up between a
| dozen different spots, or performing crazy stunts with it, so
| that only an expert can understand what's going on. And just
| because some logical constructs (like dynamic dispatch) are
| unwritten doesn't mean they don't create mental load."
| bilekas wrote:
| > but adding custom abstractions can result in shorter code
| that is difficult for newcomers to understand
|
| I've worked at places where the lead would abstract
| everythiNg possible, it made tracing the flow not just
| difficult but almost intentionally obfuscated. When calling
| him up on it he would sing the principles and say it's the
| source of robust code. I'm sure out 100 customers appreciated
| that.
|
| I do appreciate your comment on keeping the flow right, I
| would add to that I guess by making sure your domains and
| boundaries are well established and respected.. mistakes will
| always happen, but if they're "gated" by domains, the person
| who fixes it will definitely buy you a beer/coffee.
| winwang wrote:
| I think it's fine if code is difficult for newcomers to
| understand (of course, to a point). Most programmers are
| taught in C-like languages and paradigms. Using FP (ML-like)
| languages is already "difficult to understand".
|
| The question then becomes: how large is the disconnect
| between the "theory" in the mind of the newcomer(s) vs. the
| "theory" they need to be useful in the codebase -- and is
| this gap worth it?
|
| For example, programming with explicit effects (i.e. `IO`) or
| even just type-safe Futures. There's not too much difficulty
| with simply getting started, and it builds up a general
| theory of effects in the newcomer, which would presumably be
| useful in many contexts of the codebase even outside of async
| effects, e.g. error-handling with `Either`.
| wry_discontent wrote:
| Everything is difficult for newcomers to understand.
| Newcomers should be helped to learn new things. Every
| programming language will be incomprehensible to non-
| programmers. That's not the target audience.
| bilekas wrote:
| A great rule of thumb I found useful while learning under great
| tutorship (way back when) was, look at your check-in, (svn at
| the time) if you think you will remember it in 5 months in less
| than 15 mins then it's okay.. But still have someone put eyes
| on it before clicking. SVN made us careful maybe..
| boogieknite wrote:
| i inherited spaghetti code written by a geography phd and some
| fresh out of coding boot camp flunkies. i really enjoy finding
| "clever" code, even code they only think is clever. its
| entertaining! might as well be entertained at work.
|
| if its legit clever code, just add a link to the source for the
| theory behind it and that's enough for me
| gchamonlive wrote:
| I think any attempt to distil hard earned experience and domain
| awareness will eventually devolve into misplaced generalisms.
|
| This isn't to say that the article isn't good. It's well written
| and the teachings are valuable.
|
| This comment is for the inexperienced dev that arrives at theses
| posts looking for ideological prescriptions: don't.
|
| Give yourself time. Let yourself fail and learn from your
| mistakes. Keep reading the masters work like Clean Code, SICP,
| Working effectively with legacy code, software architecture the
| hard parts, mythical man month etc... but don't let anyone
| prescribe to you how to do your job.
|
| Developing is ultimately managing an unmanageable and ever
| evolving complexity and making it work. Developing is art and
| experience. Developing requires great peace of mind.
| spit2wind wrote:
| The author has a few words about Clean Code
| https://qntm.org/clean
|
| A better recommendation is "A Philosophy of Software Design" by
| Osterhaut.
| parpfish wrote:
| generalisms are fine as long as you don't try to turn it into a
| hard and fast rule.
|
| generalisms contain knowledge that _generally applies_ , but i
| think it's well understood that there will always be times
| where it doesn't apply.
| bigiain wrote:
| > Let yourself fail and learn from your mistakes.
|
| In my experience, trying and failing is the very best
| teaching/learning method.
|
| If you're observant and lucky during your career, you'll gain
| the skill of learning from other people's failures as well as
| your own.
|
| (And from a management and mentoring perspective, it's
| important to assign tasks/projects to junior and mid level devs
| that have real risks of failure while shielding those devs from
| blame or blowback if/when they fail. All the very best devs
| I've worked with in my 30+ years in this game have a deep oral
| history of war stories they can dig into when explaining why a
| particular approach might not be as good as it seems on the
| surface.)
| Kinrany wrote:
| Same qntm that wrote There Is No Antimemetics Division
| datadrivenangel wrote:
| "By the time the ground-up rewrite starts to seem like a good
| idea, avoidable mistakes have already been made. "
|
| This is the wisdom of devops. Do it well, and things will go
| smoothly.
| tra3 wrote:
| Someone below already commented [0]
|
| > I think any attempt to distil hard earned experience and
| domain awareness will eventually devolve into misplaced
| generalisms.
|
| Ground up rewrites are a gamble. Classic Spolksy essay [1]
| about Netscape losing their lead to Internet Explorer is a must
| read.
|
| Briefly:
|
| 1. You think you know how to build the new version, but you
| really don't. Years of improvements of the old version, years
| of bug fixes, years of business knowledge are below the
| surface.
|
| 2. The new version is going to have new bugs.
|
| 3. While you're rebuilding everything from scratch your
| competition is improving their product.
|
| 0: https://news.ycombinator.com/item?id=42921426
|
| 1: https://www.joelonsoftware.com/2000/04/06/things-you-
| should-...
| datadrivenangel wrote:
| All abstractions are leaky, and all pithy sayings have a
| contradictory and equally pithy counter-saying.
|
| True wisdom is knowing which wisdoms to look at and when.
| burningChrome wrote:
| >> You think you know how to build the new version, but you
| really don't. Years of improvements of the old version, years
| of bug fixes, years of business knowledge are below the
| surface.
|
| This point has always baffled me. The old adage of "if it
| ain't broke, don't fix it." but then in the past decades of
| everybody jumping on the JS frameworks and whole heartedly
| believing by moving to "X" framework, they can eliminate all
| the issues you have or had with the older version.
|
| In my own experience, it never goes this way. Oh sure, do you
| want to be working in legacy code that's 10 plus years old?
| Probably not, but the idea that every new shiny thing has all
| the answers to all the issues you had before is a sure fire
| way to get a lot of people fired for overpromising and
| underdelivering.
| zurfer wrote:
| "I apologise for writing such a long letter, but I didn't have
| time to write a short one."The quote, " is generally credited to
| Blaise Pascal, a French mathematician and philosopher. In his
| work "Lettres Provinciales" (Provincial Letters), published in
| 1657, Pascal wrote in French: "Je n'ai fait celle-ci plus longue
| que parce que je n'ai pas eu le loisir de la faire plus courte,"
| which translates to, "I have made this letter longer than usual
| because I lack the time to make it shorter."
| omoikane wrote:
| These are all good ideas, particularly the last 5 which are
| mostly technical. The first 2 are often influenced by things
| beyond developers' control. For example, developers might be
| pushed on a schedule that encourages accumulation of technical
| debt, leading to the inevitable bug bankruptcy and ground-up
| rewrite.
|
| I think every developer should strive to do the right thing, and
| also be flexible when the right outcome didn't happen.
| wduquette wrote:
| "Nobody cares about the golden path. Edge cases are our entire
| job."
|
| This is an obvious exaggeration; if you ignore the golden path,
| the code doesn't solve the problem it's meant to solve. But yes;
| writing reliable code is all about the edge cases. Eliminate them
| if you can; code for them if you can't.
| AnimalMuppet wrote:
| Back in the 1970s, when I was just a high school kid reading
| computer magazines, I saw references to a study (I believe by
| IBM), that said in production code, that 70 or 80% of the lines
| of code was error handling; only 20% or 30% was the "golden
| path". I'm not sure I saw an actual reference, even then, and I
| certainly cannot give a reference now.
|
| Does anybody know the study in question? (I have never seen
| another study on the topic. Does anyone else know of one?)
|
| This was almost certainly either done in assembly or PL/I or
| Algol or something. Do more modern languages change it?
| Exceptions? Dual-track programming (options or Maybes)?
|
| Regardless of exact numbers, yes, error cases are something you
| have to think about _all the time_.
| atq2119 wrote:
| Maybe this applies to Go code?
|
| Snark aside, I am somebody who is _very_ concerned about edge
| cases, but those ratios seem completely wrong to me for the
| kind of code I write. And perhaps one should say "corner
| cases" instead of "error cases". Corner cases aren't
| necessarily errors. What I find is that a good algorithm that
| is properly "in tune" with the problem space will often
| implicitly handle corner cases correctly. While an algorithm
| that was hacked together by somebody who is "coding to the
| test" without really understanding the problem space tends to
| not handle corner cases, and then the developer tries to
| handle them by adding if-statements to patch their handling.
|
| In the end, devoting 70% or 80% of _thinking time_ to corner
| cases seems entirely plausible to me. 70% or 80% of _lines of
| code_ dedicated to corner cases may be a smell.
| wduquette wrote:
| Depends on the kind of code. If you're automating a
| process, or handling large quantities of user input, for
| example, problem cases are everywhere. Or if you're working
| with a complex problem space where things can compose in
| unexpected ways (e.g., a language interpreter).
| hintymad wrote:
| This reminds me of Joel Spolsky's test and true article on
| rewrite: https://www.joelonsoftware.com/2000/04/06/things-you-
| should-...
| neves wrote:
| The author cited this quote:
|
| > he first 90% of the job takes 90% of the time. The last 10% of
| the job takes the other 90% of the time.
|
| When I report my work done I always prefer the ironic version:
|
| > I've already did 90%, now there's just the other 90%.
|
| It is fun, but most importantly, for non developers, it reports a
| reality of our work. To do the simplest case, is almost easy, but
| when you have to factor in taking care of exceptions, errors,
| usability, log, robustness, security etc. there's a lot of
| "unexpected" work.
| mtrovo wrote:
| First time hearing about the 90/50 rule and it's something I've
| seen play out so many times. It's easy to get caught up in just
| getting the code work on a limited case, but true quality comes
| from spending extra time on testing and handling edge cases. It's
| often those overlooked details that can take up more time than we
| expect. This is particularly crucial for junior developers to
| grasp as you need to understand that your task is not done when
| you send your first push to git.
|
| I also agree wholeheartedly with automating best practices.
| Relying on manual reviews for everything is just not scalable.
| Setting up automated tests to enforce format, lints and testable
| code have the side-effect of creating a code base with clear
| expectations and minimal side effects.
| pydry wrote:
| True quality comes from avoiding edge case traps.
|
| Some approaches/feature types create edge case explosions.
|
| For example, I'm often hell bent on the need for avoiding
| bidirectional syncing or writing mini parsers. If there is
| another, simpler way Ill find it.
| tommica wrote:
| This post really verbalized my own similar experiences so much
| better than I ever could have:
|
| - I always think what could go wrong, but of course, it's all
| about the edge cases!
|
| - what the last 10% really consists of.
| csours wrote:
| To me, software development is many things, but the inner loop is
| mainly characterized by two alternating modes: Trying things and
| Learning things.
|
| The biggest hidden assumption I see is that we expect other
| people to be trying and learning things in the same way we do.
|
| Experienced devs will write code to improve their own
| understanding, they will create tests to improve their own
| understanding, they will do research, they will do a lot of
| learning and all of that rarely gets talked about at standup or
| in a pull request. This work never shows up in a planning or
| budget meeting.
|
| I see junior devs getting stuck hard on delivering production
| ready code - which is the WORK PRODUCT that we want; but that is
| not what the actual work of software development looks like. A
| lot of junior devs are hesitant to do throw-away work that does
| not get committed to source control - they feel like someone out
| there knows the answer and they just have to find them. And for a
| long time, that works - they can find someone to provide the
| answer they need, they can find a senior dev who glances at the
| code and fixes it effortlessly.
|
| This whole thing is exacerbated by managers with no or minimal
| dev experience, who also confuse work product and tracked work
| items with the actual work of producing software.
|
| (And if you're wondering who 'junior devs' is, it's me. I'm
| junior devs.)
| armanboyaci wrote:
| I believe your description of software development is highly
| aligned with the ideas of peter naur, programming as theory
| building.
|
| https://pages.cs.wisc.edu/~remzi/Naur.pdf
| digdugdirk wrote:
| I love when this paper pops up, because now I get to
| recommend a relevant episode of a really great, really nerdy
| podcast:
|
| https://futureofcoding.org/episodes/061.html
| throw310822 wrote:
| Surprisingly boring advice from such an imaginative writer.
| settsu wrote:
| The #1 rule in my home is "Be kind" (not to be confused with "be
| nice".)
|
| The #1 rule I _try_ to abide by when coding is "Be empathetic"
| (to others and my future self.)
|
| In practice, this means things like valuing clarity over
| cleverness (unless I can manage to be both!) and documenting
| unless I can really justify not (i.e., is it realistically "self-
| documenting"), but of course also extends to empathy for the user
| --I'm a front-end dev so much of my work is UI.
|
| You may read this and think "duh" but trust me when I say that in
| the 20+ years of doing this professionally, those are very
| clearly not obvious guidelines (even for myself.)
| cies wrote:
| I like the list. I'd add:
|
| * Optimize for readability.
|
| * The cost of a bug is exponentially proportional to the time
| between that it was introduced and the time is was discovered
| (some NIST study): prevent bugs from going to the next phase
| (requirements -> design -> dev't -> staging -> prod).
|
| * Favor FP principles such as: separate data and logic
| (functions); immutability; explicit nulls; prefer pure functions;
| etc. Even in non-FP languages.
|
| * Strong typing disciplines in languages are worth it.
| metadat wrote:
| The (linked) Ratchet is genius! A near perfect mechanism to
| enforce the future you want without undue work in the meantime.
|
| https://qntm.org/ratchet
___________________________________________________________________
(page generated 2025-02-03 23:00 UTC)