Skip to main content

Glossary

Abstraction

Abstraction hides implementation detail behind a stable interface so callers depend on what a component does, not how it does it. In object-oriented and functional code it is realised through interfaces, abstract types, and pure functions. Good abstractions reduce coupling and let implementations change without breaking clients.

Acceptance Test

An acceptance test verifies that a feature satisfies a business requirement from the user's perspective, expressed in terms of observable behaviour rather than internal state. It is typically written in a Given/When/Then form and executed against a running system. It answers "did we build the right thing?" rather than "did we build the thing right?".

Aggregate

In Domain-Driven Design an aggregate is a cluster of domain objects treated as a single consistency boundary, accessed only through its aggregate root. All invariants inside the aggregate must hold after every transaction. Aggregates should be kept small to reduce contention and to map cleanly onto a single database transaction.

API (Application Programming Interface)

An API is the contract through which one piece of software is invoked by another, defining operations, inputs, outputs, and error semantics. Well-designed APIs are consistent, evolvable, and explicit about versioning and failure modes. REST, gRPC, and GraphQL are common styles for networked APIs.

Backward Compatibility

A change is backward compatible if existing clients continue to work without modification after it is deployed. Adding optional fields or new endpoints is typically backward compatible; removing fields or tightening validation usually is not. Semantic Versioning encodes this contract in the MAJOR version number.

Bounded Context

A bounded context is an explicit boundary within which a particular domain model and its ubiquitous language are consistent and unambiguous. The same term (for example "Account") can mean different things in different bounded contexts, and integration between them happens through well-defined contracts. It is the central strategic pattern of Domain-Driven Design.

Cache

A cache stores the result of an expensive computation or fetch so that future requests for the same data are served faster. Caches trade freshness for latency and require an invalidation strategy (TTL, write-through, write-behind, or explicit eviction). The two classically hard problems are cache invalidation and naming things.

Circuit Breaker

A circuit breaker is a resilience pattern that stops calls to a failing remote dependency once an error threshold is crossed, failing fast instead of piling up blocked threads. After a cooldown it allows a few trial calls (half-open state) to test recovery before fully closing. Libraries such as Resilience4j implement it as a state machine with closed, open, and half-open states.

Clean Architecture

Clean Architecture organises code into concentric layers where dependencies point only inward, toward business rules, and outward concerns such as UI, database, and frameworks are kept at the edges. The domain layer has no knowledge of frameworks, so business logic is testable in isolation. It is one of several names for the same dependency-rule idea, alongside Hexagonal and Onion architecture.

Code Smell

A code smell is a surface symptom in source code that often indicates a deeper design problem, such as long methods, large classes, duplicated logic, or feature envy. Smells are heuristics, not defects: they suggest where refactoring may pay off. The term was popularised by Kent Beck and Martin Fowler.

Cohesion

Cohesion measures how strongly the responsibilities of a single module belong together. High cohesion means a module does one well-defined job; low cohesion means it mixes unrelated concerns. High cohesion paired with low coupling is a primary goal of good modular design.

Concurrency

Concurrency is the composition of independently executing tasks that may overlap in time, as opposed to parallelism, which is their simultaneous execution. Concurrency is about structure (dealing with many things at once); parallelism is about execution (doing many things at once). Correct concurrent code requires careful management of shared mutable state.

Continuous Integration (CI)

Continuous Integration is the practice of merging developers' work into a shared mainline frequently, with each merge triggering an automated build and test run. It surfaces integration conflicts early and keeps the mainline releasable. CI is a prerequisite for Continuous Delivery and Continuous Deployment.

Coupling

Coupling measures the degree of interdependence between modules; the more one module must know about another's internals, the tighter the coupling. Loose coupling lets modules change independently and be tested in isolation. Dependency inversion and well-defined interfaces are the main tools for reducing coupling.

Dependency Injection (DI)

Dependency Injection supplies a component's collaborators from the outside rather than having the component construct them itself. This inverts control over object creation, improving testability and configurability. Constructor injection is the preferred form because it makes dependencies explicit and supports immutability.

Domain-Driven Design (DDD)

Domain-Driven Design is an approach that places the business domain and a shared ubiquitous language at the centre of software design. Its strategic patterns (bounded contexts, context maps) handle large-scale structure, while tactical patterns (entities, value objects, aggregates, repositories) shape the model. It was introduced by Eric Evans in 2003.

