You need to be able to run your system

When developing a system, it is important to be able to run the system in its entirety.

"Run the unit tests" doesn't count. The complexity of your system is in the interactions between the units.

"Run an individual service against mocks" doesn't count. A mock will rarely behave identically to the real dependency, and the behavior of the individual service will be unrealistic. You need to run the actual system.

"Run an individual service in a shared stateful development environment running all the other services" doesn't count. A shared development environment will be unreliable as it diverges more and more from the real system.

"Run most services in a mostly-isolated development environment, calling out to a few hard-to-run external services" doesn't count. Those few external services on the edge of the mostly-isolated development environment are often the most crucial ones; without the ability to run modified versions of them, your development process is hobbled. Furthermore, being dependent on external services greatly complicates where and how you can run the system; it's much harder to, for example, run tests with the system on every commit if that will access external services.

"Run all the services that make up the system in an isolated development environment" counts; it's the bare minimum requirement. Bonus points if this can be done completely on localhost, without using any off-host services.

Without the ability to actually run the entire system in this way while developing, many evil practices will tend to become common.

Running the entire system during development is the first step to preventing these issues. Further steps include writing automated tests for the system (which can be run repeatedly during development), and using, as much as possible, the same code to run the system in development and in production.

Developers of large or legacy systems that cannot already be run in their entirety during development sometimes believe that it is impractical to run the entire system during development. They'll talk about the many dependencies of their system, how it requires careful configuration of a large number of hosts, or how it's too complex to get reliable behavior.

In my experience, this is often wrong. These systems can be run locally during development with a relatively small investment of effort. Typically, these systems are just not as complicated as they're thought to be; once the system's dependencies are actually known and understood rather than being cargo-culted or assumed, running the system, and all its dependencies, is straightforward.

When running your system, it can seem tricky to run your dependencies, especially if they're mostly services rather than libraries. Fortunately your dependencies have the same goal: They also need to be able to run their system! They shouldn't reserve that ability for themselves; they should pass it down to you, the user of their system. Likewise, you shouldn't reserve the ability to run your system for yourself; you should pass it down to your own users, so that they can run their system, which is a superset of yours.

Being able to run your entire system during development is just about the most basic requirement for a software project. It's not, on its own, sufficient for your development practices to be high quality; but if you can't do this, then you're not even in the running.