[HN Gopher] Holding a Program in One's Head (2007)
       ___________________________________________________________________
        
       Holding a Program in One's Head (2007)
        
       Author : yamrzou
       Score  : 112 points
       Date   : 2024-09-16 08:19 UTC (3 days ago)
        
 (HTM) web link (paulgraham.com)
 (TXT) w3m dump (paulgraham.com)
        
       | nickdrozd wrote:
       | > You never understand other people's code as well as your own.
       | No matter how thoroughly you've read it, you've only read it, not
       | written it.
       | 
       | There is certainly some truth to this. On the other hand, it's
       | possible to become blinded to defects in code you've written
       | yourself. You see what you intended for the code to do rather
       | than what it actually does. Reading someone else's code, it can
       | be easier to see what's really going on, since you just see
       | what's there.
        
         | hinkley wrote:
         | I, for instance, learned years ago to refuse to help people
         | debug promise chains in languages with async-await semantics.
         | Rewrite it and then get back to me if it still doesn't work.
         | They usually transcribe the intent of the chain and not the
         | letter of it, fixing the bug they can't see. And if not the
         | error makes enough sense they can figure it out.
        
         | saghm wrote:
         | I often tell younger engineers that the human brain is the
         | slowest, lowest-memory, and most error-prone runtime for a
         | program. If they're stuck trying to figure out a bug, one of
         | the most effective things they can do is validate their
         | assumptions about what's happening, because there wouldn't be a
         | bug if everything was happening exactly according to
         | expectations.
        
           | wruza wrote:
           | That's why I learned to log literally everything into stdout
           | _unless_ a process is time-sensitive _and_ it's deep
           | production _and_ it passed the mark where bugs and insights
           | occur once a month+ _and_ there's zero chance someone asking
           | me what exactly happenes with X at Y afternoon-ish last
           | Friday.
           | 
           | The obvious exception are recursive number-fiddling algos
           | which would spam gigabytes of output due to big N.
           | 
           | This way I can just read assumptions and see branches taken
           | and what's wrong as if it was written in plain text.
           | 
           | When I see klocs without a single log statement, to me it's
           | readonly and not worth touching. If you're stuck with a bug,
           | log everything and you'll see it right there.
        
             | jimbokun wrote:
             | For large systems the cost of maintaining all of those logs
             | in a searchable system can be prohibitive.
        
               | lanstin wrote:
               | Just reduce the time horizon you keep the logs until you
               | can afford it. Also, as he mentioned, once a system is
               | getting bugs infrequently, you can lower the log level.
               | My standard is to have a log msg for each branch in the
               | code. In C, I would use macros to also have a count of
               | all the fmt strings the log package encountered (so I
               | still got a sort of profile of the logic flows
               | encountered, but not have the sprintf expense), but I
               | haven't figured out an efficient way to do that in Go yet
               | (i.e. not using introspection).
        
           | nfw2 wrote:
           | This is one of the reasons I think that the push towards
           | server-side UI is misguided. It's much easier to walk through
           | the runtime of a program running locally than it is to step
           | through a render that's distributed across a network.
        
             | sodapopcan wrote:
             | You've clearly never used Elixir/Erlang.
        
           | alphazard wrote:
           | > wouldn't be a bug if everything was happening exactly
           | according to expectations
           | 
           | This isn't quite true, especially concerning distributed
           | systems. It's relatively common for a software system to be
           | _broken by design_. It 's not that the developer didn't know
           | how to use the programming language to get the computer to do
           | what they want. It's that what the developer wanted reflects
           | a poor model of the world, a logical inconsistency, or just a
           | behavior which is confusing to users.
        
             | saghm wrote:
             | Keep in mind I said that this is advice I give junior
             | engineers specifically; they shouldn't be the ones
             | responsible for designing distributed systems in the first
             | place. For someone in that part of their career, this
             | advice is meant to help to learn the skills the need to
             | solve the problems they're dealing with, and it's not
             | intended to be universal to all circumstances, just a
             | useful thing to keep i mind.
        
             | monocasa wrote:
             | That sounds distinctly like an expectation that didn't
             | hold.
        
               | Stefan-H wrote:
               | "a poor model of the world, a logical inconsistency, or
               | just a behavior which is confusing to users" I expect
               | when I pull from the queue (but it was designed non-
               | atomically) that I will be guaranteed to only grab the
               | item once and only once, even after a failure. That
               | expectation is wrong, but the developer may have
               | implemented their intent perfectly, they just didn't
               | understand that there are error cases they didn't account
               | for.
        
         | jmkr wrote:
         | There's some idiom that says something like "you don't
         | understand something if you can't explain it." I think this is
         | the real point of code review. To make a case for why your code
         | is valuable. If it's just a blob of 1000 lines of "refactor" or
         | "adding feature." It means nothing. A good commit has some kind
         | of abstract tailored to what work was done.
         | 
         | Then a review becomes something like "the claim was made this
         | function does this, does it look like the function does what it
         | says it does?" If you can understand it in context, then you've
         | added trust and knowledge of how it works.
         | 
         | However it seems to often be the case a review turns into "I
         | like this word better than that word" so back to the explaining
         | it point, it becomes a bit of a self review with the hope it
         | might be helpful to somebody else in the future.
        
           | lanstin wrote:
           | There is a balance there. You can have 1000 trivial commits
           | making it hard to see the fact you just have 10 features, and
           | ten mind-breaking commits making it hard to see what each
           | feature entails. (Then there's the 50 commits "try this"
           | where you are fighting CI or CD and can't test without going
           | thru a git commit/push.)
        
         | xanderlewis wrote:
         | The comparison with mathematics also makes sense here. It's
         | much easier to spot typos in other peoples' work than your own
         | for exactly that reason: when you read back what you wrote, you
         | read back _what you meant to write_ rather than what's actually
         | there.
         | 
         | Open any textbook (even a fourth edition of a famous one,
         | written by an expert) and you'll find countless typos. In fact,
         | in a certain sense, the more expert you are the less suitable
         | you are as a proof reader for such books.
        
           | lanstin wrote:
           | One of my undergrad tutors taught complex analysis with a
           | book she had written, and she offered a reward for any one
           | who found an error. She said the best students never claimed
           | the reward, only the people that had to study each word
           | carefully.
        
             | xanderlewis wrote:
             | I proudly study each word carefully.
        
           | jpc0 wrote:
           | You touched on it but I've experienced the same reading code
           | when I knew what was intended by the code, regardless of who
           | wrote it. I miss obvious but simple bugs because I only read
           | what it is mean to do.
        
         | stonemetal12 wrote:
         | I believe that is the source of "the worst code I have seen is
         | code I wrote six months ago" feeling. It has been long enough
         | that the code has fallen out of your memory, making you less
         | blind to the defects. You can now see it as an outsider would
         | see it.
        
         | noufalibrahim wrote:
         | This is true and it's one of the problems I have with code
         | generators and these days, AI generated code.
        
         | HumblyTossed wrote:
         | I don't think that quote is true in all situations. I have
         | worked with a couple developers long enough their code reads to
         | me as easy as my own.
        
           | ahoka wrote:
           | Sometimes when I do code reviews, I understand other's code
           | better than they do and find bugs they don't see. So yeah.
        
         | iamflimflam1 wrote:
         | Nothing beats the experience of looking at code you wrote a
         | year ago and thinking "who the hell wrote this nonsense"
        
       | corytheboyd wrote:
       | > [...] bottom-up programming, where you write programs in
       | multiple layers, the lower ones acting as programming languages
       | for those above
       | 
       | I like to explain this as "hide the bad parts behind a good API".
       | Anything interesting is going to require "bad parts", which just
       | means the low-level, difficult work. From there, compose up and
       | up until a high level orchestration is achieved. It works so much
       | better than the bad parts being distributed everywhere! That's
       | what you'd also call a "leaky abstraction"
        
         | reddit_clone wrote:
         | This is what I believe as well. Also throw in some Functional
         | Programming (isolating pure functions and side-effecting
         | functions) for extra benefits.
        
           | kevindamm wrote:
           | Both excellent points, and I would add a recommendation for
           | high level organization: to consider the data then the
           | process. If you can draw a graph where every data structure
           | is only connected to a process, and vice versa, and that
           | processes may take multiple inputs but only produce a single
           | output type, it will make holding the entire system in your
           | head a lot easier, even for very scaled-up systems.
           | 
           | Bonus points if you can distinguish between essential state
           | and circumstantial state.
        
         | kmoser wrote:
         | Said another way: push interface up and implementation down.
        
           | corytheboyd wrote:
           | Well said, I'll be taking that :)
        
             | kmoser wrote:
             | I can't take credit for it; I read it in a C Users Journal
             | article back in the 1990s which I haven't been able to find
             | online.
        
         | WillAdams wrote:
         | This seems to be one of the core lessons behind John
         | Ousterhout's _A Philosophy of Software Design_
         | 
         | https://www.goodreads.com/book/show/39996759-a-philosophy-of...
         | 
         | and I find that the mechanism of "Literate Programming":
         | 
         | https://literateprogramming.com/
         | 
         | is a useful one for doing this since it allows one to write
         | about both how the low level details are implements in a
         | function, _and_ how the written function is used in a way which
         | allows the twain to support each other.
        
           | zimpenfish wrote:
           | That needs to be http://literateprogramming.com/ at the
           | moment because their certificate / HTTPS setup is borked.
        
         | nfw2 wrote:
         | I think that many, perhaps even most, engineers incorrectly
         | believe that the main purpose of abstraction in code is simply
         | DRY, as if the goal is to save keystrokes or something.
         | 
         | In my view, the purpose of abstraction is to compress the
         | concepts of your application into digestible and manueverable
         | chunks, and DRY is just a heuristic for beginners to follow to
         | help point to where appropriate abstraction boundaries may be.
         | 
         | I hope the various theories behind what constitutes good code
         | will make their way out of scattered blog posts and into CSE
         | curriculum.
        
           | 4star3star wrote:
           | I think DRY should be supplemented by "Don't make me read it
           | multiple times". Repeat yourself, by all means, if that makes
           | it so that I don't get all twisted up jumping between so many
           | files that I can't keep the main thread straight while I read
           | your code.
        
             | wduquette wrote:
             | Don't repeat yourself...but don't obfuscate the code
             | either.
        
             | jpc0 wrote:
             | Another on this. If you abstract away code that throws or
             | returns an error document that somehow.
             | 
             | The amount of times I've had to dig through 6 levels of
             | abstraction to find what error gets returned in some edge
             | case so I can catch and handle it gave me PTSD and gave me
             | not invented here syndrome.
        
           | jimbokun wrote:
           | Good API is for encapsulating and communicating ideas between
           | other programmers or teams.
           | 
           | DRY is for improving communication with your future self.
        
           | lanstin wrote:
           | New software demands a new vocabulary, and if those new
           | concepts correspond exactly to implemented code, everything
           | becomes very clear and possible to share with new people.
           | 
           | As well, the division of a project into layers where each
           | layer has a manageable amount of concepts, 5-7 for normal
           | layers, becomes much easier for people to learn and use
           | correctly. If I have to keep 12 things in mind while using a
           | layer, it's going to be a lot harder to get correct.
        
           | corytheboyd wrote:
           | DRY is an okay rule at the absolute beginning of your
           | programming career, but it must become obvious why it is too
           | simple for you to advance much further. DRY is most certainly
           | not abstraction.
           | 
           | I actually took a general Software Development course when I
           | was in school that sort of touched on things like Linux,
           | source control, debugging, and other things I now forget-- it
           | was an elective though. It was neat, the teacher even
           | introduced us to Ruby, which was a cool experience for a
           | bunch of dumb kids who thought the whole world ran on Java or
           | C++ :) I liked it so much I went on to implement Ruby-isms in
           | C++ for my other classes, and use those to orchestrate
           | solutions. Completely dumb in retrospect, but I thought it
           | was so cool at the time. And hey I guess that's a great
           | example of learning early on how to "hide the bad parts!"
        
         | joe_the_user wrote:
         | _" Hide the bad parts behind a good API... It works so much
         | better than the bad parts being distributed everywhere!"_
         | 
         | This doesn't work for the "bad things" I know of. All of the
         | low-level bad parts which are truly bad/mucky, are bad because
         | they can't be entirely hidden. They are leaky abstractions and
         | by that fact, they ... leak. They impact every part of the
         | system so they are "distributed everywhere" in the sense that
         | the maintainer of a large program has to consider them
         | everywhere even if they only directly show up in a few places.
         | 
         | Just as an example, programming languages are abstractions over
         | the complex structure of "raw" memory. Pythons hide this
         | abstraction more than for example c but once you reach a
         | certain scale the use of python, you have to consider the
         | details of its use of memory. And that's memory in general,
         | which people work at to make reasonably regular as well as
         | fast.
         | 
         | That's not saying you can't have an API that makes the low-
         | level problems less.
        
       | mingusrude wrote:
       | I once watched a presentation by Dan North where he said that a
       | microservice should never be bigger than your head. What he meant
       | was that all the code for the microservice should fit on your
       | screen and you should be able to put your head against the screen
       | and it should cover the code.
       | 
       | Yes, this was in the microservices-heyday.
        
         | fredrikholm wrote:
         | A quote originally (AFAIK) from the wonderful book 'Practical
         | Common Lisp'.
         | 
         | https://gigamonkeys.com/book/
        
           | jmkr wrote:
           | This is probably a common; lisp/scheme type of thought. Dan
           | Friedman also said something about how he only likes code
           | that he can hold in his head to think about in the shower. I
           | forgot the source, but it's in one of the talks. I think
           | Sussman has also said something similar.
        
         | dkarl wrote:
         | Anything you create in software should be able to fit in
         | someone else's head. I.e., you should be able to think of it as
         | a tractable arrangement of abstractions that let you reason
         | about it in a precise, non-leaky way.
         | 
         | Those abstractions don't just poof into existence after the
         | project is complete, though. You have to design them into the
         | system and communicate them to the people who need them.
         | 
         | The abstractions also need to be precise and non-leaky enough
         | to be useful. One of the most dangerous talents in software is
         | the ability to create the illusion of tractability by using
         | vague language. You can create an absolute mess and then
         | describe it to management in a way that makes it sound well-
         | understood. This is the most lucrative and destructive skill a
         | consultant can have.
        
           | ellis0n wrote:
           | Unfortunately, all the market giants follow this destructive
           | practice to rewriting 95% of all code every five years to
           | multiply added value.
        
       | kuharich wrote:
       | Past comments: http://news.ycombinator.com/item?id=45698,
       | http://news.ycombinator.com/item?id=2988835
        
       | kmoser wrote:
       | "Use succinct languages" is somewhat at odds with "Write
       | rereadable code." There's a point beyond which making your code
       | more succinct makes it more difficult for a human to parse. This
       | can be somewhat mitigated by comments but I'd rather just read
       | more readable code than more succinct code.
        
         | dkarl wrote:
         | Succinct languages don't force you to be succinct. They only
         | allow you to be succinct where it helps.
         | 
         | (I'm sure there are exceptions, but in the set of languages
         | that enable succinctness, the subset that force succinctness is
         | surely small.)
        
         | jmkr wrote:
         | I think this is addressed in the link under that section
         | 
         | https://paulgraham.com/power.html
         | 
         | > I think that the main reason we take the trouble to develop
         | high-level languages is to get leverage, so that we can say
         | (and more importantly, think) in 10 lines of a high-level
         | language what would require 1000 lines of machine language.
         | 
         | ...
         | 
         | > 5. Write rereadable code. All programmers know it's good to
         | write readable code. [...] If you're writing for other people,
         | you may not want to make code too dense. Some parts of a
         | program may be easiest to read if you spread things out [...]
         | Whereas if you're writing code to make it easy to reload into
         | your head, it may be best to go for brevity.
        
         | jimbokun wrote:
         | I completely disagree.
         | 
         | It's possible to write code so succinct that making it more
         | verbose would make it more understandable.
         | 
         | But overly verbose code is far, far more common. And having a
         | naturally succinct language does not stop you from keeping your
         | code verbose. Just gives you more ways to make your code
         | succinct that aren't possible in non-succinct languages.
         | 
         | (Not this is orthogonal to weaker or stronger compile time type
         | systems. Type systems that catch more errors at compile time
         | are very useful. But some strongly compile-time typed languages
         | are still quite succinct.)
        
         | ellis0n wrote:
         | You always have comments. I've always been fascinated by GitHub
         | repositories like "odd-even" where the code is just a few
         | lines, but the README takes up several times more text. I even
         | started a small collection of these fun React modules :)
        
         | ragnese wrote:
         | Sure, but it's all so vacuously ambiguous that it doesn't
         | really matter. I hate advice lists like this because it can
         | essentially be summarized by saying "write good code" and you'd
         | be left with almost exactly as much wisdom.
         | 
         | What does "succinct" mean? Well, it means terse but not too
         | terse. What does "readable" mean? It means I can easily
         | understand it.
         | 
         | How is this helpful?
        
       | rshudson wrote:
       | Take a look at the list of people who read the draft of this
       | post.
       | 
       | > Thanks to Sam Altman, David Greenspan, Aaron Iba, Jessica
       | Livingston, Robert Morris, Peter Norvig, Lisa Randall, Emmett
       | Shear, Sergei Tsarev, and Stephen Wolfram for reading drafts of
       | this.
        
         | akira2501 wrote:
         | People who are famous for running companies and not writing
         | code.
        
           | jimbokun wrote:
           | Robert Morris, Peter Norvig and Stephen Wolfram didn't write
           | code?
           | 
           | (I don't recognize some of the others.)
        
             | akira2501 wrote:
             | Is that what they're famous for or even what they've
             | dedicated most of their time to? From looking at their
             | histories I would not describe them as "coders." Let alone
             | presume that they have anything to offer anyone doing the
             | same in a modern context.
             | 
             | "Keep the whole program in your head?"
             | 
             | Cool advice for small greenfield projects that you can sell
             | to unsophisticated companies and then move on. Interesting
             | that it comes from an investing firm that makes this
             | precise activity it's core business and reviewed by people
             | who are in a position to directly benefit from this.
             | 
             | This is all terrible advice if you want to actually
             | contribute to or work on anything significant in your life.
        
               | kragen wrote:
               | yes, writing code is what all three of them are most
               | famous for. especially writing code for vast, significant
               | projects spanning decades, in a way that contributes to
               | something significant. your criticism could hardly be
               | further off target. you dismiss their knowledge at your
               | peril
        
         | joshdavham wrote:
         | I'm always amazed at the impressive list of people pg gets to
         | review his essays. His recent essay "Founder mode" was no
         | exception.
        
       | norir wrote:
       | I more or less agree with the main thesis although I would point
       | out that typical software development practices in industry make
       | this very difficult. Fred Brooks told us to plan to throw out the
       | first draft. Industry says ship it.
        
         | ellis0n wrote:
         | That is true. Then these drafts travel, fly, and feed you.
         | Don't be surprised by plastic in every micron of space -- it
         | was just a draft. By the way, the first refrigerators without
         | Freon also caused harm, but back then people were only thinking
         | about reliability and didn't have the resources to tackle the
         | full scope of the problems. Now the goals have changed driven
         | by the pursuit of profit
        
       | amelius wrote:
       | It's (mostly) not about the code. It's about the data structures
       | and their relations.
        
       | kulor wrote:
       | I call this program in one's head "suspended comprehension" as it
       | has a degree of transience and fragility that requires effort to
       | resume where you left off.
        
       | snowwlex wrote:
       | > You can magnify the effect of a powerful language by using a
       | style called bottom-up programming where you write programs in
       | multiple layers, the lower ones acting as programming languages
       | for those above. If you do this right, you only have to keep the
       | topmost layer in your head.
       | 
       | And if you do it wrong (overengineering), you would need to learn
       | not just one, but as many programming languages as there are
       | layers...
        
         | snowwlex wrote:
         | That's IMHO what OOP (as understood in Java world) tends to
         | evolve to...
        
       | jimbokun wrote:
       | A good way to keep a program in your head:
       | 
       | Break it up into a few or several smaller programs that interact
       | through clean interfaces. Then you can keep one smaller, simpler
       | program in your head at a time, then integrate them at the end
       | once all the smaller programs are working.
        
         | minkles wrote:
         | Those are called functions.
        
           | Aeglaecia wrote:
           | imagine having the brain to synthesise every function across
           | a codebase , most humans gotta settle for interfaces :p
        
             | minkles wrote:
             | Interfaces are just collections of function prototypes.
        
               | Aeglaecia wrote:
               | and some projects have more interfaces than are memorable
               | by the average human
        
           | jimbokun wrote:
           | Sometimes.
           | 
           | Sometimes it is one or more programs writing to a queue or
           | topic, and other programs reading from that topic.
           | 
           | Or programs writing to and others reading from a Unix pipe.
           | 
           | Or programs talking to each other using HTTP.
           | 
           | Or Erlang processes communicating concurrently on one machine
           | or across a network.
           | 
           | Or different programs sharing one database.
           | 
           | Or many objects communicating by passing messages in a small
           | talk program.
           | 
           | There are many ways to encapsulate programs and have them
           | interact.
        
             | minkles wrote:
             | _> Or programs writing to and others reading from a Unix
             | pipe._
             | 
             | write(message), read() -> message
             | 
             |  _> Or programs talking to each other using HTTP._
             | 
             | request() -> response
             | 
             |  _> Or Erlang processes communicating concurrently on one
             | machine or across a network._
             | 
             | sendMess(message), waitMess() -> message
             | 
             |  _> Or different programs sharing one database._
             | 
             | execute(query) -> response
             | 
             | ...
             | 
             | I'm a mathematician at heart so I'm staying away from
             | category theory as long as possible.
        
             | ellis0n wrote:
             | Totally agree and it depends on the current context of the
             | programmer. For example, in the ACPUL language the program
             | is split into boot images, files, modules, functions and
             | expressions. All of these represent different levels of
             | context encapsulation
        
             | wduquette wrote:
             | Or to put it another way...clean architecture is how you
             | arrange the code so that you don't need to keep ALL of it
             | in your head at once, just the big picture and this bit
             | here.
        
           | jll29 wrote:
           | The UNIX way would be to break things down into actual
           | programs, where each one would be doing one thing well - and
           | in such a way that they'd be useful as building blocks for
           | solving other problems also.
        
             | minkles wrote:
             | The unix way is re-parsing text 5000 times in separate
             | programmes with no consistency or contract between them
             | really.
             | 
             | That's not great.
        
               | jimbokun wrote:
               | Only great enough to be the operating system for the vast
               | majority of computing devices on the planet.
        
               | tonyedgecombe wrote:
               | The world is full of technologies that are ubiquitous but
               | imperfect.
        
               | jimbokun wrote:
               | https://en.wikipedia.org/wiki/Worse_is_better
        
               | Too wrote:
               | In close competition with the well renowned JavaScript.
        
             | Too wrote:
             | This must not be done prematurely. Replacing function calls
             | with processes quickly break "go to definition" and all the
             | other conveniences or guardrails provided by your compiler
             | toolchain.
             | 
             | Unfortunately been dropped into that situation. The system
             | was constantly broken due to missing of malformated
             | arguments. Nobody dared to change anything.
             | 
             | Same applies to prematurely microservicing a monolith. At
             | least there folks seem to be sensible enough to use
             | protobufs or json, instead of loosely typed strings.
        
         | mejutoco wrote:
         | Making as much of the program as possible pure functions and
         | enforcing types works extremely well for this task. I would
         | only add clean _enforced_ interfaces are key.
        
       | ellis0n wrote:
       | A great article that accurately describes the challenges I've
       | faced over the past 12 years while creating the best project for
       | programmers and the various attempts to find work and funding,
       | observing all the madness in the organizations It seems like the
       | best of it was left in 2007, from which we still draw inspiration
       | and knowledge, while since 2008 we've been living in a new world
       | of marketing and wars. The insatiable interests of faceless
       | systems are destroying everything alive in this great science of
       | "programming".
        
       | btown wrote:
       | IMO this is one of the most important skills for a developer to
       | have. In an age of Github Copilot and similar systems, it's both
       | far more viable (because, per OP's #1, you won't get distracted
       | by the "side quests" of implementing utilities you need, when you
       | can just tab-complete to get them) and far more vital (because
       | with that productivity increase comes an increase in the
       | complexity of problems you'll be asked to tackle at any given
       | level of seniority).
       | 
       | My advice on this would be: never be afraid, and even force
       | yourself to, follow the chain of how a certain function is
       | implemented in third-party libraries you are using. Set up your
       | IDE to be able to click into functions, make that muscle memory,
       | and perhaps even have a dedicated project you can bring up for
       | your site-packages or node_modules. Don't just rely on
       | documentation, see how things actually work a few levels deep.
       | You'll gain a deeper understanding of the code you're using, as
       | well as incredible practice for when you need to do this on an
       | existing first-party codebase.
       | 
       | Oh, and if you can, get one or more large 4k monitors, and split
       | your IDE into 4 quadrants! It's certainly possible to hold a
       | codebase in your head on a small laptop screen, but being able to
       | see the code you're working on alongside its dependencies and
       | dependents makes this far easier!
        
         | lanstin wrote:
         | This is one of my standard interview questions, how do you
         | familiarize yourself with a multi-million line code base with
         | partially correct partial documentation (in addition to
         | generated documentation). Looking for interesting tooling, and
         | stepping thru the framework code to see how it all comes
         | together (and enough concrete details to verify the claimed
         | work history).
         | 
         | I'm not sure about the advantage to seeing all the code at once
         | for understanding it. Surely for refactoring or massive
         | editing, but to encode it into your brain, I feel the crucial
         | thing is more abstract than actually seeing the code.
         | 
         | I personally find the large screen is something that's more
         | useful when I am moving between different low-concentration
         | tasks (confluence, slack, teams, emacs, whatever) but for deep
         | problem solving/thinking, just 1 window I can see everything
         | completely with a full-screen emacs is more conducive. I assume
         | other editors than emacs would have this same facility.
         | Extremely rapid answering of different questions about the code
         | via LSP type facilities is more key than seeing a bunch of text
         | at once, so I can follow the flow of my thoughts. Sometimes,
         | when I'm trying to make sure that 2 or 3 functions have the
         | same flow/logic (yeah, haven't found the abstraction to replace
         | them with) I'll want a big side-by-side comparison of 2 or 3
         | places at once.
         | 
         | This ability to follow into third party code you use was one of
         | the initial attractions of Gentoo - you can build all from
         | source, keep source and symbols around, and edit/trace the code
         | for anything on the system. Reading a lot of code I think makes
         | my own code better.
        
         | intelVISA wrote:
         | Any suggestions for a nice 4k 144Hz OLED?
        
       | rswail wrote:
       | I'd add "Focus on the Nouns, not the Verbs", or more prosaically,
       | the data and the changes that occur to data, not the process of
       | changing it.
        
       | PaulHoule wrote:
       | I'll call out                  7. Don't have multiple people
       | editing the same piece of code.         You never understand
       | other people's code as well as your own. No matter        how
       | thoroughly you've read it, you've only read it, not written it.
       | So        if a piece of code is written by multiple authors, none
       | of them understand        it as well as a single author would.
       | 
       | On some level it's true but it is also true that most of the
       | world's code is in some sort of maintenance mode and the original
       | developer is not always available. When I work on code that I
       | think would be difficult to maintain I write a lot of comments to
       | explain invariants that should be followed or anything strange.
       | (Hmm, there are three different kinds of "row" talked about in
       | this source file)
       | 
       | If you have a front end-back end system and you want to do
       | something simple like add a field to a form there's a strong case
       | for a single developer or maybe paired developers to make all the
       | changes to make that change happens as opposed to assign two
       | developers (not paired) to communicate with each other about
       | doing the task, or worse yet, assign two _teams_. You might have
       | had two people build out the front-end and back-end systems but
       | for sustainable maintenance one person should be able to ship a
       | feature.
        
         | ellis0n wrote:
         | I think it was 2007 when the vision of software, developers and
         | resources was still limited. We didn't even have IoT and the
         | first iPhone was seen as a novelty. Now it's clear that this is
         | not the case. I founded a company in 2006 and started focusing
         | on code review because I was interested in code and wanted to
         | be the best. Since the advent of GitHub, I have reviewed
         | thousands of repositories across many languages, worked on
         | architecture, tried to create better code, developed several
         | operating systems, hundreds of projects and dedicated 12 years
         | to programming languages. In the end, I realized that the world
         | is ruled by chaos and the simplest LLM AI is best suited for
         | the task of code functionality.
         | 
         | For example, consider this analogy: when we make a car, we have
         | one wheel and a multitude of parameters that change over time.
         | The wheel is a derivative of these parameters. In car
         | manufacturing, time is virtually unlimited for improving the
         | quality of the wheel. But when we develop software, we always
         | face time constraints and an enormous set of parameters.
         | Thousands of car engineers spend decades improving a single
         | wheel with a limited number of parameters, while a single
         | programmer (or a couple of programmers) have only a short
         | amount of time to release software with a randomly variable
         | number of parameters (a service depends on Auth0 and its
         | parameters change). As a result the programmer cannot be
         | certain that all parameters have been correctly handled. This
         | is why the programming process is similar to learning, and this
         | is where LLMs are the best.
        
           | HeyLaughingBoy wrote:
           | Actually I think it was in 2007 that I was leading my
           | company's first IoT project to get remote access to our
           | medical instruments' operational data.
        
         | wduquette wrote:
         | When I've had to take over maintenance of code that isn't mine,
         | and is poorly commented and documented, which is usually the
         | case, I work through the code and comment it. That eventually
         | leads to refactoring, adding unit tests as needed, and so
         | on...and eventually the code that wasn't mine is now mine.
         | 
         | But there's no time in the schedule for that? Either that's not
         | true (the long way round is usually the shortest way home); or
         | it's time to find another project. And if you're the sort of
         | person who has the skills Graham describes, that shouldn't be
         | hard.
        
           | sfn42 wrote:
           | I do pretty much the same. If any part of the code makes me
           | go "wtf" and sends me down a rabbit hole to figure out why
           | it's like that, I'll typically write a comment about it to
           | save myself and the next guy from that.
           | 
           | However I have one quibble. Almost invariably when I explore
           | other people's code, there's a lot of these "wtf" moments and
           | some times they end with "oooh that makes sense" but honestly
           | most of the time they end with "ugh, this is stupid".
           | 
           | For example i was tasked with factoring out Newtonsoft.Json
           | in favor of System.Text.Json in an Azure function. I looked
           | through the code and it was some of the worst shit I've ever
           | seen. And completely untested, there were two test classes
           | with a few test functions but they literally tested nothing.
           | The only way you could have failed those tests would be by
           | adding a `throw new Exception()` as the first line of the
           | function the test was calling. Seriously. The rest was a for
           | each loop iterating over a list parameter and the test was
           | passing an empty list.
           | 
           | The core of the whole thing was this big chain of functions
           | where over a dozen different parameters were passed down
           | through about two dozen different methods, some weren't even
           | used, some were repeatedly serialized to json, passed as a
           | string to the next method, deserialized and passed as an
           | object to the next method etc. There was this whole
           | complicated AsyncEnumerable setup that served no purpose at
           | all except complicating the code. There was a lot of other
           | stupid stuff. I really don't think my description adequately
           | conveys how bad this code was.
           | 
           | It was fucking atrocious. A coworker did some pair
           | programming with me and suggested asking the author about it,
           | I said I didn't want to talk to him because I didn't know
           | what to say. I don't think I could have had that conversation
           | without just completely shitting all over his entire project.
           | There weren't any questions to ask, there was no "maybe I
           | just don't understand the reasoning". I understood the code
           | perfectly and it was shit. Plain and simple.
           | 
           | So I did what I tend to do in these situations, which is the
           | subject of my quibble - I rewrote it. Instead of trying to
           | figure out how to do what I needed to do in the context of
           | this complete mess, I wrote some tests to establish the
           | current functionality (surprise, it uncovered multiple
           | glaring bugs - not sure how nobody noticed it wasn't even
           | working properly for months) and then I just deleted all the
           | trash code and wrote it properly. It wasn't a very
           | complicated program, it literally just gets some data from a
           | few API endpoints, massages it a bit and sends it off to an
           | event hub as messages.
           | 
           | So my quibble is that a lot of people don't appreciate this
           | approach. They call it scope creep, I get some task that
           | should be fairly small but it leads me down a rabbit hole
           | where I end up rewriting or refactoring large chunks of code
           | in addition to what I'm supposed to do.
           | 
           | I think it's a nuanced topic, I think my approach is
           | appropriate for some situations and not for others. For
           | example if I'm working on an app that only needs to exist for
           | another 6 months it's reasonable to minimize the effort spent
           | on it. Doesn't make sense to refactor stuff. In the case I
           | just described I think the rewrite was appropriate. My team
           | agree with me on that, though I'm not sure everyone would.
           | And I'm having trouble drawing that line, when should I fix
           | stuff and when should I work around it? I love great code and
           | I hate bad code, it honestly really bothers me when I have to
           | work with some moron's spaghetti. So I think I'm pretty
           | biased towards fixing stuff like that when I see it. I'm
           | happy to be in a team that appreciates this side of me but
           | I'm worried about when I inevitably end up in one that
           | doesn't.
        
             | wduquette wrote:
             | Ultimately you have two choices: you refactor the
             | architecture as needed as part of implementing the current
             | feature...or you end up drowning in technical debt farther
             | down the line.
             | 
             | A properly architected code base makes it easy to make the
             | kind of changes you want to make. A badly architected code
             | base (as you describe) makes it nearly impossible. I've
             | found it's usually by far the quickest thing to fix the
             | architecture and then implement the new feature sanely.
             | (And no, you don't ask permission; you just make everything
             | clean. As I noted above, if your boss doesn't like this
             | kind of thinking, you need a new boss.)
             | 
             | Of course, I'm one of those guys Graham mentions who works
             | by himself most of the time.....YMMV.
        
       | kazinator wrote:
       | > _And of course you can 't safely redesign something other
       | people are working on._
       | 
       | Unless, you know, it's automatically tested to hell and back.
        
       | kazinator wrote:
       | > _You never understand other people 's code as well as your
       | own._
       | 
       | Not only is that often false, but there are times when you can
       | understand another author's code _better than that author does_.
       | Like to see through it and why it cannot possibly work, while
       | they are laboring toward that.
        
       | jll29 wrote:
       | Another PG classic masterpiece - thanks for re-posting, I agree
       | with all eight points, and this should be mandatory reading for
       | people that manage developers particularly if the new manager
       | does not herself/himself have a development background.
       | 
       | Just to elaborate on "start with a simpler subcase": you can even
       | start with a single example and do what your code will be
       | supposed to be doing automatically by hand. After your draft
       | architecture stands, you can even hardwire what each component
       | does for that one example to see if things fit together before
       | implementing the general method for each component, which
       | provides an opportunity for early integration testing that is
       | priceless.
       | 
       | The current essay recommends building bottom-up primitives that
       | serve as primitives or languages (DSLs) for the next levels. This
       | is true, but you can do this upside down. For example, you can
       | write code that looks like pseudo-code because implementations of
       | functions you call do not (or not yet) exist. The code directly
       | reflects how you think, and you worry about the implementation
       | later. A special instance of that is API design, where you design
       | interfaces without implementing them yet; you can then write
       | client code and judge if the hypothetical API would be flexible
       | enough, be easy enough to use, and be feature complete and
       | orthogonal. When designing an architecture in a team with
       | multiple people, you can use paper cards with an example piece of
       | data that you pass from person to person, with each person
       | "performing" a component. They can then check that they have what
       | they need to carry our their task (otherwise there may be bad
       | surprises when integrating components later).
       | 
       | I found that some people are more leaning "top down" and others
       | more "bottom up"; I like to mix both styles, with system
       | architectures designed top down and the core algortihms inside
       | their components often being designed bottom-up, sometimes also
       | top-down.
       | 
       | Ironically, looking only at the headline, one could say that
       | abstraction enables one to solve problems without getting the
       | whole problem in one's head, or problems bigger than what anyone
       | can hold in their head, at least not at the same time, which kind
       | of is the whole point made by SICP.
        
       | noufalibrahim wrote:
       | I don't know how far this can go but it's a feeling that I've had
       | which is relevant and some people might resonate with.
       | 
       | I used some tiny devices (e.g. Casio PB80
       | http://oldcomputermuseum.com/casio_pb80.html) as a kid to write
       | small programs on in BASIC. It has only a single line of display
       | and you had to sort of remember where things were to make your
       | GOTOs work properly etc. This means that most of the program had
       | to be in your head. You couldn't easily jump between things and
       | see the whole thing as a single screen of text. I also remember
       | reading that people like Ken Thompson wrote significant parts of
       | the original UNIX on a line editor (ed). That would also mean
       | that most of it had to be in his head in a semi parsed format.
       | 
       | Sure, with modern editors and IDEs, you can outsource that to the
       | computer and focus on the more valuable stuff but I still wonder
       | how much the grunt work of remembering things in detail is under
       | appreciated in creative work.
        
       | zubairq wrote:
       | Brilliant article. I read a brilliant book written by Jessica
       | Livingston (Paul Graham's wife) called Founders at Work. In the
       | book Steve Wozniak talked about how he got designs done fast by
       | keeping it all in his head. Ever since I read that I have tried
       | to do the same. I would recommend this to anyone working on their
       | own project.
       | 
       | Of course in a corporate setting it is much harder to do as you
       | have code written in multiple languages using multiple patterns
       | stored in different places, so often there is not underlying
       | architectural thread to hold it all together.
        
         | tonyedgecombe wrote:
         | One of the things I liked about programming the Apple II was
         | that I could also hold the whole machine in my head. It's quite
         | a contrast to wondering which of the 4,000 methods on a Java
         | textbox I need.
        
       | FrankLicea wrote:
       | How relevant is this when AI has the ability to both write and
       | debug massive code bases?
       | 
       | I imagine a future world where 100% of coding and debugging is
       | done by prompt not by editing code.
        
         | tonyedgecombe wrote:
         | If that comes to pass then I can foresee a world where code
         | bases grow in size and complexity to the point of being barely
         | maintainable. After all that's what we tend to do right now.
        
           | lubujackson wrote:
           | It's effectively no different than the shift from coding in
           | assembly to using a compiler. We could abstract a level of
           | complexity away, which should always be a positive. There
           | will always be a level of human decision making because AI
           | relies on human decisions and choices, so higher level
           | architecting will be the new "scripting language" and we will
           | all become the new neckbeards complaining how nobody know
           | what's happening under the hood.
        
       | godshatter wrote:
       | As a developer who has aphantasia (can't visualize at all), I'm
       | curious how much visualization is used by others when "holding a
       | program in your head". I can hold a program in my head just fine
       | without visualizing anything, I'm just curious how much of it
       | involves visualization for others.
        
       | tonyedgecombe wrote:
       | >Probably the best we'll do is some kind of hack, like making the
       | programming parts of an organization work differently from the
       | rest. Perhaps the optimal solution is for big companies not even
       | to try to develop ideas in house, but simply to buy them.
       | 
       | I remember the CTO of a big American bank telling me they didn't
       | want to develop any software in-house. Their plan was to buy
       | everything in. At the time I thought it was rather strange but
       | having dealt with a lot of enterprise software since then I can
       | see why.
        
         | intelVISA wrote:
         | >I remember the CTO of a big American bank telling me they
         | didn't want to develop any software in-house. Their plan was to
         | buy everything in. At the time I thought it was rather strange
         | but having dealt with a lot of enterprise software since then I
         | can see why.
         | 
         | It's a very pragmatic choice for the majority of business use
         | cases. It should be more common imo, but some execs enjoy the
         | empire building aspect and underestimate TCO when looking at
         | cheap offshore dev resources.
        
       | iamflimflam1 wrote:
       | Reminds me of when I spent some time learning functional
       | programming. I did a Scala course and I still remember solving
       | some of the programming challenges. The slightest lapse in
       | concentration - I would immediately lose understanding of what I
       | was writing. It would turn from something amazingly simple and
       | elegant into a thing that was incomprehensible.
        
       ___________________________________________________________________
       (page generated 2024-09-19 23:01 UTC)