Classes of Objects - raisercostin/software-wiki GitHub Wiki
The objects can be classified by the roles/behavior they exhibit:
-
Application Wired Objects - Long term wired objects
- These are objects that once created will stay and provide a "structure" of your app. A lot of times are singletones but not always.
- Examples: services, repositories, catalogs, spring beans
-
Transfer Objects
- Input
- Output
- These are objects that exist to send information to a method and get the information back, but they are also short lived.
-
Data Structures - they are the data structures and attached algorithms to them:
List
,Queue
,Tree
,RedBlackTree
,Table
, etc. -
Data Structures Companion Objects / Structural Objects - they companion objects of the Data Structures and Algorithms them (think
Map.Entry
,Option.Some
,Option.None
,Try.Success
,Try.Failure
,Monad
,Mono
,Flux
). They get intermixed with domain objects - Domain Objects - objects that reflect the domain relation ships
-
State Objects are Domain Objects that contain state fields like:
state
,description
,isValid
,reason
besides the normal fields.- They are needed to replace a mix of Domain Objects with Structure Objects
- Sometimes modeled as DataStructures of domain objects but better to be modeled similar with NullObjects
- Technical classification - useful for compiling
- parameters
- fields
- result
- A function(method, component) should not receive and return Structural Objects. That is because the wiring is done at the beginning and that also forces the dependencies to be explicit.
- Always use constructor injection.
- The need for setter/field injection show that there are circular dependencies.
- A special form of circular dependency that is acceptable is one where one component is depending but can also create a second component:
new FirstComponent(){this.second = new SecondComponent(this);}
- Circular dependencies require a special lifecycle management: minimally in a form of creation and then registration and more often via a dependency injection framework.
- Use Companion Objects instead of static methods. Create a field
instance
on a class that self instantiate it. Then refer the "static" methods via this instance field. This keeps the advantage of having normal classes: methods that can implement interfaces but also simple singleton. - Never discard information. You can always later reduce it. If you have Security concerns delay them. Is not good to reduce information deep down. The system will not be debug/developer friendly. Like in premature optimization is the root of all evil, premature discarding of information is also evil.
- see also https://github.com/raisercostin/software-wiki/wiki/Domain-and-Test-Driven-Design
- Is best to have only Domain Objects without mixing them with Structures and Structures Companions? Instead of returning
Option<Foo>
isn't better to create aFooState
that is included inFoo
?
-
Add preconditions and postconditions
-
Fail fast. Think about where to move the exception/error condition to be called much sooner. In the end you will find the exact place that have the bug.
-
Do not purposely re-design before hacking the fix because the design might change anyway as a result of the new constraints added in test. Also this is the reason whitebox testing is fragile. So first add new constraints in the test, fix the test, redesign. Sometimes you are forced to redesign before because the technical debt blocks you in understanding or in easily changing current code. Read "Refactoring.Working with legacy code" in order to understand the code transformation process.
-
Two types of code: code as a scaffolding vs final building. Scaffolding is fast and can be used to create regression tests. In the end you don't need to use and you can remove the code that helped you creating them.
-
Forking/cloning tests for specific conditions are easy and almost cost free but they are not DRY and come up with the later price of reading and maintaining them. Is better to try to encode the scenarios in as few tests as possible. If you want to test the specificities and corner cases of a specific unit do unit tests.
- Refactoring triggers also data migration strategies: lenient input, fixing on the fly, @JsonAlias and @JsonSetter are usefull.
- Searchable items