This is part 2 of the article. Please read Part 1 first if you didn't do so yet.
Writing Code
Write beautiful code!
Beautiful code is short, simple, quickly understandable, modular, extensible, reliable and maintainable.
Beautiful code rarely needs comments and reads like prose.
Developers love to look at and work with beautiful code. It makes them feel good.
Writing beautiful code is an art that requires passion, deep commitment, and many years of practice.
Quote:
Great software requires a fanatical devotion to beauty. If you look inside good software, you find that parts no one is ever supposed to see are beautiful too.
Quote:
Current development speed is a function of past development quality.
— Brian McCallister
Quote:
Programs should be written for people to read, and only incidentally for machines to execute.
Quote:
Because maintenance is so important and so expensive, write programs as if the most important communication they do is not to the computer that executes them but to the human beings who will read and maintain the source code in the future (including yourself).
— The Art of Unix Programming
Quote:
Clean code always looks like it was written by someone who cares.
— Michael Feathers
author of 'Working Effectively with Legacy Code'
Quote:
I have deep faith that the principle of the universe will be beautiful and simple.
— Albert Einstein
Use existing software whenever possible!
Don’t reinvent the wheel!
Before writing new code, be sure the functionality you need doesn’t exist already.
Look at existing libraries and frameworks (maybe written in different languages), tools, other applications and cloud services to find what you need, or to get ideas and become enlightened.
For example, Unix provides many powerful, reliable and flexible out-of-the-box-tools (also available on Windows) for text manipulation. Use them in your application if they are appropriate.
Quote:
... library code is likely to be better than code that you’d write yourself and is likely to improve over time. … library code receives far more attention than most developers could afford to devote to the same functionality.
— Joshua Bloch
book 'Effective Java'
Quote:
Thou shalt study thy libraries and strive not to re-invent them without cause, that thy code may be short and readable and thy days pleasant and productive.
Quote:
The best code is no code at all.
— Jeff Atwood
Quote:
If I have seen further than others, it is by standing upon the shoulders of giants.
— Isaac Newton
Fail fast and noisily!
Detect and fix problems as early as possible!
This helps to minimize development time and costs, and reduces the risk for failures and damages in production mode.
A maximum of bugs should be detected automatically. This can be achieved by smart IDEs, compilers, static code analyzers, fuzzy testers, etc. Automatically detected bugs are very cheap to be discovered, and they can’t go into production and cause malfunctions.
Write good unit tests.
Bugs that stay undetected before running the application, as well as all kind of runtime problems (e.g., file not found, invalid input data, etc.) should be detected as early as possible at runtime.
Therefore, check all input for valid values (function arguments, user input, resource input, etc.). Check all return values for error conditions.
If the runtime problem cannot be handled gracefully, then the application should consistently apply the Fail-fast principle by reporting the problem in an appropriate way (i.e., with a maximum of information that helps to solve the problem), and then aborting immediately. This is important because:
-
in development mode, it helps in debugging, as the application crashes noisily as soon as something goes wrong
-
in production mode, it leads to a crash of the application which is generally less awful than silently continuing and leading to outcomes that are worse, such as wrong data, wrong decision making, etc.
Here is an example of what can happen with wrong HTML code, because the Fail-fast principle is not applied:
Instead of displaying the following life-saving warning …
... a life-threatening message is displayed:
For an explanation of the above outcome (and for more advice about how to fail fast), please read Introduction to the 'Fail Fast!' Principle in Software Development (hint: it’s just a missing >
character in HTML code).
Ultimately, the Fail-fast principle helps to write more reliable and safe code in less time.
Therefore, prefer programming languages, libraries, frameworks, and tools that support the Fail-fast principle.
Quote:
Repair what you can - but when you must fail, fail noisily and as soon as possible.
Quote:
If a function be advertised to return an error code in the event of difficulties, thou shalt check for that code, yea, even though the checks triple the size of thy code and produce aches in thy typing fingers, for if thou thinkest "it cannot happen to me", the gods shall surely punish thee for thy arrogance.
Quote:
Do you fix bugs before writing new code?
Every software component should be small and have a single responsibility.
Small, single-responsibility components have benefits for both the author and the user of the component.
-
Benefits for the author: They are easier to write, test and maintain. They are less error-prone and reduce dependability (coupling).
-
Benefits for the user: They are easier to understand and use. They can be combined with other components in more flexible ways. It is easier to replace or extend them with another implementation if needed.
The power of the whole is the result of many simple components working seamlessly together.
Quote:
Write simple parts connected by clean interfaces.
Make each program do one thing well.
— The Art of Unix Programming
Quote:
I developed a habit of writing very small functions.
Don’t overdesign!
Resist the temptation to add features that might be used in the future.
Every feature increases complexity as well as the risk for malfunctions. Every feature needs time to be created, tested and maintained.
Moreover, it is often difficult to foresee features that will actually be needed later, especially in projects with frequently changing requirements. Adding features that will never be used is pointless.
Remember: Keep it small and simple!
Before thinking "What else can we add?", ask yourself "Is there anything we can remove?"
Quote:
When in doubt, leave it out. If there is a fundamental theorem of API design, this is it. It applies equally to functionality, classes, methods, and parameters. Every facet of an API should be as small as possible, but no smaller. You can always add things later, but you can’t take them away.
Quote:
Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away.
— Antoine de Saint-Exupéry
Quote:
To attain knowledge, add things everyday. To attain wisdom, remove things every day.
— Lao Tzu
Quote:
YAGNI: You aren’t gonna need it.
Optimize only if necessary!
Instead of writing 'clever code that runs faster' it is better to write simple, correct and maintainable code that runs fast enough.
The approach should be:
Don’t forget: Bad performance is often just a consequence of bad data structures, bad code and/or bad architecture.
Quote:
Premature optimization is the root of all evil.
— Donald Knuth
author of 'The Art of Computer Programming'
Quote:
Make it run, then make it right, then make it fast.
— Kent Beck
Creator of extreme programming
Quote:
Rushing to optimize before the bottlenecks are known may be the only error to have ruined more designs than feature creep. From tortured code to incomprehensible data layouts, the results of obsessing about speed or memory or disk usage at the expense of transparency and simplicity are everywhere. They spawn innumerable bugs and cost millions of man-hours — often, just to get marginal gains in the use of some resource much less expensive than debugging time.
— Eric Steven Raymond
The Art of Unix Programming
Automate recurring tasks!
Doing the same again and again is error-prone, counter-productive, boring and increases the risk of not doing things that are important, such as unit/integration tests, backups, etc.
Use the best tools you can get for frequent tasks, such as writing/editing code, handling files, etc.
Strive for single-click-execution or, even better, scheduled tasks that run automatically.
It is often easy to automate tasks. Create small scripts (written in your preferred language or using OS scripting), use automation tools such as Autoit, Selenium, or use any other best suited tool to quickly automate your or your user’s recurring tasks.
Quote:
Use tools in preference to unskilled help to lighten a programming task, even if you have to detour to build the tools and expect to throw some of them out after you’ve finished using them.
— Doug McIlroy
Inventor of Unix pipes
Quote:
Rule of Economy: Programmer time is expensive; conserve it in preference to machine time.
— The Art of Unix Programming
Quote:
Can you make a build in one step?
Enjoy being in the flow!
Flow (psychology) is described as follows in Wikipedia:
Quote:
Flow … is the mental state of operation in which a person performing an activity is fully immersed in a feeling of energized focus, full involvement, and enjoyment in the process of the activity. In essence, flow is characterized by complete absorption in what one does, and a resulting loss in one’s sense of space and time.
Being in the flow (also called being in the zone or in hack mode) can lead to a state of blissful feeling that needs to be experienced to be understood. Flow might be the reason a programmer once wrote in a forum: "I want to code, code, code - until I die."
For programmers, flow can best be achieved under the following conditions:
-
There are no distractions, such as incoming phone calls, emails, any other kind of notifications, noise, etc.
-
The programming task at hand is worthwhile and challenging, but not too difficult.
-
You must see clearly, before starting to code.
What does it mean to 'see clearly'? Close your eyes. Can you see the overall picture, the data structures with their relationships, as well as the functions and their interactions? Doubts must be eliminated first - by using paper and pencil, searching the net, asking for help, writing small snippets of test code, or doing whatever else is appropriate to get rid of the doubts.
Can you see clearly now? Then start coding and fully enjoy it!
Summary
Here is a summary of the pragmatics for successful programmers:
General Guidelines
-
Everything should be as simple as possible, but not simpler! - Albert Einstein
-
If it’s doomed to fail, then 'Fail fast!'
-
Strive for 'good enough', not for 'perfect'. Then release!
-
Listen to the users!
Data Design
-
Before writing code, design your data carefully!
-
Make all data structures immutable, unless there is a good reason to make them mutable!
-
Limit the set of allowed values to the smallest possible one!
-
Most of the time, a default value should be the strictest among the set of allowed values.
-
Avoid data redundancy!
-
Consider storing data in simple text files using universal, standardized formats!
Writing Code
-
Write beautiful code!
-
Use existing software whenever possible!
-
Fail fast and noisily!
-
Every software component should be small and have a single responsibility.
-
Don’t overdesign!
-
Optimize only if necessary!
-
Automate recurring tasks!
-
Enjoy being in the flow!
History
- 13th March, 2018: Initial version