Encapsulation

Encapsulation bundles data with the operations that act on it and restricts direct access to internal state. It lets an object enforce its own invariants, so callers cannot put it into an invalid configuration. Violations such as exposing mutable internals erode the object's ability to guarantee correctness.

Entity

In Domain-Driven Design an entity is an object defined by a continuous identity rather than by its attribute values; two entities with identical fields are still distinct if their identities differ. Entities typically have a lifecycle and mutable state. They contrast with value objects, which are defined entirely by their attributes.

Eventual Consistency

Eventual consistency is a consistency model in which, given no new updates, all replicas of a datum will converge to the same value over time. It is common in distributed systems that favour availability and partition tolerance over immediate consistency. Clients may temporarily read stale data.

Idempotency

An operation is idempotent if performing it multiple times has the same effect as performing it once. Idempotency is essential for safe retries in distributed systems, where a client cannot tell whether a timed-out request actually executed. HTTP GET, PUT, and DELETE are defined to be idempotent; POST generally is not.

Immutability

An immutable object cannot be modified after construction; any "change" produces a new instance. Immutability removes a class of bugs caused by shared mutable state, makes objects inherently thread-safe, and simplifies reasoning. Java records, final fields, and copy-on-write patterns are common ways to achieve it.

Inversion of Control (IoC)

Inversion of Control is a principle where the framework or container, rather than application code, controls the flow of execution and the creation of objects. Dependency Injection is the most common concrete form of IoC. It enables loose coupling by removing hard-wired construction from business code.

Integration Test

An integration test exercises several components together, typically including real infrastructure such as a database or message broker, to verify that they collaborate correctly. It catches defects that unit tests with mocks cannot, such as wrong SQL or serialization mismatches. Tools like Testcontainers run real dependencies in disposable containers.

Liskov Substitution Principle (LSP)

The Liskov Substitution Principle states that objects of a subtype must be usable anywhere their base type is expected without altering correctness. Subtypes must not strengthen preconditions or weaken postconditions of the base type. It is the "L" in SOLID and constrains how inheritance may be used.

Mocking

Mocking replaces a real collaborator with a controllable test double that records interactions and returns programmed responses. It isolates the unit under test from slow or non-deterministic dependencies. Overuse of mocks couples tests to implementation detail and can produce tests that pass while the system is broken.

Monolith

A monolith is an application deployed as a single unit, with all modules sharing one process and usually one database. Monoliths are simpler to build, test, and deploy than distributed systems and are often the right starting point. A well-structured modular monolith keeps clear internal boundaries that ease a later split.

ORM (Object-Relational Mapping)

An ORM maps between objects in code and rows in a relational database, generating SQL on the developer's behalf. It reduces boilerplate but can hide expensive queries and introduce pitfalls such as the N+1 problem and unintended lazy loading. JPA/Hibernate is the dominant ORM in the Java ecosystem.

Pure Function

A pure function returns the same output for the same inputs and produces no observable side effects. Purity makes code trivially testable, cacheable (memoizable), and safe to parallelise. Isolating side effects at the system's edges while keeping the core pure is a recurring design strategy.

Race Condition

A race condition occurs when the correctness of a program depends on the unpredictable interleaving of concurrent operations on shared state. Its symptoms are intermittent, hard-to-reproduce failures. Race conditions are prevented by synchronization, immutable data, or by confining mutable state to a single thread or actor.

Refactoring

Refactoring is the disciplined restructuring of existing code to improve its internal design without changing its observable behaviour. It relies on a suite of fast tests to prove that behaviour is preserved at each small step. The goal is to keep code changeable as understanding evolves.

Repository Pattern

The repository pattern provides a collection-like abstraction over data storage, exposing methods such as findById and save while hiding the persistence mechanism. Domain code depends on the repository interface, not on the database, which improves testability and isolates storage choices. It is a tactical Domain-Driven Design pattern.

REST (Representational State Transfer)

REST is an architectural style for networked applications that models the system as resources identified by URIs and manipulated through a uniform set of HTTP methods. Constraints such as statelessness and a uniform interface enable scalability and caching. Mature REST APIs use hypermedia to drive state transitions (HATEOAS).

SOLID

