Chapter 4. Pragmatic Paranoia
23. Design by Contract
Trust between software can be maintained by contracts. In design by contract, if all the preconditions are met, a routine must guarantee that the post conditions would be met. Designing a program that does no or less than what it claims to do is the heart of design by contract.
“Do One Thing and Do It Well”
— Unix philosophy
24. Dead Programs Tell No Lies
Try…Catch is only a good habit when you have a rescue plan for inside the catch block. If you don’t, it’s better to let your program fail. A dead program does a lot less damage than a crippled one.
If you are looking to create a reliable software: crash early and crash often!
25. Assertive Programming
If it shouldn’t happen in the normal execution of a program, then add assertions to ensure that if it ever happens you are able to crash immediately.
26. How to Balance Resources
The simple rule: whoever allocates a resource must always de-allocate it ensures there are no imbalances in resource allocation, i.e a file that is opened is always closed by the routine opening it. When it doubt, reduce the scope of resource allocation.
27. Don’t Outrun Your Headlights
Instead of taking in large projects and delivering end-to-end six months down the road, it’s always better to take small steps towards the goal, verify with feedback that the step is correct and then continue for the next step.
Any steps that requires fortune telling instead of educated guess is an impractically large step.
Chapter 5. Bend, or Break
28. Decoupling
Decoupling is the technique to ensure orthogonality. It can be done by ensuring you don’t operate on the object state, instead, ask the object to make changes. Global variables, method call chaining & inheritance are just some examples that add coupling.
29. Juggling the Real World
Users don’t want to wait for the critical processing your application is doing. They want the applications to be reactive. Events can help in creating more interactive applications. FSMs, Observer Pattern, & PubSub Pattern are strategies for implementing events.
30. Transforming Programming
Pipelines enable us to transfer data from one function to another which allows us to think in terms of transforming data to achieve output. The advantage of thinking in transforming data to reach our goal is that it forces us to break big problems into small components.
Programming is about code, programs are about data.
31. Inheritance Tax
There is no option to inherit just one function from parent, you have to get them all to use just one, this exposes new irrelevant functions for the object. Moreover, it add coupling! Use alternatives like interfaces, delegation, mixins.
“You wanted a banana but what you got was a gorilla holding the banana and the entire jungle.”
— Joe Armstrong
32. Configuration
All the configuration values should be outside the application separately in a file. This includes any business decision or system values that may change in the future. This file should be loaded by a class and all other classes should fetch values from this class allowing access control on our values.
Chapter 6. Concurrency
33. Breaking Temporal Coupling
Actions bundled together because they occur at the same time is temporal coupling. In the modern systems, it’s bad for two reason, it’s coupling & it stops unrelated routines from running concurrently. Activity Diagrams can help in identifying what processes can run concurrently.
34. Shared State Is Incorrect State
A shared state like global variables, files or databases which are accessible to multiple concurrent routines, is bound to create hard to reproduce bugs. Semaphore or mutex can ensure sequential access of the shared state.
35. Actors and Processes
The actor model allows us to create a system that does not have a shared state, Each actor has a capability of invoking other actors and process each message sequentially. This enables each process to be sequential but the system as a whole to be concurrent.
36. Blackboards
Message transfer systems like Kafka & RabbitMQ enable us to implement a laissez-faire system to avoid writing complex workflows and implement actions triggered when a message is received. This enables our systems to be concurrent by executing an action on request.
I hope you learned something new today. Good Luck with your skill development!