What are some things that I’ve learned that really made my brain stretch?
I’ve seen plenty of articles or essays written talking about what the basics are that every programmer should know. I’m not just talking about kernel authors, device drivers, or embedded microcontroller developers. I’m also talking about JavaScript or Python developers doing typical “jam value A from box B into database field C”.
For any programmer, there are a few basics that you can learn that will really help you expand beyond just being an average programmer, things that help you understand stuff like the Law of Leaky Abstractions, or the Law of Demeter. Most good, experienced developers are already utilizing these concepts, perhaps without even realizing it. The first two that start down the path are Pointers and Recursion.
Pointers are important because they help you understand the difference between pass-by-value and pass-by-reference. That’s really where the key is. I don’t think you necessarily need to know all the details of how C handles pointers in terms of looking at memory spaces and indexes, but you should understand the idea of memory heap vs stack, sizeof, and addressing. Again, that concept of understanding how data moves around within your program is very valuable when you’re working with frameworks, singletons, SDKs, and other libraries. The pass-by-reference concept is also important because some modern languages push the concept of immutable data objects, so you have to understand where the values really are being updated in your code. Sometimes there are “surprises” when variables are, or are not, changing when you’re not expecting it.
Once you understand pointers, then you can understand linked lists, which I believe is also important. You’ll probably never really implement a linked list, but understanding not only how they are implemented, but how you perform operations on them, is key to understanding the “bigger-picture” concepts of managing data. Pop, push, shift, moving an item in and out of a random spot in the middle, or even moving items around to different indexes. Again, this is important to understand how your data is moving around in your program, or in this case even in your bigger pipelines like CI orchestration or cross-application integration. I’ve found I spend a lot of my debugging time just trying to draw long, detailed dataflow diagrams or data sequence diagrams.
It’s interesting how, in computer science, there’s a strong order to how concepts stack on one another. Once you have learned pointers, the groundwork is set for the next step. There’s two other things that I learned that really helped me make that next step to being a better programmer: lambdas and b-trees/hashing.
Hashing
Hashing ends up being important because it’s such a widely used concept in so many places. Many basic containers in modern languages utilize this, but also since so much is data-driven, or even database-driven, that understanding the basics of hashes can help you understand indexing and searching. This is really important if you ever end up working with large sets of data. If you are working with databases, indexes, and especially NoSQL nowadays, understanding how a hash organizes its pointers, and then how a b-tree shards the data, helps you know which indexes to create and how to push down into data more quickly and efficiently. For example, with dynamodb, you can’t really and truly understand the difference between a local secondary index and a global secondary index unless you understand what hashes and search trees are.
Lambdas
For many years, I read and heard so often the idea that functional programming was “better” than procedural, and that understanding functional programming would take your development skills to the next level.
Trying to sit down and learning Haskell or Lisp was much harder than I expected. More than once I got a hold of a functional interpreter or compiler, and a tutorial, and I tried to learn a purely functional language. But each and every time, I just could not get through the tutorial without understanding what was really going on.
Eventually I just sort of gave up, and wrote myself off as being forever a mediocre programmer. However, I happened to stumble across a book one time and reading just the first few chapters turned on an enormous light bulb.
By the way, the book is available for free online by the author. Enormous shout-out to Mark Dominus.
So I started reading this book, working the exercises and examples, and it’s a really great book. It starts just as a regular procedural programming language book, albeit teaching you advanced techniques. It has you writing fairly straightforward code, but then it gently inserts some interesting and tricky things, which at first just seem like little “tricks” to make your code more efficient. But suddenly you realize, you’re using recursion and lambdas. Then suddenly again, it’s like, Surprise! You just learned functional programming!
Once you understand what a lambda is, and anonymous functions, that’s really all it takes to flip your mind into understanding functional programming.
The reason lambdas are important, from a pragmatic programming perspective, is that they are actually more frequently use then people maybe realize. JavaScript, databases, even C#, anonymous functions are used in lots of places. JavaScript a really good example. If you’ve ever written an inline function to format the data in a row for a datagrid widget (i.e. you don’t know how many rows there are in a grid, but every time a new row in the grid is rendered that anonymous function fires), there you go, you’ve just written a lambda. In fact that’s the idea behind functional programming making procedural programming better, that you’re not spinning off into another method or library but instead rolling your code directly into your other code.
There’s much more I want to talk about, but these couple of basic concepts above are what can start you down the path of being a truly exceptional programmer.