A long time ago when I was about to finish university and just above junior level programmer, I joined a new company and received their organized, fresh out of the oven, MVP code.
The code was written by an Ukrainian developer I have never met, but loved in my heart. It wasn't the first time I saw a layered application, but it was the best of times.
She put everything there, clean controllers layer for the API, service layer to handle process logic, handlers layer to tackle fine grained actions, and of course DAO layer to handle all the DB stuff. From then on, all my future projects followed her beautiful layering and everything was better.
Fast forward a couple of years, my partner and I are now managing the R&D team somewhere (not interesting & not important). Like most teams, we are being swamped with feature requests, and other bullshit the management finds "CRITICAL". Our code-base is still quite organized with the layering we know and love but we start noticing some issues (Add dramatic sound...).
Every time we need to add a new CRUD entity to the system, even the most basic entity for some kind of configuration, we need to add A LOT of boiler plate code. We start by copying an existing entity code, then:
- Update the controller with the new entity. Clean not relevant code.
- Update the service with the new entity, again. Clean not relevant code.
- Update the handler with the new entity, again... Clean not relevant code.
- Update the DAO with the new entity, again....... Clean not relevant code.
The next image is not for the faint of heart. It contains the boiler-plate code required for one the SIMPLEST use cases. The horror!
Just writing it and remembering the old times made me tired. And more important, adding the new entity is the easy part, now we have more code we need to maintain. Our code base is growing and doing system wide changes becomes impossible.
Then one day, we are on a flight to some conference, disconnected from the world and connected to our inner thoughts (no wifi...). My partner, comes to me and say, "What if we develop a generic CRUD framework without boiler-plate, just add an entity and everything else is available in seconds". At first I was skeptical, but he is the smart one between us so I give it another thought and decides to roll with it.
Fast forward again, my partner and his trusted sidekick have kept their promise and delivered their boiler-plate free CRUD framework, after countless of fights and iterations (to this day). I don't want to bore you with too much code, but I just have to show a simple example to honor everything we lost along the way.
@Entity
@Table(name = "example")
@DefaultMappingTarget(ExampleDisplay::class)
class Example(
@MappedField
@Column
var exampleString: String?,
@MappedField
@Column
var exampleBoolean: Boolean?,
// ...
) : AbstractJpaEntity()
@DefaultMappingTarget(Example::class)
data class ExampleDisplay(
@MappedField
var exampleString: String? = null,
@MappedField
var exampleBoolean: Boolean? = null,
// ...
) : AbstractJpaDisplay()
@RestController
@RequestMapping("example")
class ExampleController : BaseCRUDController<Example, ExampleDisplay>() {
}
That's it! Now I know what you are going to tell me. Where are your layers that you couldn't shut up about?! The beautiful thing is, they are all here. Behind the scenes the framework has all the layers and it allows you to use hooks and other mechanisms to add additional logic/frameworks/...
Since then, the smart guys have added permissions, security and more on top of the CRUD framework, according to the requirements of each project.
So your next thought is probably "Where do I sign?". Hold your horses for a moment, I know your honest current thought is that I'm stupid and I know nothing, fair. Also I would be happy to give you the CRUD framework but it's not truly open source ready. If you want to take a look anyway it's available here.
Because it's a large framework and it will take time to bring it to the level that we want for an open source release, we decided to start small and separate our object mapping capabilities into a separate library. Of course the hardest part was to find a name for this library but in the end we settled for ShapeShift.
If you are not sure what is object mapping or why you need it you can read more about it here.
If you have any thoughts/comments/disses you would like to throw at me I would be more than happy to connect.
Top comments (0)