I'd like to build on something I mentioned briefly in yesterday's post about efficiency: inefficiency doesn't hurt you as much in smaller systems as larger ones. While that is true, there's also a kind of reverse effect: we tend not to notice small inefficiencies in large systems. So, for example, the code to set up the environment before everything else runs might be way too complicated, but who cares? It's one tiny part of the code and you only have to write it once anyway. We need to worry about the big complexity that affects us every day.
While that is true, and it is absolutely more important to tackle large systematic inefficiencies, even small inefficiencies have a way of becoming quite substantial. The cost they impose can just keep growing but you only have to pay it once per system and it's still proportionally much smaller than everything else, so it never gets dealt with. This might not be a big deal when you build one big system, but it really hurts when you're building lots of small ones.
And that's a significant problem, because most software is too big. It does way more than it should and ends up overcomplicated. But it's very difficult to build small software if the way you do it is inefficient at a small scale. If you have to load up with a whole bunch of complex abstractions every time you start a new project, it doesn't make sense to bother unless the project is going to be big enough to justify it. This inefficiency-in-the-small changes your software the same way that inefficiency-in-the-large does: it rules out certain kinds of problems you can solve.
When we wonder why more people don't write code, I don't think the answer has that much to do with inability to handle syntax or state. I think it's that most people have small problems; they don't want to invent a web browser, they want to organise their bookshelf, or figure out which plants need watering. All our software development systems are too big for that. They come to us for home woodworking advice and we hand them industrial milling equipment. To solve their problems, we need tools that scale down.
For what it's worth, even with all the modern software in the world I still reach for my trusty set of minimal Unix tools when I have a small problem. They're 40 years old and still the best-scaling tools I know.
In many cases you can guarantee that there will be a solution to a given problem, as long as it falls within certain bounds. For example, the problem of "my computer should do this thing" for most values of "thing" is guaranteed to have a solution. Indeed, perhaps the biggest frustration in software development is when someone tells you "look, I know that a solution to this problem would look roughly like this, so why can't you just do that?" It's hard to explain that the challenge of software isn't finding any solution, it's finding a good solution within an infinite space of bad ones.
I like to make analogies between software and physical engineering a lot, because people have better intuitions about physical problems and tools. One hard problem in architectural engineering is making a really tall building. But that's not hard at all! Anyone can make a tall building given enough resources. Here's one solution: take a lot of material and keep putting bits of it on top of other bits. Every time the resulting structure is unstable, add more material to the sides. Bonus: the material will add itself to the sides if you make it too tall.
It turns out what you really want from your skyscraper is a bit more complicated than just making it tall. You want one that is not too wide because you have limited land area to work with. You also have limited materials and time to work with. Most importantly, you want a building that doesn't cost too much. Many problems are trivial to solve if you can just commit infinite resources to them, but practicality dictates that you have to work with less. What you want is the solution that gives you the most of what you want for the least resources. Which is to say, the best solution is the most efficient solution.
In software, efficiency is mostly used to talk about resources like processor time, storage space, and, more recently, energy usage. Those are the resources the software consumes when it's running. However, when creating software, it makes sense to think about the resources that are used for its creation. Those resources are developer time, developer working memory, and amount of code.
Developer time is probably the most well-understood and agreed-upon resource in software development. If you write one function, it will take an hour. If you write two functions, it will take two hours, that kind of thing. For a long time, it was thought that you could draw a linear relationship between size of problem and number of developer hours. Unfortunately, it doesn't, for reasons mostly related to the next two resources.
Developer working memory is less well-appreciated, but it is a significant mechanism behind the non-linear slowdown in building larger systems. Once a system goes above a certain size, you can no longer fit the entire thing in your mind at once. To understand it, you need to break it down into subsystems and only think about individual subsystems at a time. This adds a switching cost between subsystems and a new source of errors and design problems, as nobody is capable of reasoning about the entire system and its subsystems at the same time.
But both of these resources are dwarfed by the last resource, which is amount of code. If you can only concentrate on one resource, it should be this one. It is the equivalent of the amount of material in the skyscraper. It's not just that more is worse, it's that too much fundamentally changes the kind of building you can make. A skyscraper, by its nature, has to be built out of a structure that has a high strength but a low weight, because that structure has to support the whole rest of the building as well as itself. In other words, a skyscraper is only possible if you use material efficiently.
Similarly, certain kinds of software are only possible if you use code efficiently. A tangled mess of spaghetti code won't get in the way too much when your scope is small and your requirements are modest, the same way you can build a small house out of sticks and mud. However, as the amount of complexity your system needs to support scales up, the efficiency of your code becomes more important. It's vital that your code is able to support the weight of the problem's complexity while introducing as little complexity itself as possible.
Now, I say that, but obviously you can just naively build a really big codebase the way you might naively build a really big building: just add stuff on top of other stuff until it gets big enough. Assuming you have an unlimited number of developers and an unlimited amount of time, this is a perfectly reasonable way to go about things.
But, assuming you don't, too much code is a problem you can't afford to have.
Well, things are improving somewhat on the prototype front since last time. I committed to 3 and I got 3 done. That's technically a 200% increase. Victory!
This one came from a place of deep personal frustration. I'm always running lots of little webservers on my computer for development, and since each one needs a unique port number I end up having all sorts of ridiculousness: 3000, 3001, 4000, 8000, 8080, 8081. I forget which ones are which and sometimes end up trying to run things on the same port. In production this is exactly the kind of thing HTTP solves with virtual hosts, so I decided I'd make a local HTTP router to do the same thing. Ended up taking a bit more time than I thought because there was a lot of ridiculous DNS nonsense, but all told it was pretty under control, and the end result has already saved me a lot of annoyance.
I've had an idea for a while about generating more memorable passphrases by making the random words fit into a semi-meaningful sentence. Think "the {noun} {verb}s at {time}" kind of thing. In theory it would be possible to build even quite long scenes by sequencing actions and so on. Anyway, in trying to find decent word lists I ran headlong into the total devastation that is semantic web/natural language processing. It was all I could do to just get something that vaguely worked out the door, and I'm still not really that happy with it. It works okay as a proof of concept though.
This is a bot to manage contributors and pull requests on GitHub. I wrote about it ages ago and I'd even done some really early exploration with GitHub's API, but never actually pulled the trigger to make something that worked. Well, now I have and it seems pretty good. It only supports a couple of rules so far, but I built in the ones I wanted and it's already self-hosting (ie automaintainer is managing the automaintainer repo). If all goes well I'll be able to start using it for my other projects as well.
Time: 6 hours.
So I really pulled out some stops and stayed up to get this bunch over the line, mostly because I was sick of failing at my commitment. I can see though that the prototypes are still too complicated to make a feasible everyday activity. In my first week I noted that I would either need to accept only being able to manage a few project-sized prototypes, or figure out how to scale down.
I want to push a bit harder on that latter angle, so for next week I'm committing to do 3 prototypes in under 3 hours each. If I do something that takes more than 3 hours, it's a project and it doesn't count. That's harsher than I'd normally be, but I think I need to learn how to do less if this is going to work.
Which is more important: the experience of something, or the memory of it? Let's say you have the opportunity to either go on the amazing holiday of a lifetime, experience the most supreme pleasure and bliss you will ever experience, and then remember nothing about it afterwards. Alternatively, you could be given the memory of that amazing holiday, but never actually experience it. Presumably the person offering you these options doesn't like you very much. All the same, what would you choose?
I find myself tending towards memory over experience, but I'm not actually convinced that makes any sense. In the extremes, if memory counts and experience doesn't, torturing amnesiacs would be perfectly fine. They won't remember it anyway! Or, more mildly, your life becomes less valuable as your ability to retain memories decreases. Why bother to be nice to forgetful people? For that matter, why be nice to anyone? We all forget in the end.
There's an interesting phenomenon called the peakāend rule, studied by none other than Daniel Kahneman. According to that theory, we remember experiences not in their totality (eg, as the sum of all the individual moments in the experience), but by representative samples: the most intense experience and the most recent experience. That means that, for example, people will prefer longer, less painful surgeries to shorter, more painful ones, even if the total pain is much less in the short surgery.
So this is another angle into the same question: given that knowledge, do you use a surgical technique that causes more total pain but less remembered pain, or vice versa? Especially since people will use their memory to make decisions, so they themselves would choose more pain over less in this instance. And if you go with memory over experience, would your answer be any different if we were talking about an immensely painful surgery with a quick dose of sedatives at the end to wipe out the memory of it?
Perhaps complicating the whole thing is that memory influences experience. A memory isn't just an abstract record; you re-experience the memory as you recall it. So a happy memory makes you smile, an awkward memory makes you cringe, and a painful memory hurts, even though nothing has actually happened to cause that reaction. To really isolate memory from experience would require imagining an alternate human who can do those things separately. Someone who remembers without re-experience.
However, I think even that person has to make decisions based on memory. They would thus choose to repeat the holiday they remembered fondly but enjoyed less at the time, and the surgery that was more painful in total but formed less painful memories. That answer still seems unsatisfying to me, though; isn't this memory distortion spoiling the person's decisions? I mean, if you otherwise tricked someone into thinking a painful thing was less painful they'd go for that option, but it wouldn't be a good decision. On the other hand, that distortion is in fact how we remember, so it's not much good pretending that we don't.
So let's make one more change to our hypothetical: if a person who could remember without re-experience was also making their decisions in advance, with complete knowledge of how the experience would feel at the time, but also aware that their memories would not agree with that experience, how would they decide?
I think, in that case, the only sensible choice is to go with the best experience. Although the memories might not reflect it, those memories would have no emotional consequences. You would want to make the decisions that lead you to the best aggregate experiences regardless of what your faulty memory would tell you about them afterwards. However, this result is not terribly useful because there aren't any people who actually work like that.
But adding re-experience on top of this result isn't so hard: you still want to aim for the best aggregate experience, but you also need to take into account the impact of memory on your future experiences. This means you can't completely disregard your memories when they diverge from reality, but you also don't attempt to optimise for them directly. In most cases, your memories will affect your immediate emotional state less than the present situation. And if you assume that generally holds true over time, it also makes sense to generally choose experience over memory.
I remember this really funny situation that came up once in a library. You could book these nice study booths that were relatively secluded and good for getting work done, and I tried to make good use of them whenever I could. One time I went in and there was a small group already in my booth. "Hey, sorry", I said, "I have a booking for this booth". One of them replied, "we're already set up here, would you mind just taking that other free booth?" I very nearly said yes, until I realised the trap I was about to fall into.
Here's what would have happened next: I sit down in the nearby free booth, the group in my original booth save the effort of moving, everyone wins. Until fifteen minutes later, when someone else comes up to me. "Excuse me", they say, "I have a booking for this booth". When I explain that I am all set up at this booth and ask if they'd mind moving to a nearby free booth, they say "no, sorry, this is the booth I booked". What? This isn't the deal! I moved for those other people. I didn't have to, but I was being nice! And this is the thanks I get from this jerk who won't even reciprocate.
I call this situation a deal with the universe, and it comes up a lot. You decide that, because you've done some good thing or acted charitably, the universe now owes you. You and it have a deal. It's going to take care of you because you're a good person. You spent your weeknights helping homeless puppies with cancer, but during the weekend your date cancels on you and then you get sick. What the hell, universe? I give you all that and this is what I get in return?
Two things on that: firstly, I hope it should be obvious that the universe can't actually make deals because it's mostly empty space with some rocks and gas, and thus lacks the sentience necessary to engage in trade. The second thing is that the actual parties to these deals are sentient, but do not necessarily have any relationship to each other. This means your date who gets an earful of how good a puppy-saving superhero you are, or the jerk from the library who just wanted to use the booth they booked, are unwitting parties to a bad deal that was made without them.
That's not to say it's wrong to do nice things, but as soon as you start thinking those nice things are a trade you walk into real danger. Even doing something nice for a person and expecting something in return is a recipe for uncomfortable situations and resentment, but doing that when the person you give to and the person you expect from are totally different? There's no way that's going to work. The universe doesn't make deals, and people rarely see themselves as manifestations of some cosmic barter system.
The library situation, by the way? I told them they'd need to move. They grumbled a bit like I was being unreasonable and moved to the free booth. Fifteen minutes later someone else came along and kicked them out of that one too. Thanks, universe!