#A SOLID CASE
for application architecture
How can I fit more related things together on screen?
When editing this massive Rails project, I find myself scrolling up and down the file browser and forgetting where I am in the codebase or what I was trying to find.
It's OK when I know the name of the file I'm looking for, but it's awful when I am not sure or can't remember what to look for.
Also having tons of small objects is great. But understanding the dependencies between code that is many levels of directories away from other related code seems painful.
The aim of this project is to aid ruby developers in spotting, understanding and fixing violations of some of the 6 lesser known package-related SOLID principles. These principles broadly correspond to:
- Cohesion
- Acyclic Dependencies
- Stability
- Equivalency of Release/Reuse
CASE is an easy to remember acronym, but the letters map to 6 principles
Specifically the principles are:
* Cohesion -----> CCP - Common Closure Principle
* \---> CRP - Common Reuse Principle
* Acyclicity ---> ADP - Acyclic Dependencies Principle
* Stability ---> SAP - Stable Abstractions Principle
* \---> SDP - Stable Dependencies Principle
* Equivalence --> REP - Release Reuse Equivalency Principle
The E
of CASE
is a bit contrived and would be better as an R
but we were trying to make it easy to remember :)
You can read about them in the Original Paper
In less technical terms I want to be able to answer the following questions:
What are the main domain concepts in my application?
How can I refactor or organize my code to better match the domain?
What are some specific examples of coupling between objects that are not located together?
I think that Rails is great, but I think that most large Rails apps built by successful founded startups are likely to have considerable technical debt.
Often developers at startups are at the beginning of their careers and may cut corners in order to get to market.
Rails helps you quickly build applications but doesn't provide much of a helping hand for scaling the complexity of the codebase up.
Namespaced Engines are an example that helps, but I've rarely seen them used, or when used, rarely seen them used properly.
So lots of developers tackle the complexity by introducing more design patterns like
jobs
, services
, decorators
, presenters
, forms
, etc.
This helps with object complexity and size, but doesn't help with code organization
obeying the CRP
and CCP
.
Technical terms, but basically they mean keep related things together. Things that change together should be located together.
When you start with a Rails app it does feel like related things are together.
Models like User
have many Post
s and Post
s belong to User
s.
Views are grouped together, and you can go and change all the styles for the site in
one place.
But as the application grows and you have more and more design patterns it starts to feel less like the concepts change together.
Does your BurgerPresenter
belong with the RestaurantPresenter
,
and EmployeePresenter
and ManagerPresenter
?
Or does it belongs with the Burger
, BurgerTopping
, BurgerCreationService
and BurgerSerializer
?
If you've read this far, I'm sure you can guess which one I think is the correct answer.
But I want to answer this with data.
I bet that @dhh and all the guys writing basecamp etc do write well organized code.
I suspect that they know or feel exactly what and when is the right code and time to extract a piece of functionality into an engine.
I also bet that organizing a really simple blog application based on domain concepts mapping to domain folders is also overkill.
So the questions to answer are:
Can I create a metric that gives a good feel for how coupled/cohesive/spaghetti-like a codebase is?
Would the basecamp codebase score well?
I think yes
Would a small rails app with say 10 models score better than one organized by domain concept?
I think yes
Would a large app with 300 models and controllers and every design pattern directory under the sun score better in domain related folders (or in engines)
I think yes
Can I create a useful metric for this?
I think yes I can.