2.1 Programming Principles
← Technical Skills | Home | Next: 2.2 Data Structures →
Control Flow and Boolean Algebra
Control flow describes how execution progresses from one command to the next in software. Basic structures: - Sequence: Line-by-line execution. - Branch: if-else, switch, goto (goto has been considered harmful by many computer scientists, including Dijkstra). - Loop: for, while, do-while, foreach, infinite loops. - Function calls: Execution jumps to function code and returns to the calling point.
Boolean algebra was introduced by George Boole in his books The Mathematical Analysis of Logic (1847) and An Investigation of the Laws of Thought (1854). It differs from elementary algebra in two ways: variables are truth values (true and false, denoted by 1 and 0) rather than numbers, and it uses logical operators—AND (∧ conjunction), OR (∨ disjunction), and NOT (¬ negation)—rather than arithmetic operators. Core laws include associativity, commutativity, distributivity, De Morgan's laws (¬(A ∧ B) = ¬A ∨ ¬B), and complementation (A ∧ ¬A = 0, A ∨ ¬A = 1). Claude Shannon applied it to switching circuit design in the 1930s, laying the foundation of digital electronics.
Object-Oriented Programming (OOP)
Four core concepts: - Encapsulation: Binding data and the methods that operate on it together, hiding internal implementation. - Inheritance: Subclasses inherit properties and methods from parent classes for code reuse (use with caution—see Composition over Inheritance). - Polymorphism: The same interface, different implementations. Different types of objects respond to the same message with different behaviors. - Abstraction: Exposing only the essential interface while hiding complex implementation details.
SOLID Principles
A mnemonic acronym for five design principles introduced by Robert C. Martin in his 2000 paper Design Principles and Design Patterns. The acronym was coined around 2004 by Michael Feathers.
| Principle | Description |
|---|---|
| SRP—Single Responsibility | There should never be more than one reason for a class to change. Every class should have only one responsibility. → Maintainability, testability, flexibility. |
| OCP—Open–Closed | Software entities should be open for extension, but closed for modification. → Extensibility, stability. |
| LSP—Liskov Substitution | Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it. Subclasses must adhere to the contract defined by the superclass. → Polymorphism, reliability, predictability. |
| ISP—Interface Segregation | Clients should not be forced to depend upon interface methods that they do not use. Large interfaces should be broken into smaller, specific ones. → Decoupling, avoiding unnecessary dependencies. |
| DIP—Dependency Inversion | Depend upon abstractions, not concretes. High-level modules should not depend on low-level modules; both should depend on abstractions. → Loose coupling, flexibility, maintainability. |
GRASP Patterns
General Responsibility Assignment Software Patterns, first published by Craig Larman in Applying UML and Patterns. Larman states that "the critical design tool for software development is a mind well educated in design principles. It is not UML or any other technology."
| Pattern | Description |
|---|---|
| Information Expert | Assign responsibility to the class that has the information needed to fulfill it. |
| Creator | Assign class B the responsibility to create object A if B contains, records, closely uses A, or has the initializing information for A. |
| Controller | Assign the responsibility of dealing with system events to a non-UI class that represents the overall system or a use case scenario. The controller should delegate work; it should not do much work itself. |
| Low Coupling | Lower dependency between classes. A change in one class should have a lower impact on other classes, increasing reuse potential. |
| High Cohesion | Keep objects appropriately focused, manageable, and understandable. Responsibilities of a given element should be strongly related and highly focused. |
| Polymorphism | When related alternatives or behaviors vary by type, assign responsibility for the behavior—using polymorphic operations—to the types for which the behavior varies. |
| Pure Fabrication | A class that does not represent a concept in the problem domain, specially made up to achieve low coupling and high cohesion (corresponds to a "service" in Domain-Driven Design). |
| Indirection | Assign the responsibility to an intermediate object to mediate between other components so that they are not directly coupled. |
| Protected Variations | Identify points of predicted variation or instability; assign responsibilities to create a stable interface around them. |
Functional Programming
Functional programming treats computation as the evaluation of mathematical functions, emphasizing:
- Pure functions: Given the same input, always return the same output, with no side effects (no modification of external state, no I/O, no network calls). This is the foundation of testability and predictability.
- Immutability: Data structures that cannot be modified after creation. Modification operations return new copies rather than mutating in place, eliminating concurrency bugs from shared mutable state.
- Recursion: Replacing iterative loops with self-calling functions to handle decomposable repeating patterns.
- Higher-order functions: Functions that can be passed as arguments and returned as values—e.g., map, filter, reduce.
- Function composition: Combining simple functions into complex behavior: f(g(x)).
Functional programming is a subset of declarative programming.
Declarative vs. Imperative Programming
| Dimension | Imperative | Declarative |
|---|---|---|
| Concern | How to do it | What to do |
| Abstraction level | Lower, closer to machine execution | Higher, closer to human intent |
| Example | for (i=0; i<arr.length; i++) { sum += arr[i]; } |
SQL SELECT SUM(price) FROM orders |
| Subset | Procedural programming | Functional programming |
These are not opposing styles—most programs contain both. UI frameworks (React, Flutter) naturally lean declarative; algorithm implementation leans imperative. Procedural programming is a subset of imperative programming that uses subroutines (procedures, which don't return values). Functional programming is a subset of declarative programming that uses subroutines (functions, which do return values and aim to have minimal side effects).
Sources
- Wikipedia — Control flow: https://en.wikipedia.org/wiki/Control_flow
- Wikipedia — Boolean algebra: https://en.wikipedia.org/wiki/Boolean_algebra
- Wikipedia — SOLID: https://en.wikipedia.org/wiki/SOLID
- Wikipedia — GRASP (object-oriented design): https://en.wikipedia.org/wiki/GRASP_(object-oriented_design)
- Anthony Zotti — Declarative vs Imperative Programming: http://amzotti.github.io/programming%20paradigms/2015/02/13/what-is-the-difference-between-procedural-function-imperative-and-declarative-programming-paradigms/
← Technical Skills | Home | Next: 2.2 Data Structures →