Treat backing services as attached resources
What’s a Backing Service?
Put simply, a backing service is anything that’s not delivered as part of the single executable defined by your codebase. This could be anything from a database to a logging service to a particular Amazon S3 bucket. It can even extend to indirect third party services, such as a public Stripe key to be used by an HTML frontend.
Internal vs External
Nothing about your application should care if a particular external resource is provided by a 3rd party or hosted on the same VM (or anything in between). The only thing that it could possibly do with that information would be to add complexity and change behavior that shouldn’t be changed.
Its common for these situations to be different by environment. Developers frequently run the entire stack locally on their laptops; QA may be executing tests against a central database but using local queues, and your production environment may be hosted in one or more commercial clouds with load balanced HA pools of services at its disposal. If your application becomes aware of those differences at any point, you’re going to suffer.
It should be expected that backing services will change. Some systems provide elaborate location services designed to facilitate connection lookup, and have even more elaborate mechanisms in place to handle their movement. We haven’t seen Processes yet, but one of the fundamental principles of 12 Factor applications is that they should be stateless. This means that we don’t have to worry about anything too fussy - if a resource changes its connection information we simply spin up new backends with the updated environment and then take the old servers offline.
Clean and Simple
Remember, keeping the configuration of your environment in your process's environment (hint: it got its name for a reason) doesn’t solve problems so much as prevent them from every arising - my favorite sort of hack.
None of this means that your application has to be agnostic about the type of backing service that its using. While there may be some advantages to writing generic SQL, or to being able to swap out SMTP providers, you should feel free to assume that you know the type of service you're using if that makes things easier.
Where you should choose to look away is in anything that assumes how that service will be provided. A database may be local to the appserver, or may be a cluster located across the internet. So long as you treat it as a resource defined by its [[environmental configuration]] and don't make assumptions as to the way, you'll find that your application is much easier to develop, test, and deploy than it would otherwise be.
Don't overthink this one. Just draw a hard line between your application - that thing that's being built from your repository - and everything else. And just as with any random 3rd party subscription service, don't assume that you know anything about the internals of products provided by your internal teams that's not formally included in their service definitions, which will need to be fulfillable at every stage of the applciation lifecycle.