See the first post in The Pragmatic Programmer 20th Anniversary Edition series for an introduction.
Think about a design principle you use regularly. Is it intended to make things easy-to-change?
Pure functions! Outside of Functional Programming, this is perhaps a lesser used/considered design principle - often superseded by principles such as SOLID and DRY. However, I have found it to be a very effective principle to follow no matter the programming paradigm being used.
In computer programming, a pure function is a function that has the following properties:
- Its return value is the same for the same arguments (no variation with local static variables, non-local variables, mutable reference arguments or input streams from I/O devices).
- Its evaluation has no side effects (no mutation of local static variables, non-local variables, mutable reference arguments or I/O streams).
– Pure Function, Wikipedia
This definitely makes code easier to change. Since a function depends only its inputs, it can be understood independently of the surrounding system. This means, for example, that the function can be changed with the knowledge that it’s not going to break something else through shared, mutable state.
Also think about languages and programming paradigms (OO, FP, Reactive, and so on). Do any have either big positives or big negatives when it comes to helping you write ETC code? Do any have both?
When coding, what can you do to eliminate the negatives and accentuate the positives?
I’ll address a few points for several paradigms only - this could be an entire book in itself! Please do note the emphasis on phrases such as ‘it can’ and ‘in theory’. These are not absolute truths and I don’t believe that any programming paradigm is outright incorrect or bad. These are pragmatic assessments of some of the positive and negatives of each from my experience.
Classes can split Software up into small pieces of functionality/behaviour. Each provides an interface which can be used by other classes to exercise the behaviour of that class without needing to understand the algorithms used to achieve it. This, in theory, makes Software easier to understand by hiding details behind abstractions and allowing the internals of these classes to change without requiring changes to the rest of the system.
Actually splitting the behaviour of Software into discrete classes becomes difficult for any non-trivial scenario. This can often lead to leaky abstractions and complex inheritance hierarchies - both of which make code harder to change and manage over time.
A program is modelled as a composition of many small functions. Each of these functions performs one small operation (usually in a pure manner) upon some data. The program is therefore a set of transformations of data which can each be be easily reasoned about. This compositional design can make changing a program simple - compose some function with another to produce a different output.
Due to a large number of small functions, it can become difficult to find where to change the code to affect the intended behaviour change. Furthermore, it can be difficult to change the underlying data within the program. Since a functional program is a series of transformations on some simple data structures, adding new keys and/or values to these can causes cascading changes throughout the program. There are of course ways to design a program to where this is not the case, however this can take a lot of skill and experience to do effectively.
A program reads from ‘top to bottom’, in theory allowing one to comprehend the process/steps performed by a program. This can make changes easy as it is clear where each step in the program takes place and how it works.
For any non-trivial scenario, it can be very easy for procedural programs to fall into the trap of spaghetti code. Furthermore, since the algorithms and inner working details of each step are present it can become difficult to parse out the high level steps (the ‘what’) from the low level details (the ‘how’).
Many editors have support (either built-in or via extensions) to run commands when you save a file. Get your editor to popup an ETC? message every time you save and use it as a cue to think about the code you just wrote. Is it easy to change?
:autocmd BufWritePost * !notify-send "ETC?"