Imagine you've created a wonderful contact management system that has all the bells and whistles, meets the clients needs. It creates, edit, deletes and read contacts. This system has various different classes that don't strictly relate to one and another but are all required to make the system operate.
In addition to this you would like to to have your group of developers working on different parts of the codebase without stepping on each other's toe.
A developer interested in changing how persistence works shouldn't be concerned with the GUI and vice-versa.
The next step to get isolation of the components is to create smaller packages so then the developer can happily modify the system and complete new releases without ever having to interfere with other parts of the system.
This solves only part of the problem.
The SOLID principles are related to class design, the package principles are related to the packages within our app. In .NET, these are our outputted dll files that other clients can import into their own project as a dependency.
The 6 package principles are:
Related to cohesion
- Release Reusue Equivalency
REP essentially means that the package must be created with reusable classes
- Common Reuse
The CRP states that classes that tend to be reused together belong in the same package together
- Common Closure
CCP states that the package should not have more than one reason to change.
Change only one package at a time
Related to coupling
- Acyclic dependencies principle (ADP)
In a development cycle with multiple developers, cooperation and integration needs to happen in small incremental releases. The ADP states that there can be no cycles in the dependency structure, and that when an incremental release is made, the other developers can adopt and build upon it.
- Stable-dependencies principle (SDP)
Designs, by nature of the environments they are used in or by, are changing.
- Stable-abstractions principle (SAP)
I The SAP says that a stable package should also be abstract so that its stability does not prevent it from being extended. It also states that an instable package should be concrete since its instability allows the concrete code within it to be easily change
Here is the Package structure for my Contact Management
The class representation of the contact object and validation class
Classes that the UI uses to connect to the model and storage
CRUD related actions
Classes related to running the WPF UI version
Classes Related to running the Console UI version
Release Reuse Equivalency
The Release reuse equivalence principle states that all classes inside a package should be treated that as though a 3rd party is going to be using it, thus should have some form of version tracking system.
For my classes I used the assembly information to change the version number, so each new release brought a newer version number.
Common Closure(CCP) & Common-reuses principle(CRP)
Classes that change together are packaged together.
In the event that the Contact class changes, it made sense to also change the contact builder(uses builder pattern to build a contact). If a new field is introduced, say contact blood type, then the builder needs to introduce a method that builds that field into a contact. Likewise the ContactValidator class needs to be update to validate blood type inputs.
These changes all stay within the same ContactModel package, we are not required to leave the package and venture elsewhere. This has good cohesion and CCP.
Stable dependencies principle(SDP)
SDP is about violatile packages should ideally be dependent only on stable package(s).
A good example of this is the WPFGui package. The gui design of an app can change a lot, especially during development. Making crucial that we don't make our lives more difficult by the floor constantly moving beneath us. The WPFGui is dependent on the Storage package which itself rarely changes.