SOLID Principles
The SOLID principles are a set of five foundational guidelines in object-oriented design, aimed at creating software that is maintainable, scalable, and robust. Adhering to these principles promotes cleaner architecture, reduces technical debt, and enhances testability.Single Responsibility Principle (SRP).
A class should have one, and only one, reason to change.Each class or module should encapsulate a single responsibility or function. This separation of concerns reduces complexity and improves maintainability.
Best Practice: Decompose complex classes into smaller, purpose-driven components. Avoid mixing unrelated functionality within a single class.
Open/Closed Principle (OCP).
Software entities (classes, modules, functions) should be open for extension but closed for modification.Design systems so that behavior can be extended without altering existing source code. This is typically achieved via abstraction and polymorphism.
Best Practice: Leverage inheritance, interfaces, or composition to enable new features without modifying existing implementations.
Liskov Substitution Principle (LSP).
Subtypes must be substitutable for their base types without altering the correctness of the program.Derived classes should honor the contract established by their base class. Substitution should not introduce unexpected behavior or side effects.
Best Practice: Avoid overriding methods in ways that violate assumptions made by the base type. Ensure consistent behavior across all derived types.
Interface Segregation Principle (ISP).
Clients should not be forced to depend on interfaces they do not use.Design narrow, role-specific interfaces rather than monolithic ones. This minimizes the impact of changes and aligns interfaces with specific client needs.
Best Practice: Split large interfaces into smaller, more focused abstractions tailored to specific contexts or use cases.
Dependency Inversion Principle (DIP).
High-level modules should not depend on low-level modules. Both should depend on abstractions.System components should rely on abstractions rather than concrete implementations. This decouples the system and facilitates easier testing and flexibility.
Best Practice: Apply dependency injection techniques to supply dependencies, and define stable interfaces for critical components.
DRY Principle
DRY stands for Don’t Repeat Yourself, a fundamental software engineering principle aimed at reducing duplication within a codebase. It encourages reusability and abstraction to minimize redundancy and improve maintainability.Definition
Every piece of knowledge must have a single, unambiguous, authoritative representation within a system. In practice, this means that logic, behavior, or configuration should not be duplicated. Repetition often leads to inconsistencies, increases the surface area for bugs, and makes future changes more error-prone.Benefits
- Improved Maintainability: Changes need to be made in only one place.
- Reduced Errors: Less duplication means fewer opportunities for introducing bugs.
- Increased Clarity: Consolidated logic improves readability and understanding of the system.
- Better Scalability: Reusable components are easier to extend and adapt.
Common Violations
- Duplicated business logic scattered across multiple classes or modules.
- Copy-pasted code blocks instead of shared functions.
- Repeating the same configuration or constants in multiple files.
Best Practices
- Abstract Repetitive Logic: Extract common functionality into functions, classes, or modules.
- Centralize Constants and Configurations: Use configuration files or environment variables.
- Use Templates: In web or UI development, utilize templating systems to avoid markup duplication.
- Leverage Inheritance and Composition: In object-oriented design, avoid rewriting similar behaviors across classes.
Note: Avoid over-abstracting early. Premature abstraction can lead to unnecessary complexity. Let repetition emerge before generalizing.
Working with Jupyter Notebooks
When running example notebooks, you might want to prevent git from tracking your notebook output changes to avoid accidentally committing over the examples.Ignore notebook changes
Run once after cloning:This tells git to ignore any changes to notebooks in the examples directory.
Auto-Generate documentation
To auto-generate your documentation, you can follow these steps:Generate documentation from docstrings
Run
pdoc3 to save .md files to the ./docs/reference folder with the following command:Generate mdx files
Run
gen_api_docs.py to save .mdx files to the ./docs/api folder with the following command:
