Organize Code By Features

Structure packages in monilithic applications around features instead of Spring Components

Luke ShannonLuke Shannon

Package Structure As A Gateway To Microservices

This blog shares an insight I recently got from my good friend Josh Long. To many of you it might be obvious, but where I'm at with my Microservices journey, it was a great realization that I wanted to share.

Does this look like your source code?

For years I have had package names like this:

  • Services
  • Controllers
  • Model
  • Repo

The feedback I got from my good friend Josh was to create packages based on Features and not component.

Now I have this.

Each of these packages is named after a feature in my app.

What's so great about this you ask?

Granularity Can Be Tricky

Like many I have been reading and researching Microservices.

My first journey into Microservices resulted in an application that had a group of services and some Netflix OSS bells and whistles. I felt really smart and cool.

But it was annoying to deploy and not fun to trouble shoot.

I ended up writing lots of shell scripts and using Monit to keep the system "alive".

A platform like Cloud Foundry (Hosted version) can handle infrastructure management. PCF creates nice workflows for developers. That helps with some of the pain of operating multiple distributed services. But I still went too far from an arcitectural point of view, at least one of these services could have existed within another. What's the alternative?

Is Starting With Microservices Smart?

If you look at the some of better examples of this Microservice style architecture, Netflix and Amazon, both moved towards this out of necessity.

For example, Netflix wanted to move from shipping DVDs towards streaming video to users around the globe. They could not do it with a large and complex monolith. This blog has a great explanation of why that was.

Amazon went from selling books online to selling everything (remember staring at Amazon Prime half the day looking for deals), include the same on-demand infrastructure they created to make their architectural shift possible (AWS).

These successful internet gaints did not start in a 'Microservice' fashion, they moved this way out of necessity. They were successful with monolithic architectures first, microservice style architectures allowed them to scale and evolve their success.

This idea of starting with a monilith and moving towards Microservices has been thrown out there: https://martinfowler.com/bliki/MonolithFirst.html

Sam Newman's book references 'Seams' in the code as the boundaries for services and a guide on how to peel out code: http://shop.oreilly.com/product/0636920033158.do

Interesting ideas. But....

Breaking Up Monoliths Is Hard!

If you are developing in an enterprise, chances are the you have seen big tightly coupled code base that won't leverage the scalable nature of cloud compute. No-one started with bad intentions when developing an application. But over years, with multiple teams, contractors, tight deadlines, fixes and patches...well...it becomes a tangled mess.

Breaking out functionality in a legacy application is possible, but it's a bit like unplugging and tracing wires in the picture above.

Moving Forward Organized By Feature

So the idea of starting with a monilith does not mean you create tangled mess

By organizing all components (Model, Controllers, Services, Repos) by Feature, rather than the tangled mess you have more order in the way the code is grouped.

The task of peeling out functionality is less daunting than before.

We can break out a package/feature into to a seperate service when:

  • A package gets too full of components and requires multiple team members to maintain
  • Functionality of a package needs to be exposed outside of the context of this application
  • Want to re-write a feature in a language/framework better suited for the problem the feature/package is addressesing

In theory I hope to just copy the package/feature into a new Spring Boot app, add the correct dependanices, update tests and then have a new service to deploy. I'm sure there will be more to it than that, but at least there is a clear starting place now.

Time will tell how well this works, but going forward I plan to be less aggressive to peel out services but more mindful of package structures.

Happy coding my friends.