Programming Values and Practices
This page is being demoted to a WIP as there are some things that I have learned that I need to incorporate into this document, and other things which I really don't believe in/care about anymore.
I think you’ll have an incredibly easier time in life if you quit trying to make code into some sort of aesthetic, amazing piece of something, and instead just accept the fact that coding is largely uncomfortable, that it’s largely not going to be the way you want things to be, that it’s largely going to be kind of annoying and that it takes time to get up to speed, and that readability is going to be an exercise in patience and time. Simply let that happen and then all of a sudden you’re just not going to be nearly as pissed. Because the reality is that at some point every codebase had to make tradeoffs or concessions for delivering.
– Paraphrased from The Primeagen đ«”
The thing I hate in the software industry is that everyone believes there is only one way to do things and itâs their way and that their way is the best.
– A YouTube Comment I Saw Once
Most aspects of programming quality are entirely subjective. There is no objectively best way to program or best style in which to program. However, I do think there are aspects which have a measurable effect on the quality of a particular codebaseâbeyond surface-level things like syntax or paradigmâthat are worth thinking about. These are the things that can increase the “Time To First Commit” of a new developer on a team or which can make it harder to come back and make changes to a program in the future.
Here are a few points that I think are good to keep in mind when designing systems or writing programs:
- Explicit is (usually) better than implicit, except if some implicit behaviour is anticipated/expected/intuitive (Odin creator Bill Hall talks about this on an episode of Developer Voices at roughly the six minute mark).
- Simplex is better than complex.
- Flat is better than nested (similarly, composition over inheritance).
- Sparse is better than dense.
Defining Simple, Simplex, Complicated, Complex
A system which is simple is easy to understand. A system which is complicated is hard to understand, often requiring specific knowledge about the problem to figure out why something is being done the way it is.
A system which is simplex has few moving parts. A system which is complex has many moving parts.
It is easy to see why these terms get mixed up a lot. Simplex systems often tend to be simple because it’s easier to understand what’s going on in a system that has few components. Conversely, a system with many moving parts is often viewed as complicated because there may be many aspects to take into account to fully understand what a system is doing.
However, these relationships are not inherent. If a system with many moving parts has each part made with a cleanly defined, easy to understand interface and as-close-to-singular purpose as is reasonable for a given part, then one can figure out the behaviour of a system by looking at it at the level of abstraction of interface interactions, as opposed to needing to know how or why each individual part is doing what it’s doing.
Similarly a system that has only one or two components may appear to be simple because of that fact, but if those components are tightly coupled, making use of implicit and non-intuitive behaviour (e.g. changing a value in one component affects how something works all the way in another component), it can be incredibly difficult to understand, requiring a line-by-line read through of the entire codebase just to figure out what a system is really doing.
Prototype first, get the thing working, then clean it up and polish it.
Create abstractions only if absolutely necessary such as when you’re finding yourself repeating code too many times (e.g. >3 times) or to establish clean interfaces between the parts of your programs.
Follow the principle of least surprise both in your programs themselves and in the interfaces users use to interact with it.
When a program needs to fail, it should do so fast and loud.
Always carefully consider how you can solve your problem without adding any new dependencies or tools to your ecosystem. Only when you have determined it would be impossible (or very very hard) without, should you add something new.
More generally, do not pre-empt your needs. Only do something when you have determined that you will actually need something, not when you think you might need something in the future.
“What is object oriented programming? My guess is that object oriented programming will be in the 1980’s what structured programming was in the 1970’s. Everyone will be in favor of it. Every manufacturer will promote his products as supporting it. Every manager will pay lip service to it. Every programmer will practice it (differently). And no one will know just what it is”
– Tim Rentsch
On The Ease of “Making Machines Do Stuff”
One should not have to be an expert or engineer to program in a non-professional setting; programming should be open and available to all. In the same way anyone can pick up a hammer and hang a painting or put together furniture, one should be able to slap together a temperature monitor or work with data with ease. Some great examples of this are Excel and visual programming systems.
On Complexity
Paraphrasing Alex Wennerberg’s (@aw@merveilles.town) impromptu rant about StackOverflow and the state of the Software Engineering industry:
I don’t like StackOverflow. It’s not the best. It’s not where I want us to go. ‘Cause it’s not knowledge, it’s just information.
The problem is that we have these systems that are so complex that no one could conceivably understand all of them. No one could possibly understand all of the systems that some professional engineer works with. We’ve gone so far into complexity that no person can understand the whole system or some programming environment top to bottom. So what we have to do is get really good in the whole industry about building tools for partial understanding so that if you know a little bit about one thing you can learn a little bit about another thing. StackOverflow is really good about that. You can get a lot of partial understanding about a lot of different things. Which is good in some sense, but I think the fact that we’re not using systems that we can understand deeply is a fundamental problem.
That’s why you have to learn Forth. That’s why you have to suffer through the bits and the bytes. You have to suffer because suffering will make you a better person. It will make you a better programmer to suffer. But it’s a specific kind of suffering, it’s not toil. Toil is how most people do engineering work. Toil is like: “Ugh, why is this code so bad. What does this system even do?” and that’s so horrible. To deal with toil as an engineer is miserable but that’s what most of Software Engineering is. And so we just proliferate toil. That’s how we do engineering. And then we say we’ll just hire 5,000 engineers and they’ll all toil. Whereas doing something like Forth is a different kind of suffering. It’s the suffering of developing an understanding that you didn’t have before. It’s the suffering of really mastering something really deeply which, I think, unfortunately, is something we do less and less as engineers.
Edsger W. Dijkstra on Complexity:
[…] an early conclusion was that the only effective way of winning the battle against unmastered complexity requires that one prevents the latter from entering the design in the first place, or, in more technical terms: mathematical elegance is not a dispensable luxury but a factor that decides between success and failure.
Mathematical elegance, conceptual simplicity, and their companion, brevity of an unambiguous reference manual, are a condition sine qua non for any product reliable enough to attain stability.
On Perl and Languages That Let You Express Yourself
From @Arcana@akko.disqordia.space:
So Iâve been meaning to write a post about my Perl âhot takesâ so to speak, or at least what I like about the language and why I unironically defend it
I first got into Perl back in 2015, after having used C, PHP, JavaScript, and Shell Scripting. I started playing around with different languages to decide on one to learn and decided to make small programs in a few languages to compare how they felt. I tried Go, Python, Ruby, and Perl and out of all of them Perl felt the best and I found myself wanting to do more and more with it
Sure, the semi colon made it syntactically similar to the languages I already knew but it felt like it was super general purpose and in a very expressive way that actively stimulated my mind
I think one of the best ways to sum this up comes in Perlâs motto itself, âthereâs more than one way to do itâ. This is often contrasted with Pythonâs âthereâs only one way to do itâ and I felt this very heavily. While Iâm sure the consistency and standard structure of Python makes it appealing for big projects, I was just doing my own thing and learning Perl felt more like learning to paint or writing a poem. I could express myself and do things in the ways that felt good for my brain
It just felt incredibly expressive and I loved how it flowed, how I could very easily rearrange statements and subroutines, and have as much as I wanted on a single line (or not) to suit my own style. Perl is often insulted as a âwrite onlyâ language but I feel like this is part of the beauty of Perl, in that itâs let the coder put their own personality in. Much like handwriting, youâre using the same words, and some are easier to read than others, but ultimately itâs part of who that person is, a mark left on the world
I think when people criticize Perl they often see it as âitâs either good at making big complex software projects or itâs badâ when it is at its core an expressive hacker language thatâs easy to learn and yet youâll still be learning new tricks a decade later. You can use it to quickly write little automation tools or scripts where writing it in Bash would be pain, but you can go bigger with it too. It has a big module repository (and was one of the first to pioneer the idea I believe) which means you can very quickly build little tools and projects in your own way
I think people get far too hung up on what they see as a very professional and standard set of tools and that the freedom Perl gives is bad for maintainability, but I think that isnât and shouldnât be the whole picture, I think there should be room for a fun expressive language that lets you add a piece of yourself to everything you write, your own quirks, your own style. You can actually have a lot of fun and learn a lot by reworking a single statement of code in many ways, and in fact, thereâs the âJust Another Perl Hackerâ thing where people try to find their own way to write code that simply prints out that string, and there are so many creative and interesting examples including one where the source code is ascii art of a camel
Iâm not saying you should start doing everything in Perl or adopt it as your main language but that you should give it a chance and at least not cast it away as a mistake of the past. I think it very much embodies the late 80s and 90s hacker culture in its very makeup and really does lean into programming as an art not just a science
If you asked 10 artists to paint a horse youâd get 10 different styles, and likewise, the âwrite onlyâ criticism of Perl is that if you asked 10 Perl programmers for a basic program, youâd get 10 different sets of source code but I think itâs honestly nice for that to exist, a project should be an endeavour of passion and creativity, and being able to do that in your own unique way is a good thing imo
Why I Like “Simple” Languages
Languages like C and Lisp are very barebones. They contain very basic syntax and very few features yet are complete programming languages. I find myself increasingly drawn to these languages over languages such as Python and C++ specifically because of this simplicity. Although these more “modern” languages can reduce the work needed to build a robust and correct program (though their complexity often gets in the way of this goal), they also feel constraining in a way.
When I program in Python, it feels like I’m building a house out of pre-defined pieces that I’m treating as black boxes. When I’m programming in C, it feels like I’m building a house out of pieces that I’m sculpting and tailoring to the problem I’m trying to solve. Where in Python I use the built-in data structures, in C I craft my own. Where in Python I might throw together a prototype to better understand the problem domain, in C I carefully stitch together a final product that tackles the problem using only what is needed, eschewing any other cruft or considerations.