When building and delivering software, you’ve pretty much always got some third-party software dependencies in the mix, and often more than you’d like. Operating systems, system SDKs, programming-language runtime libraries and interpreters are easy to take for granted, but you have to count them. Then there are database engines, networking servers, and other components which lift you off the base abstractions of files and sockets. There may be GUI widget libraries for your rich clients, or message queues for your distributed servers, or PaaS or IaaS providers for your cloud-based apps. You don’t start a cloud-backed iPhone app by writing your own kernel, after all.
With each such decision, however, you outsource some part of your customer experience to another, most-likely unknown, developer. Performance, quality, reliability, usability, system requirements, and customer support turnaround each have a dependency graph which mirrors that of your code.
So here are my general rules.
- I tend to avoid third-party dependencies where there’s not a clear gain over doing things myself or just using the base platform capabilities. For example, I’ll use a third-party HTTPS server, because getting that right is hard, and because the integration points are pretty clear. But I’ll probably avoid a framework which takes built-in Java capabilities like threading or logging or classloading and tries to plumb it for me; that kind of plumbing I’m good at, and the costs of doing the integration plus the dependency risk aren’t worth it.
- When using a third-party component, I want to make sure it’s as replaceable as possible. For libraries and APIs, this usually means writing thin wrappers and calling them instead. For example, I’ll use the AWS iOS SDK libraries from Amazon, but only via thin wrapper classes in my app which isolate the specific functions I’m using.
- Finally, when using a third-party dependency which is core to the product, like an OS or DBMS, and when I have a choice (for example in embedded or server-side contexts), I want to use free and open source software as much as possible. With free software, if I find myself needing a fix, enhancement, or support that the original vendor can’t or won’t provide, it just becomes a question of time and money to do it myself or have it done for me. With closed, proprietary software, I’m stuck. Particularly in embedded contexts, users don’t see or care what OS I use, they just see my application. On the client side, of course, I pick the OS (iOS, Windows, Mac OS X) based on my target users, but then it’s easier for them to see when an OS dependency causes problems.
Interestingly, the first two of the above rules seem to be reliable recipies for having more readable code as well. The first rule avoids framework-itis, where you have to read scattered code and configuration files to figure out what is going on, and the second rule masks third-party complexity and flexibility.
I’m interested in building long-lived and maintainable things in my work.
Oh yes, seems to be in the news that Parse is shutting down.