Developing your own style
(Work very much in progress, don't judge me)
When many programmers start working they have usually two problems on their hands. Obviously getting the code to do what is intended but also how to structure and layout their code.
- Should this be multiple classes?
- Do I use inheritance (no)?
- When do I break up a function?
- Are there better abstractions or patterns to solve this?
- What do I name this? And on and on.
Frederick Brooks of Mythical Man-month fame calls these microdecisions.
Brooks in "The Design of Design" defines as style as "a set of different repeated microdecisions, each made the same way whenever it arises, even though the context may be different".
When someone doesn't have a clear style it means that there are many of these microdecisions that they are constantly solving over and over again.
This will slow you down and your code will be sub-optimal because you truly haven't grokked how to express your intentions in code.
By developing your style you can, in essence, get out of your own way and focus on the solution. You have internalized the structural answers already and can write your intentions in a manner as concise as possible.
What I see often from other developers is that every project seems to be like their first. They are constantly struggling with these microdecisions.
Or they setteled into unproductive style. Writing a ton boiler plate code or crazy chains of if/else statements or my other personal pet peeve the variable that is assigned and then only used once.
I think that style is not an unconscious developement. It is about constant examing what you put in and take out of your tool box.
I believe it is about finding the most concice ways of solving the problem. I am not advocating for all code to be these dense one-liners. That is not great for different reasons.
That being said less code is in many ways better. Less to write initially, less to refactor. I do believe there is value in finding concise ways to achieve a solution.
Ok, how do you do that?
Back to basics
The first thing that I recommend is drop anything that you use that you don't feel like you own. Anything that is a bit of a mystery. You can add it back later but if you don't understand the pros and cons of it drop it for now.
Learn new languagues
There is an often asked question in programming. Is it better to learn more programming languages or master the one you work in the most? The jack of all trades or the master of none question.
The answer is both.
You should absolutely learn the advanced features of the language you use on a day to day basis. This can help you be more productive in that language no doubt.
That being said I don't think that it will by itself provide enough contrast and exposure to develop your own style.
Other programming languages will force you to think in different ways in order to solve a problem and if it is a good programming language it will introduce to even better ways of solving or structuring your code.
New languages can force you to think about computation in different ways and can impose constraints that force new ways of thinking and question our hidden assumptions.
Through these constraints, you can discover your own style. Constraints are your friends.
It is not just the constraints but the contrasts in styles highlight hidden implicit assumptions that you may have. If you lived your whole life with for loops then map, reduce, fold and list comprehensions can be an enlightening moment.
I don't think that the new programming language list has to be that long as most languages fall into general families.
Yeah, they may have a cool feature or two but in general, they are similar to the languages you probably already now and will not restructure your thinking. If you know Python or Ruby, it is not going to really push you to learn the other. Same with Java and C#.
The criteria is to find something starkly different from what you currently use.
If you have only programmed in an object-oriented language, then I highly recommend you try a functional style language.
I was first exposed to Lisp through Paul Graham's book: Hackers and Painters which is a collection of essays. In his essay, Beating the Averages, he makes a really strong case that lisp is a game-changer for productivity.
I am not going to go into this too deep as I think Graham's essay will do a better job, but in short Lisp and Scheme (Scheme is a dialect of Lisp) like languages have a very interesting property called Homoiconicity.
In Lisp everything is a list, even the code is defined as a list. So Lisp code can then modify its own code with ease as the code is just a list. This is basically the ultimate form of meta-programming.
It took me a while to really grok all this and to get to point where I felt productive in Lisp, but once I did it was one of the most profound changes in my mindset. If you only learn one language please pick up a Lisp dialect. I know that the parenthesis seem super crazy but it is worth it.
I started with Graham's book on ANSI Common Lisp which is a standardized version of Lisp. You can also take a look at Clojure or Racket which are two modern implementations.
Forth is a stack-based concatenative language. Like Lisp, it is amazing to see how much power can be wrung from constraints. In Lisp, everything is a list and in Forth, everything works off the stack.
Functions take values off the stack and put values back on. You build up your programs by defining a simple but expressive set of Words or functions.
Forth has been used in actual spacecraft, which I find insane but it is a really interesting language that again forces you to think about programming in a starkly different way.
You can get started with the open-source gForth, there is also a Forth inspired languaged called Min that runs on Nim. Min is a little more modern so that may be a good place to start.
Haskell is a statically typed purely functional programming language.
What that means is that functions do not have any side effects you know fun things like writing to disk and displaying characters to standard out.
It gets around this with these crazy things called Monads. Which are there own mental challenge to grok.
Why does it do this?
There are many ideas in Haskell but I would say an overarching goal is to make programming more rigorous and provable.State management is an important aspect of software. By tightly controlling and quarantining state you can make your programs more deterministic.
This is a great feature of not just Haskell but functional programming in general
Haskell has a steep learning curve, but has some intense constraints and new ideas to push you forward.
Haskell code at least to me does produce some beautiful code and has features I want more languages to have like pattern matching.
Systems programming may not be your bag but if you are going that route then this is the spot. C is amazing and how many languages remain relevant for so long?
C to me is elegant and beautiful. Sure there are some things that I don't miss, like endless compiler directives but there is a reason the C has endured. It is a perfect at the task it was designed for.
On the constraints front C will definitely give you constraints, especially if you are coming from a language with things like automatic garbage collection. It will also give a stronger understanding of how the computer actually works.
As I alluded to C does have some problems. It gives you all the power you could ever want, but that comes at a cost of safety.
Rust is a modern systems language that I think for the first time has a chance to displace C. It doesn't have garbage collection but a unique ownership system to understand when memory can be freed.
So how do we turn this into deliberate practice?
There is a book called "Exercises in Programming Style" where the author writes 33 versions of a simple text frequency counter. All these are examples are written just using Python.
I think that is an amazing application of deliberate practice.
So that is a good starting point, trying to write one project in many different styles and languages.
I would expand it to maybe a few other projects as each project can highlight a different aspect of the language.ll set of languages.
What would the following projects look across Python, Lisp, Haskell, C/Rust?
- Text Frequency Counter
- Basic Console Black Jack Game
- Simple context indexer
- Basic Html Tag validator
- Recreate them in different styles within your day to day language as possible. Write a version in pure OOP, everything has to be in a set of classes. Then as purely functional as possible.
- Recreate them using as many of the advanced features in your day to day language like meta-programming.
- Recreate them as idiomatically as possible in the set of other programming languages.
- If you are using a language that has a Repl try to as much as possible to write code using the Repl and your main editor.
Add back advanced features
Now that you have done a breadth search you can start to look at advanced things your day to day langauge. See if those things still make sense to you and if so do a deep dive.