SOLID is an acronym for five object-oriented design principles: Single Responsibility, Open/Closed, Liskov Substitution, Interface Segregation, and Dependency Inversion. Together they aim to produce code that is easier to understand, extend, and maintain. They were collected and popularised by Robert C. Martin.

Single Responsibility Principle (SRP)

The Single Responsibility Principle states that a module should have one, and only one, reason to change, meaning it should be responsible to a single actor or concern. Mixing responsibilities couples unrelated changes and makes the module fragile. It is the "S" in SOLID.

Semantic Versioning (SemVer)

Semantic Versioning is a versioning scheme of MAJOR.MINOR.PATCH where MAJOR signals incompatible API changes, MINOR adds backward-compatible functionality, and PATCH makes backward-compatible bug fixes. It gives consumers a predictable contract about the risk of upgrading. The specification is maintained at semver.org.

Side Effect

A side effect is any observable interaction a function has with the outside world beyond returning a value, such as mutating state, performing I/O, or throwing. Side effects make code harder to test and reason about. Functional designs push side effects to the boundaries and keep the core logic pure.

Technical Debt

Technical debt is the implied future cost of choosing an expedient solution now over a better one that would take longer. Like financial debt it accrues interest as the suboptimal design slows future work. Deliberate, tracked debt can be a reasonable trade-off; unmanaged debt compounds silently.

Test-Driven Development (TDD)

Test-Driven Development is a workflow of writing a failing test first (red), writing the minimal code to pass it (green), then refactoring while keeping tests green. The cycle drives design from the consumer's perspective and yields a safety net of tests. It was popularised by Kent Beck.

Thread Safety

Code is thread-safe if it behaves correctly when accessed from multiple threads concurrently, with no data races or broken invariants. Thread safety is achieved through immutability, synchronization, atomic operations, or thread confinement. Documenting the threading contract of a class prevents misuse.

Unit Test

A unit test verifies the behaviour of a small, isolated piece of code, typically a single class or function, without external dependencies. Unit tests are fast and deterministic, forming the broad base of the testing pyramid. They give rapid feedback during development and refactoring.

Value Object

In Domain-Driven Design a value object is defined entirely by its attributes and has no conceptual identity; two value objects with equal attributes are interchangeable. Value objects should be immutable and can validate themselves at construction. Examples include Money, DateRange, and Email.

YAGNI (You Aren't Gonna Need It)

YAGNI is the principle that you should not add functionality until it is actually required, resisting speculative generality. Premature features add cost and risk while serving needs that may never materialise. It complements simplicity-favouring principles like KISS and DRY.

DRY (Don't Repeat Yourself)

DRY states that every piece of knowledge should have a single, authoritative representation in a system, so that a change is made in exactly one place. It targets duplicated knowledge, not merely duplicated text; coincidentally similar code that changes for different reasons should stay separate. It was articulated in The Pragmatic Programmer.

Coupling and Cohesion

A healthy design maximises cohesion within modules and minimises coupling between them. High cohesion keeps related logic together so a module is understandable on its own; low coupling lets modules evolve independently. Most structural design decisions can be evaluated by their effect on this pair.

Twelve-Factor App

The Twelve-Factor App is a methodology of twelve guidelines for building software-as-a-service that is portable and scalable, covering config, dependencies, processes, and more. Key factors include storing config in the environment, treating backing services as attached resources, and running the app as stateless processes. It underpins much modern cloud-native practice.

Observability

Observability is the degree to which a system's internal state can be inferred from its external outputs, usually through logs, metrics, and traces (the three pillars). It goes beyond monitoring by enabling answers to questions you did not anticipate at design time. Structured logs and distributed tracing are core enablers.

Open/Closed Principle (OCP)

The Open/Closed Principle states that software entities should be open for extension but closed for modification, meaning new behaviour is added without changing existing, tested code. It is typically achieved through polymorphism and well-placed abstractions. It is the "O" in SOLID.

Interface Segregation Principle (ISP)

The Interface Segregation Principle states that clients should not be forced to depend on methods they do not use, favouring many small, focused interfaces over one large general-purpose one. It reduces the ripple effect of changes. It is the "I" in SOLID.

Dependency Inversion Principle (DIP)

The Dependency Inversion Principle states that high-level modules should not depend on low-level modules; both should depend on abstractions, and abstractions should not depend on details. It inverts the conventional direction of source-code dependencies. It is the "D" in SOLID and the conceptual basis of Dependency Injection.