This section is about how to use the basic block of a language in order to create high order component.
Art is for expression
Science is for exploration
Engineering is for invention
Design is for Communication
There is three kinds of application
- Transformational programs: scheduling is determined by the program - compute results from a given set of inputs; typical examples are compilers or numerical computation programs. (Stream & Batch Analytics)
- Interactive - programs interact at their own speed (pace) with users or with other programs; from a user point of view a time-sharing system is interactive.
- Reactive programs - Activate in response to external demands - ie scheduling is determined by the environment, not by the program itself. only work in response to external demands and mostly deal with accurate interrupt handling.
Complex applications usually require establishing cooperation between the three kinds of programs.
Code is easy,
State is hard
There are two ways of constructing a software design:
- One way is to make it so simple that there are obviously no deficiencies, and
- The other way is to make it so complicated that there are no obvious deficiencies.
The first method is far more difficult.
If it's your decision, it's design; if not, it's a requirement.
I wrote the library and I still had to Google it.
We build our computer (systems) the way we build our cities: over time, without a plan, on top of ruins.
Programming is often more about using existing packages than about writing original code of one’s own.
The function of good software is to make the complex appear to be simple.
One view of good system design is that it can’t be found on a whiteboard, in a Visio document, or any other static resource. It comes from a system’s ability to evolve:
- to grow into new requirements,
- to leverage new hardware and development practices,
- to incrementally morph itself into the unknown.
A good design is not the one that correctly predicts the future, it’s one that makes adapting to the future affordable.
Learning the art of programming, like most other disciplines, consists of first learning the rules and then learning when to break them.
- No primitive obsession. Code that relies too heavily on basic types instead of custom abstractions (object) in order to model its world is hard to understand and maintain.
Limit integration by limiting the number of module
- No lost of information. Example: No date transformation to String in code (Except when creating a file)
If you put a spoonful of sewage in a barrel full of wine, you get sewage
No matter how good the overall application, if one part doesn't work the whole application gets tarred with the bad brush. perceptions are more important than reality.
Data and code
Static vs Runtime
Our intellectual powers are rather geared to master static relations and that our powers to visualize processes evolving in time are relatively poorly developed. For that reason we should do (as wise programmers aware of our limitations) our utmost to shorten the conceptual gap between the static program and the dynamic process, to make the correspondence between:
- the program (spread out in text space)
- and the process (spread out in time)
as trivial as possible.
- Write programs for people, not computers.
- A program should not require its readers to hold more than a handful of facts in memory at once.
- Make names consistent, distinctive, and meaningful.
- Make code style and formatting consistent.
- Let the computer do the work.
- Make the computer repeat tasks.
- Save recent commands in a file for re-use.
- Use a build tool to automate workflows.
- Make incremental changes.
- Work in small steps with frequent feedback and course correction.
- Use a version control system.
- Put everything that has been created manually in version control.
- Don't repeat yourself (or others).
- Every piece of data must have a single authoritative representation in the system.
- Modularize code rather than copying and pasting.
- Re-use code instead of rewriting it.
- Plan for mistakes.
- Add assertions to programs to check their operation.
- Use an off-the-shelf unit testing library.
- Turn bugs into test cases.
- Use a symbolic debugger.
- Optimize software only after it works correctly.
- Use a profiler to identify bottlenecks.
- Write code in the highest-level language possible.
- Document design and purpose, not mechanics.
- Document interfaces and reasons, not implementations.
- Refactor code in preference to explaining how it works.
- Embed the documentation for a piece of software in that software.
- Use pre-merge code reviews.
- Use pair programming when bringing someone new up to speed and when tackling particularly tricky problems.
- Use an issue tracking tool.