0

According to the 12-factor-app dev/prod parity principle, the developers' local environments and production should be similar.

For developers working on a system with a complex microservice-based architecture, my understanding is that, this would mean that they need to build and deploy dozens of components to their local cluster (minikube for e.g.) -- even if they work only on a small part of the overall application. I see some problems with this approach:

  • Developer machines are obviously not as powerful as the cloud staging/prod environments. Plus they need to be able to run development software (IDE etc) on top of the cluster (including data stores).
  • Time lag before the developers can start contributing. Though this can be somewhat managed with a sufficiently automated deploy process.
  • Time spent keeping the local cluster up-to-date constantly. While cloud environments can be kept up-to-date automatically through commit hooks etc, this has to be done manually for local environment.
  • In effect, doesn't this make it similar to working on a monolithic system where to touch one part of the application, you need to build and run the entire thing.

Is there a better way to handle this? Or am I misinterpreting the principle?

1
  • 1
    If a developer has to build and run 5 microservices in order to productively work on the 6th microservice, you're doing microservices wrong. They should be as independent as possible, thats the whole point.
    – marstato
    Oct 26 at 8:51
1

There are usually multiple levels of testing environments. For example

  1. Staging
  2. Integration
  3. Team
  4. Local
  5. Unit

While it is desirable to have as similar environments as possible, more deviations may be acceptable the lower down the list you go. If it is difficult to provide a full test environment for each developer, it might be more feasible to provide one for each team.

But in many cases a modern computer is perfectly able to run quite large systems, as long as the load is reasonable. And deployment should preferably be automated, making it easy to setup new test-systems. Presumably you would only change your own service, so should be able to limit testing to how your code interacts with the other systems, something that may be more difficult in monolithic systems where everything is more interconnected.

But the important point is to catch compatibility issues as fast as possible so they can be fixed.

I have heard stories about projects where all testing have been done locally with all other services mocked out. When all services was integrated for the first time after some years of development, it failed badly since the real services where much slower than the mocks each team used.

The goal is usually good modularization and cohesion. And it is possible to build a micro service based system with poor modularization, just as it is possible to build a monolith with good modularization.

2
  • Agree with all this, but can I still consider my app a "12-factor-app" if there are significant deviations as we go down the environment stack? After all, the principle (documented in the link in OP) doesn't even allow for a lighter DB (like SQLite) to be used in local environments! Let alone missing a few components...
    – Vasan
    Oct 26 at 10:17
  • 1
    @Vasan I do not think it is very useful to classify apps as following some specific methodology. The important things, as is mentioned in the article, is to keep development cycles short and find issues as fast as possible. You need to decide how this applies to your specific environment. And databases are not directly interchangeable, so if you run a different database you will hide potential issues until the next layer of testing.
    – JonasH
    Oct 26 at 11:51
1

Yes, I think you are misunderstanding the principle. When it talks the dev environment, it refers to the development deployment environment.

On my development machine, I'll be working on one component. Here I need an environment that allows me to reasonably test those parts of my component that interact with other components, systems, services etc. That test environment needs to be fast acting, eg a bunch of unit and basic integration tests that run each time I build.

When I push my changes up to the CI/CD environment, that should trigger a build and deployment to the development deployment environment. This environment is as similar to the production (deployment) environment as possible and here thorough automated end-to-end tests should run. Potentially, you have "smart tests" though, ie only tests related to the changed component and those components it interacts with are run. It's not until you deploy to eg staging that all end-to-end tests are then run.

2
  • Quoting from the link in my question: "Lightweight local services are less compelling than they once were. Modern backing services such as [...] are not difficult to install and run thanks to modern packaging systems, such as [...]. Alternatively, declarative provisioning tools such as [...] combined with light-weight virtual environments such as [...] allow developers to run local environments which closely approximate production environments". So this tells me that they're talking about devs' machines rather than a common dev environment?
    – Vasan
    Oct 26 at 8:30
  • Though I agree that your approach makes more practical sense, and was what I had in mind too (until someone in my team challenged me with this i.e.).
    – Vasan
    Oct 26 at 8:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.