SOLID: The Software Design and Architecture Handbook
899
172
16MB
English
Pages 377
Year 2020
Report DMCA / Copyright
DOWNLOAD PDF FILE
Table of contents :
Intro
Why did you decide to write this book?
Why learn software design and architecture?
The Domain-Driven Developer
Software design is taking an educated guess at the future
Thank you
1. The World of Software Design and Architecture
Introduction
Software development is a young profession
First Principles
Chapter goals
Let's talk about you
The goal of software
Users' technical expectations vary based on their needs
System quality attributes (SQAs)
How do we design a project to be successful?
Aren't all system quality attributes essential?
What is architecture?
Why is software architecture important?
What is software design?
Levels of design
The Software Design and Architecture Stack & Roadmap
Resource: The Stack
Resource: The Map
Step 1: Clean code
Clean Code
Step 2: Programming paradigms
Step 3: Object Oriented Programming and Domain Modeling
Step 4: Design Principles
Step 5: Design patterns
Step 6: Architectural Principles
Step 7: Architectural Styles
Step 8: Architectural Patterns
Step 9: Enterprise patterns
Chapter conclusion
References
2. TypeScript
Introduction to TypeScript
Chapter goals
Primary goals of TypeScript
All JavaScript is valid TypeScript
TypeScript types
Convenient Implicit Types
Explicit Types
Structural Types
Nominal typing
Duck typing
Ambient types
Migrating to TypeScript
Typescript still emits errored JavaScript code
Why JavaScript doesn't scale
When to use TypeScript
Categories of hard software problems
1 - The performant system problem
2 - The embedded system problem
3 - Complex domain problem
Object-Oriented JavaScript
Code size
Production software vs. pet projects
Lack of Unit Tests
Startups
Working on Teams
Large teams
Communicating patterns & implementing design principles
Smaller teams & coding styles
Frameworks
React
Angular
Summary on when to use TypeScript
Getting started with TypeScript
Prerequisites
Initial Setup
Setup Node.js package.json
Add TypeScript as a dev dependency
Install ambient Node.js types for TypeScript
Create a tsconfig.json
Create the src/ folder and create our first TypeScript file
Compiling our TypeScript
Our compiled code
Useful configurations & scripts
Cold reloading development script
Creating production builds
Production startup script
View the Starter Project source
Scripts Recap
TypeScript Language Features
Basic types
Primitive Types
Number
String
Boolean
Arrays
Object-Oriented Programming Features
Classes
Class inheritance
Static properties
Instance variables
Access Modifiers
Readonly Modifier
Interfaces
Classes implementing interfaces
Interfaces extending interfaces
Generics
Convenience Generic
Abstract classes
Special types
Type assertions
The ``type'' keyword
Type Aliases
Union Type
Intersection Type
Enum
Any
Void
Inline & Literal Types
Type Guards
Typeof Guard
Instanceof Guard
In Guard
Chapter Summary
Resources
References
3. Clean Code
Introduction | Clean code is your grip strength
Chapter Goals
Understanding clean code
Clean code is an overloaded term
What the community thinks about clean code
Community opinions
What the experts think about clean code
How does unclean code get written?
Two laws of software development maintenance
Why it's hard to learn clean code
Reason 1 — Humans are complex
Reason 2 — It's hard to deconstruct human psychology
Reason 3 — Trade skills are acquired through mentorship
The three pillars of clean code
? Developer mindset
⚙️ Coding conventions
?? Skills & knowledge
Section One - Developer mindset
Summary
Software Craftsmanship
A brief history of software development
Programming picking up speed (50s)
The software crisis of the 60s-80s
Dot-com bubble, OOP, and Extreme Programming (1995 – 2001)
Agile (2001 — today)
The Agile Manifesto
The (Misled) Era of Agile
Why didn't Agile work?
Software Craftsmanship (2006 — today)
The Software Craftsmanship Manifesto
Back to Basics (XP)
Craftsmanship: Professionalism in software development
Definition
Are you a software craftsman?
Art, science, engineering practice, or trade
Understanding the manifesto
Not only working software, but also well-crafted software
Not only responding to change, but also steadily adding value
Not only individuals and interactions, but also a community of professionals
Not only customer collaboration, but also productive partnerships
Your homework
To write well-crafted software…
To steadily add value…
Engage in the community…
Consider yourself a partner…
Growth
Two mindsets
Fixed mindset
Growth mindset
You need to have a growth mindset as a software developer
Fixed mindset as a developer
Growth mindset as a developer
Final thoughts
Life is more fun
Craftsmanship requires a growth mindset
Design Thinking
Structure vs. Developer Experience
Human-Centered Design
What is it?
How is this helpful for us?
Knowledge in the Head vs. World
Knowledge in the Head
Knowledge in the World
Why is this helpful for us (developers)?
Affordances
What are they?
Real-life examples
Why is this useful?
Affordances in software development
How to do affordances well
Signifiers
What are they?
Real-life examples
Why is this useful?
Signifiers in software development
How to do signifiers well
Constraints
About constraints
Real-life examples (physical constraints)
Real-life examples (cultural constraints)
Real-life examples (semantic constraints)
Real-life examples (logical constraints)
Constraint examples in software development
How to use constraints well
Mappings
What are they?
Real-life examples
Why is this useful?
How to do mappings well
Mappings in software development
Feedback
What is it?
Types of errors
Real-life examples
Why is this useful?
Feedback in software development
How to do feedback well
Conceptual Models
What are they?
Real-life examples
Why is this useful?
Conceptual models in software development
How to do conceptual models well
Testing your code for cleanliness
Summary on Design Thinking
Section Two - Clean coding conventions
Summary
About this section
Conventions we'll cover
Project planning
Notes
Documentation
Organizing things
Why code organization matters
Practical naming
Principles
Organizing and context
How to settle design arguments
Formatting & style
Objective readability truths
Whitespace
Use obvious spacing rules
Keep code density low
Break horizontally when necessary
Prefer smaller files
Consistency
Capitalization
Whitespace rules
Storytelling
Newspaper Code and the Step-down Principle
Maintaining a consistent level of abstraction
Code should descend in abstraction towards lower-level details
Keeping related methods close to each other
Enforcing formatting rules with tooling
ESLint
Prettier
Husky
Comments
Code explains what and how, comments explain why
Comments clutter code
Turning comments into clear, explanatory, declarative code
Bad comments
When to write comments
Demonstration
Example: Adding additional context
Relationship to Human Centered Design
The relationship between comments & human centered design
More doors examples
Naming things
The seven principles of naming
The seven principles of naming
Summary
1 - Consistency & uniqueness
Consistency
Uniqueness
Best practices
2 - Understandability
Knowledge in the world
Representing real-world concepts
Best Practices
3 - Specificity
Over-specifying
Under-specifying
Best practices
4 - Brevity
Compression vs. Context
The law, reiterated
Best practices
5 - Searchability
Best practices
6 - Pronounceability
Best practices
7 - Austerity
Not everyone has the same sense of humor as you
Don't use temporarily relevant concepts
Best practices
Errors and exception handling
Relevant links
Testing
BDD & TDD
Resources
Unit Tests
Refactoring
Architecture basics
Section Three - Skills & knowledge
Summary
Details
Extreme Programming
Tools in your toolbox
Infra
Know tools to deploy websites
Know a scripting language
Backend development
Know a general purpose language
Know a SQL database
Know an ORM
Know a noSQL database
Frontend development
Know a state management library
Know a view-layer library or framework
Know a CSS pre-processor
Software development approaches
Know how to gather requirements and plan a project
Know how to write tests
Know how to consistently provide value
Software Quality
Structural quality
Report on programming errors
Software quality thread
Code Smells
Code smells depend on the language, context, and developer
Anti Patterns
Anti-patterns are not determinate
Anemic Domain Models vs. Entity Component System
DRY vs Overengineering
Overengineering
Cyclamatic Complexity
Optimizing code
Absolute and relative complexity
Best practices, principles, and patterns
Guiding principles for clean coders
Principle #1 - Care deeply about the project and the domain
Principle #2 - Aim to empower teammates and future maintainers
Principle #3 - Humans > computers
Principle #4 - Conventions and patterns are helpful but they are secondary to the needs of your users and future maintainers
Where to go from here
Resources
References
4. Programming Paradigms
The three organizational archetypes
5. Object-Oriented Programming & Domain Modeling
6. Design Principles
SOLID
Single Responsibility Principle
Open-Closed Principle (OCP)
Liskov Substitution Principle (LSP)
Interface Segregation Principle
Dependency Inversion Principle (DIP)
Terminology
Components
Dependency Injection
Dependency Inversion
Using a mock object
The primary wins of Dependency Inversion
Inversion of Control & IoC Containers
Design by Contract (DBC)
Separation of Concerns
Related blog posts
CQS (Command Query Separation)
Principle of Least Surprise
Law of Demeter (Principle of Least Knowledge)
Composition over Inheritance
YAGNI
KISS (Keep It Simple, Silly)
DRY (Don't Repeat Yourself)
The Four Primary Object-Oriented Design Principles
Composition over inheritance
Aim for shallow class hierarchies
Encapsulate what varies
Program to interfaces, not to implementations
Relationship to Ports and Adapters architecture
Relationship to Dependency Inversion Principle
The Hollywood Principle
All software is composition
Design patterns are complexity
Know of them, but know when you need them
Separation of Concerns
Example: overloaded controller
Separation of concerns
Cross-cutting concerns
Principle of Least Surprise
Strive for loose coupling between objects that interact
Principle of Least Resistance
Tell, Don't Ask
7. Design Patterns
Factory pattern
8. Architectural Principles
Component principles
Reuse-Release Equivalence Principle
Common closure principle (CCP)
The Common Reuse Principle (CRP)
Stable Components
Volatile Components
Policy
Conway's Law
The Dependency Rule
Boundaries
Coupling & cohesion
9. Architectural Styles
Structural
Component-based architectures
Layered Architectures
Monolithic architectures
Message-based
Event-Driven architectures
Publish-Subscribe architectures
Distributed
Client-server architectures
Peer-to-peer architectures
10. Architectural Patterns
Clean architecture
Layers
Domain layer
Application layer
Infrastructure layer
Adapter layer
Similar architectures
Ports & Adapters
Vertical-slice architecture
Domain-Driven Design
Event Sourcing
Notes
Everything I've recorded about Event Sourcing so far
About this
Internal links
Progression to Event Sourcing
Sam Hotoum's Event Sourcing w/ TypeScript repo
Why Event Sourcing?
State management code can get messy
This is how we're ensuring that we have event handlers
Projections and deserializing events happens like this!
Copy of Best Places to Learn CQRS, Event Sourcing
11. Building a Real-World DDD app
About this chapter
Chapter goals
Domain-Driven Design
Ubiquitous Language
Implementing DDD & ensuring domain model purity
DDD addresses the shortcomings of MVC
Slim (Logic-less) Models
Pick your object-modeling poison
Concerns of the unspecified layer in MVC
Undesirable side-effects with a lack of a domain model
Model behavior and shape
Technical Benefits
Technical Drawbacks
Alternatives to DDD
DDD Building Blocks
Entities
Value Objects
Aggregates
Domain Services
Repositories
Factories
Domain Events
Architectural concepts
Subdomains
Types of subdomains
Benefits of using subdomains
Bounded Contexts
Deployment as a Modular Monolith
Deployment as Distributed Micro-services
How to plan a new project
Imperative design
Imperative design approaches are for small, simple CRUD applications
Dimensions that influence the design approach we should take
Use-case driven design
Use cases & actors
Applications are groupings of use cases
A use case is a command or a query
Use case artifacts
Functional requirements document business logic
Given-When-Then
Parallels with API-first design
Steps to implement use case design
Planning with UML Use Case Diagrams
1 — Identifying the actors
2 — Identifying the actor goals
3 — Identifying the systems we need to create
4 — Identifying the use cases for each role
Roles, boundaries, and Conway's Law in Use Case Design
Role dictates responsibility
Boundaries
Using subdomains to define logical boundaries in DDDForum
Conway's Law
Summary on use case diagrams
Event Storming
Why we need event storming
How to conduct an event storming session
Step 0 — Create a legend of all the event storming constructs
Step 1 — Brainstorm Domain Events
Step 2 — Create the Commands that cause Domain Events
Step 3 — Identify the Aggregate that the Command is executed against and the resulting Domain Event
Step 4 — Create Subdomain and Bounded Context boundaries
Step 5 — Identify Views & Roles
Step 6 (Optional) — Identify rules/policies
Event Modeling
Building DDDForum
Project architecture
Decision 1: We're going to use Domain-Driven Design
Decision 2: We're going to use a Layered Architecture
Decision 3: We're going to deploy a Modular Monolith
Decision 4: We're going to use CQRS (Command Query Response Segregation)
Decision 5: We're not going to use Event Sourcing
Starting with the domain models
Modeling a User Aggregate
Emitting Domain Events from a User Aggregate
Writing Domain Events
Building a Domain Events Subject
Marking an Aggregate that just created Domain Events
How to signal that the transaction completed
How to register a handler to a Domain Event?
Who dictates when a transaction is complete?
Feature 1: Creating a Member
Issuing an API request
Application Services/Use Cases
Use case interface
Adding the Command (request object)
Fork in the road: Transaction Script vs. Domain Model
Handling errors as domain concepts
Summary on Use Cases/Application Services
Inside the CreateUser use case transaction
Using an Express.js Route Handler to direct the request
Handling the API request with an API Controller
Invoking the Application Service / Use Case
Saving the Aggregate with Sequelize
Notifying subscribers and dispatching Domain Events from Sequelize Hooks
Chaining the CreateMember command from the Forum subdomain
Feature 2: Upvote a post
Understanding voting domain logic
Gherkin test specifications
Handling the upvote post request
Inside the Upvote Post use case
Aggregate design principles
Rule #1 - All transactions happen against Aggregates
Rule #2 - Design Aggregates to be as small as possible
Rule #3 - You may not alter entities within the aggregate's transaction boundary without going through the aggregate
Using a Domain Service
Implementing the Upvote Post logic in a Domain Service
Persisting the upvote post operation
Signaling relationship changes
Persisting complex aggregates using database transactions
Feature 3: Get Popular Posts
Read models
Modeling read models as domain concepts
Modeling read models as raw data
Handling an API request to Get Popular Posts
Using a repository to fetch the read models
Implementing pagination
Where to go from here?
Resources
References