Skip to content

Side 57

Software
Engineering

A study of software as a long-lived engineered artifact. Software engineering connects requirements, architecture, code, verification, deployment and maintenance under continuous change.

requirement→design→implementation→verification→evolution
06lifecycle lenses
05design questions
05quality dimensions
57Side

Software begins with a problem, not a feature list.

Requirements define what must be true for users and systems, along with the constraints under which the software must operate.

01 · User

Who needs something?

Actor + context.

Different users can have conflicting goals.

02 · Outcome

What job must succeed?

Observable result.

Outcome-oriented requirements resist premature implementation choices.

03 · Constraint

What limits the solution?

Latency, privacy, platform, cost?

Nonfunctional constraints often shape architecture more than feature count.

04 · Acceptance

How will success be tested?

Concrete behavior.

Testable acceptance conditions reduce ambiguity between intent and implementation.

05 · Change

What is likely to evolve?

Design for change, not prophecy.

Likely volatility should influence modular boundaries.

Architecture decides where change is allowed to propagate.

Boundaries, interfaces and ownership determine whether one change stays local or spreads across the system.

Module

Hide internal decisions.

Strong modules expose small stable interfaces.

Coupling

How dependent are components?

High coupling increases change propagation and testing burden.

Cohesion

Do responsibilities belong together?

High cohesion makes components easier to reason about.

Interface

Contract across a boundary.

Interfaces should reveal what consumers need while hiding implementation detail.

State

Where does mutable information live?

State placement strongly affects concurrency, reliability and testability.

Dependency

Who is allowed to know whom?

Dependency direction influences how easily components can be replaced.

Code quality is largely about reducing future reasoning cost.

Readable structure, explicit contracts and bounded side effects make behavior easier to change safely.

Naming

Make intent visible.

Good names reduce the amount of context a reader must reconstruct.

Function

Keep responsibilities narrow.

Small coherent functions are easier to test and compose.

State

Control mutation.

Unbounded shared mutable state creates hidden interactions.

Error

Represent failure explicitly.

Error handling should preserve enough context for recovery or diagnosis.

Review

Use another mind.

Code review catches defects and spreads system knowledge beyond one author.

Tests are executable claims about behavior.

Different tests isolate different risks.

LevelScopeStrengthRisk
UnitSmall componentFast, localized feedbackCan miss integration failure
IntegrationSeveral componentsTests boundariesMore setup and slower feedback
End-to-endWhole user pathHigh realismSlower and more brittle
PropertyInvariant over many inputsBroad behavioral coverageRequires good property definition
RegressionPreviously failing casePrevents recurrenceCan accumulate noise if poorly maintained

Deployment is part of software design.

A change is not complete until it can be released, observed and reversed safely.

Build

Create reproducible artifacts.

Dependency and environment control reduce “works on my machine” drift.

CI

Integrate continuously.

Automated checks catch incompatibility close to the change that caused it.

Deploy

Move artifact into service.

Progressive rollout limits blast radius.

Observe

Measure real behavior.

Logs, metrics and traces connect production symptoms to causes.

Rollback

Restore a known-good state.

Reversibility changes the risk of deployment decisions.

Migration

Change state safely.

Database and protocol migrations often require compatibility across versions.

Most software cost arrives after version one.

Maintenance, dependency changes, user growth and shifting requirements continuously reshape the system.

Correct

Repair behavior that violates requirements.

Adapt

Respond to new platforms, dependencies and environments.

Extend

Add new capabilities without destroying existing contracts.

Refactor

Improve internal structure without intentionally changing external behavior.

Retire

Remove obsolete code, interfaces and dependencies deliberately.

Software EngineeringIan Sommerville · lifecycle foundation
Clean ArchitectureRobert C. Martin · boundaries and dependencies
Designing Data-Intensive ApplicationsKleppmann · system design
AccelerateForsgren, Humble & Kim · delivery performance