Data vs behaviour
“Which classes should hold data, and which should do the work?”
Some classes are things that remember values, like a loan. Others are jobs that get done, like working out an EMI.
See it
In plain words
Some classes mainly hold data. A Loan remembers its amount, rate and months. Money remembers one amount. Other classes mainly do work. Emi takes numbers in, works out the monthly payment, hands it back, and remembers nothing. For any class, ask: is it a thing that keeps values, or a job that gets done?
- Classes that mostly hold data are entities, which have an identity like a Loan's Id, and value objects, which have none and are equal when their values are equal, like Money, usually a .
- A data class still owns the rules about its own data, like refusing 0.
- That is a rich domain model; a class of only getters and setters, with every rule outside it, is an anemic model.
- Classes that mostly do work keep no data of their own.
- is a pure function: its output depends only on its inputs.
- A keeps only the tools it needs in its fields, never per-request data, so one instance can be shared.
- Pure data for crossing a boundary, like API JSON, is a DTO.
In the lending API
Three files from the lending API, and their tests. Press Next line to walk through them.
Lending.sln · where these 5 files sit
- src/Domain/
- Servicing/
- Common/
- Servicing/
- tests/Domain.UnitTests/Common/
What they ask next
Interviewers check that you can explain every line. Tap a question to open it.
Why not…Why move the math out of Loan?
A Quote needs the before any Loan exists, and both must show the same number. One Emi class means one formula. Loan keeps as a one-line hand-off, so code that calls
car.Emi()did not change.Then should Loan have no methods at all?
No. A class with only get and set, and every rule outside it, is called an anemic model. Then any code can set a rate of 0. Methods that guard the object's own data stay on it.
Explain this lineWhy is static?
It has no fields and needs nothing set up, so there is no object worth making. It is also the formula pages 6 and 7 use. If the math later needs something that can change, like country rules behind , it becomes a normal class handed in through the constructor. More on .
Why not…Why for Money, not a plain class?
A record compares by values, so two Money of 100 are equal. A plain class compares , so two equal amounts would count as different.
Why not a
record struct?Also common, and it skips a object. The catch:
default(Money)makes one with every field at 0 and never runs the constructor, so its checks and rounding are skipped. Asealed recordcan only be made through the constructor.
What is the difference between an entity and a value object?
An entity has an identity that stays the same while its values change: a Loan with an Id. A value object has no identity and never changes; it is defined by its values: Money, a date range.
What is a DTO?
A data transfer object: pure data, no rules, for crossing a boundary such as JSON in and out of the API. Slice 2's is one. Teams map it to a Loan instead of exposing Loan itself.
Where does a service fit?
A service does the work of one use case, like in slice 2: it loads a Loan, calls its methods and saves it. Its fields are only the tools it needs, handed in by the constructor. See .
Traps
- Don't say
A data class should have no methods.SayIt keeps the methods that guard its own data, like . Only work that is not about one object moves out. - Don't say
Copy the formula wherever a screen needs it.SayOne formula in one class, so a Quote and a Loan can never show different .
GitHub's Copilot best-practices guide lists deep business logic among the tasks to keep for humans. When you ask an AI tool for an on a new screen, point it at Emi.cs, so it reuses the one formula instead of writing a second.