Having chosen the subsystems, how do you break each one into modules?
π Where this lives: this is the choice between "a pipeline of transformations" and "a set of collaborating things", and you can see both in tools you use daily. A Unix shell command β cat log | grep ERROR | sort | uniq -c β is a pure pipeline, and its power is that any stage can be replaced by anything that reads and writes text. A game engine, by contrast, is objects that hold state and message each other, because a pipeline cannot express "the player's health changed, so the UI updates". Neither style is better; they suit different problem shapes. Search "pipes and filters versus object oriented decomposition".
Where decomposition sits
After a system has been decomposed into SUBSYSTEMS, each
subsystem is further decomposed into MODULES.
THE DISTINCTION, restated because it is examinable:
SUBSYSTEM a system in its own right, whose operation is
independent of the services provided by other
subsystems. Composed of modules, with defined
interfaces for communication with other
subsystems.
MODULE a system component providing services to other
components, but which would NOT normally be
considered a separate system.
There is no rigid distinction between system decomposition and
modular decomposition, but the guideline is that modules are
usually smaller than subsystems, and the decomposition styles
described here are used for modules rather than for whole
systems.
TWO MAIN STRATEGIES:
1. OBJECT-ORIENTED DECOMPOSITION
The system is decomposed into a set of communicating
objects.
2. FUNCTION-ORIENTED (PIPELINE / DATA-FLOW) DECOMPOSITION
The system is decomposed into functional modules that
accept input data and transform it into output data.
In practice, a system may be decomposed with objects at one
level and functions at another. Modern practice mostly uses
object-oriented decomposition, but pipelines are the right
answer more often than fashion suggests β every batch
processing job and every data-engineering system is a
pipeline.
Object-oriented decomposition
AN OBJECT-ORIENTED DESIGN decomposes a system into a set of
loosely coupled objects with well-defined interfaces.
Β· Objects call on the services offered by other objects.
Β· Object classes are defined with ATTRIBUTES and OPERATIONS.
Β· Objects are created from these class definitions and, at run
time, are linked by a control model that coordinates object
operations.
ADVANTAGES
Β· OBJECTS ARE LOOSELY COUPLED, so their implementation can be
modified without affecting other objects
Β· objects often reflect REAL-WORLD ENTITIES, so the structure
of the system is readily understandable
Β· because these entities are reused in different systems,
REUSABLE OBJECT-ORIENTED COMPONENTS can be developed
Β· object-oriented programming languages provide DIRECT
IMPLEMENTATION support, so the design translates without a
paradigm shift
DISADVANTAGES
Β· object interface changes may cause problems, and it is
difficult to reflect a change in the interface of a
commonly used object
Β· larger entities may be harder to represent as objects β
"the payroll process" is not obviously a thing with
attributes
WORKED β an invoicing subsystem, decomposed into objects:
Customer Invoice
customerId invoiceNo
name, address date
creditLimit customer : Customer
βββββββββββββ lines : List<InvoiceLine>
creditAvailable() βββββββββββββ
isOverLimit() total()
tax()
Payment issue()
amount markPaid(p : Payment)
receivedOn
method InvoiceLine
βββββββββββββ description
apply(inv : Invoice) quantity, unitPrice
βββββββββββββ
lineTotal()
Note what OO gives you here: `invoice.total()` iterates its own
lines. The data and the operation on it live together, so
changing how a line total is computed (adding a discount rule)
touches ONE class. That is object cohesion doing its job.
Function-oriented pipelining
In a PIPELINE or DATA-FLOW model, functional transformations
process their inputs and produce outputs.
Β· Data flows from one transformation to another as it is
processed.
Β· Each processing step is implemented as a TRANSFORM.
Β· Input data flows through these transforms until converted to
output.
Β· The transformations may execute SEQUENTIALLY or in PARALLEL.
Β· The data can be processed by each transform item by item, or
in a single batch.
When the transformations are sequential with data processed in
batches, this is a BATCH SEQUENTIAL model β a common
architecture for data-processing systems (billing systems, for
instance).
Also called PIPE AND FILTER, after the Unix terminology: the
filters are the transforms, the pipes carry the data.
ADVANTAGES
Β· supports TRANSFORMATION REUSE β a filter that reads and
writes the agreed format works anywhere in any pipeline
Β· INTUITIVE β many people think of their work as processing
inputs into outputs
Β· EVOLUTION BY ADDING TRANSFORMATIONS is straightforward:
insert a stage, and nothing else changes
Β· SIMPLE TO IMPLEMENT as either a concurrent or a sequential
system
Β· each filter can be TESTED IN ISOLATION with a file of input
and a file of expected output β genuinely the easiest
architecture to test
DISADVANTAGES
Β· a COMMON FORMAT for data transfer must be agreed between
communicating transformations. Each transformation must
parse its input and unparse its output to that format,
which increases system overhead. Using incompatible data
structures may mean writing conversion code.
Β· NOT SUITABLE FOR INTERACTIVE SYSTEMS. The batch,
one-directional flow cannot express a user changing their
mind mid-stream, or an event arriving out of band.
Β· hard to handle EXCEPTIONS β a filter that fails on record
50,000 of 100,000 has no natural place to report it to.
WORKED β the same invoicing job, as a pipeline:
read orders β validate β price β apply tax β group by
customer β render invoice β write PDF + queue email
ββββββββββ ββββββββββ βββββββββ βββββββ ββββββββββ
β read ββ βvalidateββ β price ββ β tax ββ β group ββ β¦
ββββββββββ ββββββββββ βββββββββ βββββββ ββββββββββ
Note what the PIPELINE gives you that OO does not: to add a
loyalty-discount stage you INSERT A FILTER and change nothing
else. To rerun last month's billing with a corrected tax rate
you replace one filter and re-feed the same input. And because
each stage is a pure transform, the whole job is
re-runnable and idempotent β which is exactly what a monthly
billing run needs.
AND WHAT IT COSTS: if the invoice must be recalculated live
while a clerk edits it, the pipeline is the wrong shape
entirely. That is the interactive case, and it needs objects.
Choosing between them
THE DECIDING QUESTION: is the system's essence a FLOW OF DATA,
or a SET OF INTERACTING ENTITIES WITH STATE?
CHOOSE PIPELINE WHEN CHOOSE OBJECTS WHEN
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
input β output, one direction interaction, events,
user changes mind
processing is stateless per item entities carry state
across operations
batch or streaming, re-runnable long-lived identity
matters
stages are independently useful behaviour is inseparable
from data
the shape is a compiler, a the shape is a GUI, a
billing run, an ETL job, a game, a business domain,
report generator, a signal chain a simulation
A COMBINED EXAMPLE β the real answer is usually both:
the licence system uses OBJECTS for the interactive part
(an officer editing an application, where state and identity
matter) and a PIPELINE for the nightly reconciliation job
(read payments β match to applications β flag mismatches β
write report). Using objects for the batch job would make it
hard to re-run; using a pipeline for the editing screen
would make it impossible to write.
THE MISTAKE TO AVOID: applying one style everywhere because it
is the style you know. A batch job written as a graph of
stateful objects is very hard to re-run after a partial
failure, and an interactive screen written as a pipeline
becomes a tangle of flags telling later stages what the user
did.
The re-runnability point is the practical reason pipelines survive in data engineering. A stateful object graph that fails halfway through a hundred-thousand-record job leaves you asking "what did it already do?" β a pipeline of pure transforms just gets fed the same input again. When a job must be safely repeatable, that property outweighs everything else.
π Go further: the pipeline style's disadvantage β "a common format must be agreed, with parse/unparse overhead" β is precisely what Unix chose to pay, and the reason is worth studying. By fixing the format at "lines of text", Unix made every tool composable with every other tool forever, at the cost of constant reparsing. PowerShell made the opposite choice, piping typed objects: no parsing cost, but tools only compose if they agree on types. Both are defensible; the trade-off between a universal weak format and a precise strong one is one of the oldest live arguments in system design. Search "Unix philosophy text streams universal interface".
π‘ Exam angle: distinguish subsystem from module again (it is asked here too), then describe both decomposition styles β object-oriented and function-oriented / pipeline (pipe and filter, data-flow) β with a diagram and the advantages and disadvantages of each. The commonly examined disadvantages: for OO, the difficulty of changing a widely used object's interface and representing large entities as objects; for pipelines, the required common data format with its parsing overhead and the unsuitability for interactive systems. Mention the batch sequential variant.
Syllabus points
Decomposition into modules
Create a free account to tick topics off, take notes as you read, watch the video lessons and get a day-by-day study plan built around your exam date.