Food is never more delicious than after you've gone a while without eating. Happiness after a period of sadness is more intense and vice versa. That feeling of relaxation after working hard is so good, but when you relax too much doing work again can seem impossible. The transitions between these things seem in some ways more important than the things themselves. Why is this?
Modulation is the idea of varying one thing in relation to another thing to transmit information. It's the "mo" in "modem", but every wireless system uses modulation of some kind. Radios use analogue modulation, where the thing you vary is the frequency (FM) or amplitude (AM) of a waveform at a certain frequency. Modern digital devices tend to use more complex systems, encoding information using a fixed number of particular frequencies (FSK), phases (PSK) or both (QAM).
One thing that all of these systems have in common is that they depend on a fixed reference called a carrier wave. Usually that's just a simple sine wave at a given frequency. In the old days, you would transmit the carrier along with the signal, but that's pretty inefficient. Instead, when you know the frequency and phase you can just generate your own carrier wave.
But what happens when your reference isn't fixed? If the transmitter is moving relative to the receiver you get a doppler shift, and even without that there are often small variations between the carrier waves generated by different hardware. There's every chance your wave and their wave will be slightly out of sync. Compensating for this is known as carrier recovery and is, uh, fairly complicated.
There's a pretty neat technique that makes this much easier called differential coding, where instead of looking at the absolute value of the signal, you look at the difference between its current and previous value. Or, to put it another way, you use the signal as its own carrier. It's still the same modulation idea, varying one thing in relation to another, but the two things are the same signal at different points in time.
It seems to me that, since we tend to lack any kind of global fixed reference, we also look for meaning in difference. It would be great if there was some kind of absolute reference that we could measure everything by, and sometimes we can create one in certain circumstances, but everything is relative in the end. It may be that our greatest strength as a species is our flexibility, so in some sense it shouldn't be surprising that we are optimised for change.
So perhaps it is better to aim for, instead of a life of constancy, a life of constant transition. If we concentrate on meaningful transitions between high and low, busy and relaxed, over and under-achievement, we can avoid the impossible task of maintaining one particular situation in perpetuity. And although that might be difficult to deal with, it is in its own way quite liberating. Rather than relying on some external signal to give us meaning, we get to make it for ourselves, riding our own carrier wave out to wherever it might take us.
It is practically impossible to teach good programming to students that have had a prior exposure to BASIC: as potential programmers they are mentally mutilated beyond hope of regeneration.
— Edsger Dijkstra
Most programmers, even very good programmers, start by writing terrible code. Dijkstra called BASIC programmers "mentally mutilated"; he may have been thinking of the code I would someday write as a beginner. I hadn't ever heard of indentation, so I didn't use it. Subroutines scared me, so I just put all my code in one giant file. I didn't know how to make the body of an IF statement more than one line, so when I needed more lines... I just used more IFs. Needless to say, my code was a Lovecraftian horror I could barely understand even as I was writing it.
These days I've got if statements pretty well under control, and my first instinct when talking to a beginner programmer is to save them from the mental mutilation I inflicted on myself. Learn the form! Learn indentation and style! Learn code structure and comments and tests! Learn from my mistakes, young pup. Respect my long grey beard and glittering eye. Listen to my grizzled warnings, lest ye find yerself becalmed in a sea of spaghetti.
But the thing is, it wasn't all bad. At the time I was too new to understand that anything was wrong. My ambition hadn't yet scaled up to the point where it mattered whether my code was readable; I was happy if I could just get it to print some stuff. In fact, my ignorance was a source of great joy, because it made knowledge that much sweeter. When I found out about indentation, it was like an epiphany. Wow, I can understand code after I've written it! By having the chance to do things the wrong way, it made me appreciate the right way on a visceral level.
The problem with learning the right way first, then, is that it's arbitrary. You learn the form, sure, but you don't know why the form exists. I mean, sure, someone can handwave at you and say "badly-structured code is a nightmare", but until you've run out of single-letter variable names you won't really understand what "nightmare" means. It's hard to be motivated by someone else's assurances that this is the right way when it doesn't feel any different from the wrong way.
On the other hand, it's obvious that learning the right way is more efficient. We don't teach athletes to run badly before we teach them to run well. We don't teach gymnasts to do shoddy backflips with bad form and then hope they eventually come to understand why good ones are important. What a waste of time! Just teach them the right way from the beginning and they'll figure out why it was right when they win. I think this is roughly the attitude we use with beginners as well, and it does make some kind of sense.
But athletics and gymnastics aren't for everyone. For starters, a very small number of very motivated people manage to get very far in either. These people aren't motivation-constrained, they're skill-constrained. There's enormous time pressure; you've got about 10 years to win your medals and then that's it, so no room for screwing around. Most of all, you're facing off against other people who can out-compete you, so any inefficiency is a weakness your competition may not have. Plus these disciplines have been around a long time, and the form is pretty settled at this point.
And that last aspect, the lack of a settled form, is something that I think is worth considering. By learning the form without understanding where it came from, without getting a visceral understanding of the problems it solves, it makes it difficult to stray off the path of your existing knowledge. What if you need new form? What if there's a situation where the old form isn't relevant? Or what if you think you have a good reason to stop using the form, but really you just didn't understand it?
So, sure, if you're a professional athlete, or if you're trying to go from zero to a software development job in six months, learn the form. It'll be less fun, but you're not here to have fun, you're here to win. On the other hand, if you have the time, if this is a passion thing where you want to optimise for motivation, or if you're in this for the long haul and you want to end up with the long grey beard, glittering eye, and mental mutilation of hard-won experience, maybe it's not so bad to do it the wrong way first.
If nothing else, it'll rapidly reduce your desire to do it the wrong way in future.
Last week I did 3 prototypes, but this week I only managed one. That isn't too surprising, because last week was a failure week and all that. Still, I'm happy to vaguely keep my hand in, especially with my recent thoughts about tire kicking giving me a better framework for how to think about prototypes.
I've come to quite enjoy Floyd-Steinberging an image as a tire kicker. In this case, I'd recently learned about the fairly cool 𝚫 now project, which aims to be a sort of minimum viable Heroku. I saw the similarities to the minimum unit of code potential I saw in my AWS Lambda prototype, so I thought I'd try it out.
I had to work a bit harder for this one, because it was going to handle file uploads directly. That meant I couldn't use my node wrapper script trick from last time. Instead, I added http support to the code itself (via hyper). This turned out to be pretty simple, but I went a few rounds running through different options for web libraries before I found one that would let me just stream to the output. Rust's library story for web services is still a bit rough, but I think the main pieces are there once you get used to them. I didn't really deal with errors, so invalid input just brings down the service, but I figured that wasn't such a big deal for this.
As far as deploying (ie, the original goal of this prototype), it was super easy, and I was really pleased with 𝚫 now. Instead of building a binary, I gave it a Dockerfile (thus avoiding my incompatible libc woes with Lambda), and it just slurped it all up and built it. The first deploy did just hang confusedly, but I suspect that's because I was listening on the wrong port. Anyway, if you want to Floyd-Steinberg your own image, feel free to curl -T your-image-here.jpg https://saas-yeozgzvoii.now.sh > output.png.
I find it weird that when you buy a product or use a service, you're technically entering into a contract. It seems like we've gone through enormous legal hoops to make this work. Where's the contract when you buy something at a supermarket? How can you make a contract by showing someone an ad? How can you sign a contract by installing some software? Why I mean, sure, you can say that buying something is a contract, but you could also say it's a tomato for certain definitions of tomato.
Beyond their legal definition as an agreement between one or more parties, I think of a contract as something you negotiate, where everyone has an ability to influence the terms. That means there's an assumption that all the parties are first class: they can all understand the law and are on relatively equal footing. For that reason, these kind of contracts are often minimally regulated because, well, why should governments interfere in the affairs of consenting legal persons in their own boardrooms?
But most people aren't dealing with those, they get take-it-or-leave-it contracts where some company tells you "accept this or bugger off". You have no ability to negotiate, and in recent years it's become common to even sign away your right to sue entirely. Even if you wanted to, the legal disparity between Joe iTunes user and Apple's multimillion dollar legal team isn't even David v. Goliath, it's Ant v. Giant Magnifying Glass. To remedy this we have slowly built a large body of consumer protection laws and regulations, restricting contract terms to the point where many contracts have sections that are completely unenforceable.
At a certain point you have to wonder, why do we bother? I mean, sure, these consumer agreements share some features with contracts, and you can kind of make them fit into the same framework, but the question you have to ask is whether unifying these two ideas is more useful than keeping them separate. In software we run into this problem all the time; you come up with some clever framework whose ideas are so elegant you just want to cram everything into it. Sometimes it can actually work well to ignore reality a little bit if it makes your abstraction easier, but go too far and you start to end up with a big warty abstraction covered in special cases. Sound familiar?
I think we need a new thing. Some kind of alternative legal framework for consumer agreements that doesn't run through contract law. Terms of service would be set not by agreements between companies and each individual, but by companies and government agencies negotiating collective agreements on behalf of the people they represent. To an extent this is the inevitable outcome of ever-broadening consumer legislation anyway, but I don't think contract law + legislation is the right tool for the job. Legislation moves pretty slowly, so companies can often create loopholes that exist for a few years before they get stamped out, and on the other side too much consumer legislation is pretty overbearing too.
Ultimately, I feel like there's not much point having all these fake contracts that nobody reads, can't negotiate, and are mostly superseded by legislation anyway, especially when they all basically say the same things. I think it would be better for both companies and consumers if we just had a single framework for products and services being sold to end-users that everyone could understand. Plus then we could send all the lawyers off to do more useful things like ruin software for everyone.
There are always some limits in life: you can't stay up too late because you have to go to work in the morning, you can't hang out with your friends all the time because they're busy, you can't take an infinite amount of time on this project because there are deadlines to meet. These are external factors that you can't really do anything about; they're set by someone else and you have to just work with them.
Sometimes, though, you get a chance to get rid of some external limits. You start working for yourself, one of your friends gets a lot of free time, or you can set your own schedule for a project. It's natural to see this as a good thing, and in many ways it is; external limits are inflexible and restrictive, and they can make it difficult to do things the way you want to. Even if that external limit doesn't change your behaviour that much, just knowing that it's there can feel uncomfortable.
But some limits are necessary. After all, you probably want to do something useful with your time, and staying out too much makes it hard to do that. There's some real limit to how much hanging out with your friends actually benefits you; if you see them 24/7 you'll eventually get sick of them. And if you have an infinite amount of time for a project, maybe it'll end up with an infinite scope and never get done. So when the external limits are taken away, how do you keep the limits that you need?
The obvious answer is that you have to make them yourself. External limits get replaced by internal limits, which you can control and set based on your needs and the fundemental mechanics of the situation, rather than what someone else says. This is, on the face of it, unquestionably better: more control, more flexibility, and no strategic inefficiency caused by the difference between what someone else thinks you should do and what is actually best for you.
However, internal limits are also a burden. I once heard that being your own boss is working two jobs, so you should expect it to be harder than working for someone else. I think this is a related idea, though it doesn't only come up in work but in any kind of relationship. Being the person who has to set the limits is an additional burden. It comes with the perks of having control over what those limits are, sure, but it's still extra work being the one who has to say no even when a part of you wants to say yes.
So it's worth thinking about whether there are external limits you'd rather take on as internal limits, and it's equally worth thinking about whether there are internal limits that you don't need; you might be able to make your life easier by turning them back into external ones. But it's also worth thinking about whether there are people around you who are taking on the burden of acting as your backstop: taking on the additional burden of providing you with limits because you aren't limiting yourself.