Mindful programming rules

Finally I decided to share my rules for writing code. These are for your sanity, my sanity, and are hardly creative or innovative. Each of these rules you probably invented on your own, probably formulated in a different manner, or perhaps you read about somewhere in the internet. Every rule here can be replaced just by common sense. Order does not matter – I will keep numbering constant (I hope).

  1. First the INTERFACEs. It’s not an abstract class, not a keyword – more like API, spine, top, explanation how your implementation works
  2. Keep your IFs as close to the top as possible, if not higher
  3. Avoid IFs in implementation
  4. INTERFACE selects correct algorithm variant
  5. It’s better to copy&paste than make your function unreadable by IFs
  6. Separate your IFs from The Implementation
  7. Use IFs if you really must /
    Keep code branch-less
  8. SWITCH is a form of IFs
  9. TAG your parameters /
    Compiler does not read names
  10. Name your parameters
  11. Use STRUCT for large number of parameters /
    Group you parameters into STRUCT
  12. Don’t create boolean parameters – create functions assuming parameter’s name and value
  13. Don’t store boolean members in class/object
  14. Don’t inherit /
    Why don’t you inherit from vector
  15. Don’t create classes
  16. Don’t create objects
  17. SOLID is always relevant
  18. Use names everyone understands
  19. Controller/Manager/Listener/Provider/Cloud/Sometimes/Magic/… – it’s another way of saying “I DON’T KNOW”
  20. Different purpose – Different name
  21. Set of overloaded functions treat as one entity
  22. Use names for terms that are intuitive to your team and your users /
    A vector is a vector
  23. Inheritance relation is never IS /
    All inheritance diagrams from school are wrong /
    When you inherit from a vector it’s not a vector any more
  24. Remember what magic is (implicit) THIS, VTABLE
  25. Make your IFs as readable as possible
  26. Class field or object field are still global variables, just of different degree
  27. Singletons are pure evil /
    Global variables are evil
  28. Remembering INTERFACEs is all you need
  29. Function signature is an INTERFACE
  31. Don’t partially construct – always in full
  32. Use preconditions, postconditions to verify your assumptions
  33. Function always assumes something
  34. Put in parameters only what you need and not the trash bin
  35. Make implicit what is intuitive /
    Matrix multiplication is intuitive
  36. Lack of knowledge is not intuitive – it’s a reason to educate
  37. Fix name of your functions after every change
  38. Primary concern of program using threads are the threads
  39. Primary concern of using threads is concurrency – threads’ cooperation
  40. Use coroutines /
    Avoid callback hell
  41. If you can’t use coroutines use Reactive Extensions or Transducers
  42. Don’t use threads
  43. Always remember the time, place and reason when you break the rules
  44. Put a link to Stack Overflow in the comment as documentation
  45. When not sure ABORT
  46. When you keep casting class hierarchies you made an error
  47. Dijkstra tells us there are no bugs – just errors of programmer
  48. When done your creation should not ABORT
  49. Preconditions, postconditions are for developers /
    Developer is only interested in ABORTs
  50. When in doubt use reification
  51. Log changes to your state /
    Log your inputs
  52. Prepare your state for serialization
  53. Serialize your state to log file every now and then
  54. Make your function as meaningful as possible
  55. Don’t scatter your algorithm like farmer does with the fertilizer
  56. Make your function independent
  57. Segregate your functions
  58. Segregate your functions after every change
  59. Don’t deduplicate your code with IFs /
    Premature deduplications is source of all evil
  60. “a” and “b” are meaningful names if it’s a mathematical equation
  61. Put a link to wikipedia in the comment as a documentation
  62. Don’t use long names /
    Don’t call me by all my names every time
  63. If unsure don’t catch exception
  64. It’s better to ABORT than spend two weeks debugging
  65. Log all decisions
  66. Reify your decisions
  67. Don’t fix code – remove it
  68. Best code is the code you don’t have to see or debug to know how it works
  69. If you’re debugging you made a serious error /
    Don’t debug
  70. An IF inside matches the IF outside – remove IF inside
  71. Where are the Unit Tests?
  72. Your edge case is my normal use case
  73. Don’t log “this should not happen” /
    Every branch of your code will eventually be executed
  74. Singleton may hide in every line of code
  75. Don’t mutate in getters
  76. Don’t notify in getters
  77. Hungarian notation sucks
  78. IHate INTERFACEs (as in keyword in Java, abstract class)
  79. AppHolder is pronounced as Abhor There
  80. Think in tables /
    Use vector
  81. Blame the Singleton
  82. Blame Magic /
    Blame Controller /
    Blame Provider /
    Blame Listener
  83. Callable is a good INTERFACE
  84. INTERFACE must be minimal
  85. TDD stands for thought driven development
  86. If you can’t understand the code you can’t fix it
  87. Separate you concerns /
    Divide and conquer
  88. Simplify your logic
  89. Every developer makes an error in boolean expression /
    Keep boolean expressions as simple as possible
  90. Make your logs parse-able and readable
  91. Push unique CORRELATOR through every layer
  92. Log CORRELATOR with your input
  93. Fix database content after exception is thrown
  94. Don’t write code that is not exception-safe
  95. Don’t assume there are rules that user would not break
  96. Date and time are hard subjects – use good library /
    Listen to Howard Hinnant
  97. Early exit is better than several indentations
  98. Name your booleans
  99. Separate decision making from implementation /
    First make a decision then act on it /
    Don’t mix decisions and actions
  100. Filter out null as soon as possible
  101. Write loops as if it was a filter
  102. boolean is not bit-wide
  103. Always initialize your variables /
    Use IILE
  104. Compiler does not read your comments, most users don’t either
  105. Make your comments as meaningful and short as possible
  106. Always express graphically your boolean expressions /
    Unroll your boolean expressions into IFs ladder
  107. Write your function as if it was a filter
  108. Don’t use inheritance when implementing concurrency pattern /
    Concurrency does not mix well with inheritance
  109. Pass different callback instead of creating IFs
  110. When you don’t understand the code rewrite it for yourself
  111. Use INTERFACEs on every layer
  112. REDUX is a beautiful pattern in every language
  113. Even authors of Design Patterns want to get rid of Singleton
  114. Whole algorithm in only one file
  115. Finite State Machine is better than anything else
  116. If you can’t use coroutines or Reactive Extensions use Duff’s device
  117. Always try to find an algorithm for your raw loop
  118. Good code can only be written in iterations
  119. Make your code better every time you look at it
  120. Almost-Singleton is worst than Singleton
  121. There is only finite amount of decisions your code can make – make them visible to the programmer
  122. Code is not set in stone – experiment with it
  123. Make your assumptions part of INTERFACE
  124. After creating INTERFACE create the implementation
  125. Fix your INTERFACEs frequently
  126. Make your dependencies explicit
  127. Write your method like transaction (fetch -> modify -> commit) /
    Object’s fields may change in unexpected ways during execution of the method
  128. Write your function as transaction that can fail
  129. CONFIG is a STRUCT – cannot be abstract or contain methods /
    CONFIG already established everything there was to establish
  130. Create a separate callback for every phase of reading from SOCKET
  131. Optimize things that happen often – like null checks, loop internals
  132. TIMEOUT does not solve your problems – it postpones your problems and creates new problems
  133. Places where threads are started and stopped are synchronization points
  134. Don’t detach threads that you want to stop
  135. Thread managed cannot modify its managing condition
  136. Detaching thread detaches all its resources
  137. There is entire elephant in the room between the fact that ABORT MAY happen in production and the fact that it HAPPENED in production
  138. BUILDER serves same purpose as CONFIG passed to constructor
  139. Illustrate usage logic of implementation in the INTERFACE
  140. If you can’t make implementation meet INTERFACE expectations introduce another layer
  141. Don’t let error handling be swallowed by accidental complexity – errors are part of the INTERFACE
  142. Choice made in top layers should be propagated into implementation in the form of functions’ names
  143. State of TCP connection/thread/service/network/request is not instantaneously observable /
    No sense in asking about current state of TCP connection/thread/service/network/request before queuing work on it /
    Longer you’re reacting to the state of TCP connection/thread/service/network/request the less you know about the state
  144. Object is observable if you can react to informations about it’s state. Object is instantaneously observable if you can stop the world while reacting to information about it’s state.
  145. TCP connection does not guarantee that your message was received - implement confirmation in your protocol
  146. Notify asynchronously about result from your TCP connection/thread/service/network/request
  147. Clean-up your exceptions and errors before crossing boundaries
  148. When faced with non trivial inheritance tree people tend to panic and revert back to defence programming - this in turn causes avalanche of problems that can only be solved by rewriting major part of the application
  149. If you inherit from class named “CommonSomething” modify it’s methods to be static and remove inheritance
  150. If you really have to make inheritance hierarchy make sure that method calling goes one way - up or down
  151. LAYERS may be relative on outside but must always be absolute in immediate neighbourhood
  152. Path in inheritance tree is a set of LAYERS
  153. Always respect directionality of LAYERS
  154. Every aspect of your code should resemble Direct Acyclic Graph/DAG /
    Functions and calls between them should form DAG /
    Objects and calls between them should form DAG /
    Classes and calls between them should form DAG /
    Packages and calls between them should form DAG /
    Modules and calls between them should form DAG /
    LAYERS and calls between them should form DAG /
    Services and calls between them should form DAG /
    Dependencies between modules should form DAG
  155. When iterating over something complicated create an ITERATOR
  156. Always include tests for failures of file system /
    Don’t assume file system operations always work
  157. Inform about a changes using diff and new state
  158. Imagine that your every function is part of closure of asynchronous task, called from inside some parallel queue, on some super multicore machine, after unspecified period of time, in undetermined order relative to other tasks, with parameters frozen, and in very dynamic and fast environment /
    Remember Command Pattern
  159. Inter-component orchestration cannot be hidden inside components being orchestrated
  160. Name your functions/objects/classes after the choice you make