Skip to content

Developing

These principles are the non-negotiable foundation of the system.

They define how we think before we decide how we implement.

All other guidelines refine or expand these principles. None override them.


Correctness is the highest priority in all software design.

A system that is fast, elegant, or flexible but incorrect is not useful.

  • Business rules must always be enforced explicitly
  • Edge cases must be handled deliberately
  • Invalid states should be unrepresentable where possible
  • Silent failures are unacceptable in core flows

If correctness conflicts with performance, flexibility, or simplicity, correctness wins.


Simplicity is the primary mechanism for controlling complexity.

Simple systems are:

  • easier to understand
  • easier to debug
  • easier to extend
  • easier to test
  • Prefer straightforward solutions over clever ones
  • Avoid unnecessary abstractions
  • Avoid speculative design
  • Do not introduce patterns without a real need

If two solutions are correct, choose the simplest one.


Software should clearly express its intent.

Hidden behavior increases cognitive load and leads to unexpected side effects.

  • Avoid “magic” framework behavior where possible
  • Prefer explicit calls over convention-based execution
  • Make dependencies visible
  • Make side effects obvious

If behavior is not visible in the code, it is a liability.


Clear boundaries between architectural layers are essential.

Without boundaries, systems degrade into tightly coupled, unmaintainable structures.

  • Domain must not depend on infrastructure
  • Infrastructure must not leak into domain
  • Each layer has a single responsibility
  • Communication happens through well-defined contracts

Dependencies always point inward.


State is a major source of complexity and bugs.

Immutability reduces unpredictability and improves reasoning.

  • Prefer immutable data structures
  • Avoid shared mutable state
  • Treat mutation as an exception, not a norm
  • Design with transformation over modification

If a value does not need to change, it must not change.


Systems should be designed as compositions of transformations.

This improves testability and clarity.

  • Prefer pure functions where possible
  • Isolate side effects at system boundaries
  • Compose behavior from small units
  • Minimize stateful logic

Side effects belong at the edges, not in the core.


The structure of the system should reflect business capabilities, not technical concerns.

  • Organize code by feature, not by type
  • Each feature owns its full stack (domain, application, infrastructure, presentation)
  • Avoid global “service/controller/repository” buckets
  • Improve cohesion within features

Code is grouped by why it exists, not what it is.


Frameworks are tools, not foundations.

The architecture defines the system. Frameworks implement it.

  • Business logic must not depend on frameworks
  • Frameworks are confined to adapters
  • Replaceability is a design goal
  • Framework usage should be minimal and deliberate

Frameworks serve the architecture, not the other way around.


Tests are a tool to reduce uncertainty, not to maximize coverage metrics.

  • Test behavior, not implementation details
  • Prefer integration tests for real confidence
  • Use unit tests for complex logic only
  • Avoid over-mocking
  • Avoid testing trivial code

We test what we cannot afford to break.


Performance is important, but must be grounded in reality.

  • Do not optimize prematurely
  • Measure before optimizing
  • Prefer clarity over micro-optimizations
  • Focus optimization on real bottlenecks

If it is not measured, it is not a problem yet.


A system must feel predictable.

Inconsistent patterns increase cognitive load more than suboptimal patterns.

  • Follow established conventions
  • Prefer consistency over personal style
  • Avoid introducing new patterns without justification
  • Standardize approaches across features

A consistent system is easier to understand than a perfect one.


No principle is absolute in isolation except correctness and simplicity.

  • Use FP, SOLID, Clean Code as tools—not doctrines
  • Break rules when justified by clarity or necessity
  • Avoid over-engineering in the name of purity
  • Evaluate trade-offs explicitly

Principles guide decisions; they do not replace thinking.


These principles define how we build software:

  • Correct
  • Simple
  • Explicit
  • Well-bounded
  • Immutable where possible
  • Functional where practical
  • Feature-oriented
  • Framework-independent
  • Tested for confidence
  • Performance-aware but not premature
  • Consistent
  • Pragmatic

Everything else is an implementation detail.