You get better at things by practicing them. It doesn't actually matter whether it is sports or a musical instrument or an art or a craft or riding a bicycle or driving a car or programming. Practice makes perfect, as the saying goes.
This practice should be regular, frequent, and deliberate.
You should make practice part of your routine. Practice in regular intervals at the same time.
Not only should your intervals be regular, they should also be short. One hour every 10 years is certainly regular, but definitely not frequent. Make sure to practice ideally at least once every two weeks or so.
The most important thing is that this needs to be deliberate practice. You need to specifically focus on practicing for an extended period of time (I would say at least two hours), uninterrupted, undistracted, and with a specific exercise only for practicing. As someone once said: if you don't delete your code immediately after having written it, you are not practicing, you are working. (I wouldn't go so far, in fact, it can be good to be able to revisit older practice sessions, but I hope you understand the sentiment behind it.)
If you are working, no matter how much and how long and how often you are programming, you are not practicing. If you are programming after hours as a hobby, you are not practicing.
Football players don't practice by playing twenty matches a week, they practice very specific, very focused drills that only exercise one particular muscle group or one particular skill or one particular formation or one particular part of play. They may practice with a particular handicap, e.g. only being allowed to use their non-dominant foot / hand (depending on which kind of "football"), or by only being allowed to score into one specific corner of the goal, or by only being allowed to touch the ball three times, or by playing 3-against-5, etc. Musicians don't practice by playing twenty gigs a week, they practice particular scales, particular techniques, etc.
The basic idea behind this is to build something equivalent to "muscle memory", so that through practicing writing clean and good code over and over and over again, writing clean and good code becomes the easy and natural way to write code when you are under stress. When you come under stress of a deadline, you should automatically write clean and good code because you have practiced it so much that doing it any other way would be harder than doing it the clean and good way. That is the goal.
For programming, there are a couple of forms of practice that have been developed over the years.
In some martial arts, there is the idea of a kata. A kata is a ritualized performance of a strictly defined sequence of particular moves or techniques. Often, the kata contains techniques whose difficulty level is one or two grades below the grade of the performer. The goal of the kata is not to demonstrate difficult techniques but perfect execution of simpler techniques. Another important aspect of kata is that they are performed in front of an audience, including both the master of the performer as well as students and masters of other dojos.
This idea has also been taken up by some programmers. Here is an example of Micah Martin performing a kata: https://8thlight.com/blog/micah-martin/2008/11/13/kata-langston%27s-ant-in-ruby.html Unfortunately, the video of him performing that kata live in front of an audience during a lightning talk at RubyConf 2007 seems to be lost. Here's an example of Robert "Uncle Bob" Martin performing a kata set to music, where e.g. deleting a bunch of code as part of a grand refactoring corresponds exactly with a climax of the piece: https://youtu.be/jgx5QvRS6j0
Another idea is Object Calisthenics. Object Calisthenics is a set of restrictions you place on yourself while practicing, that (hopefully) guide you towards writing better code.
TDD As If You Meant It
In a similar vein, Keith Braithwaite has created an exercise he calls TDD As If You Meant It. It consists of a set of rules (based on Uncle Bob Martin's Three Rules of TDD, but much stricter) that you must strictly follow and that are designed to steer you towards applying TDD more rigorously. It works best with pair programming (so that your pair can make sure you are not breaking the rules) and an instructor.
The rules are:
- Write exactly one new test, the smallest test you can that seems to point in the direction of a solution
- See it fail; compilation failures count as failures
- Make the test from (1) pass by writing the least implementation code you can in the test method.
- Refactor to remove duplication, and otherwise as required to improve the design. Be strict about using these moves:
- you want a new method—wait until refactoring time, then … create new (non-test) methods by doing one of these, and in no other way:
- preferred: do Extract Method on implementation code created as per (3) to create a new method in the test class, or
- if you must: move implementation code as per (3) into an existing implementation method
- you want a new class—wait until refactoring time, then … create non-test classes to provide a destination for a Move Method and for no other reason
- populate implementation classes with methods by doing Move Method, and no other way
Typically, this will lead to very different designs than the oft-practiced "pseudo-TDD method" of "imagining in your head what the design should be, then writing tests to force that design, implement the design you had already envisioned before writing your tests".
These rules are meant for exercising TDD. They are not meant for actually doing TDD in production (although nothing stops you from trying it out). They can feel frustrating because it will sometimes seem as if you make thousands of teeny tiny little steps without making any real progress.
IF Manifesto is actually not meant as an exercise, but for real-world code, but you can treat it as one, by exercising how to write code without any conditionals. (Or rather, where polymorphism is your only conditional.)
In fact, getting rid of
IFs is essentially just a strengthening of rule #2 of Object Calisthenics (Don’t use the
ELSE keyword), so it is very easy to combine Anti-
IF with Object Calisthenics. Object Calisthenics also goes great together with TDD As If You Meant It: TDDAIYMI tells you when to write code and where, OC and Anti-
IF tell you how to write code.
… and more
I am well aware that you are probably not doing OOP nor TDD in scientific programming. However, I hope the programming examples above as well as the sports and music examples give you ideas about how to create your own exercises.
The big question: WHEN to do this?
Well, that is the crux of the question, isn't it? Unfortunately, there is no simple answer. The time has to come from somewhere, and there are only two possibilities:
- The time comes out of your work time.
- The time comes out of your personal free time.
In my opinion, #1 is the "correct" solution. Your employer simply needs to give you time to practice. That means they either need to keep your current pay / working hours in place and reduce your workload, or keep your workload in place and increase your working hours and your pay accordingly.
I would argue that about 10% of work hours should be dedicated to learning and practicing. That means your project workload should not exceed 90%. As mentioned above, having a longer stretch of uninterrupted time is better than having many short stretches. For example, you could have one full workday every two weeks where you can practice undisturbed.
Again, there is no way around the fact that practice takes time and this time has to come either out of your work time or out of your free time, and it should come out of your work time.