The Eternal Quandary: Build vs. Buy (or Open Source!)

You know, it’s funny how some ideas feel so fundamental that you assume you’ve already articulated them. I recently found myself searching for a blog post I was sure I’d written, detailing my approach to selecting software dependencies. Turns out, it only existed in my head! So, consider this the definitive guide to a topic that, while seemingly straightforward, carries significant implications for any software project: how to choose your dependencies wisely.
First, let’s get on the same page about what I mean by “dependency” here. While your software relies on many things – a file system, a database, the network – for this discussion, I’m narrowing our focus. We’re talking about software libraries you need to compile or run your code. Whether your stack calls them gems, crates, packages, modules, or just plain old dependencies, they all serve the same purpose: extending your application’s capabilities without reinventing the wheel.
And before anyone asks, yes, even with the industry’s shift towards service-based architectures accessed via REST APIs or other means, these same evaluation criteria largely apply. After all, a third-party service is just a dependency by another name.
The Eternal Quandary: Build vs. Buy (or Open Source!)
When faced with a new functional requirement, the first fork in the road is almost always “build vs. buy.” Should your team develop this capability in-house, or should you acquire a Commercial Off-The-Shelf (COTS) solution? For software libraries, we get a fantastic third option: Open Source. Each path has its well-documented pros and cons, debated endlessly across the tech landscape.
From my personal vantage point, this decision hinges heavily on context and control. I tend to be very conservative with external visibility within my projects. In Java, I push for `private` access modifiers wherever possible. But then you hit a snag: how do you test a private constructor? You widen the visibility to `package-protected`, which feels a bit like cheating if it’s solely for testing purposes. That’s where an annotation like Guava’s `@VisibleForTesting` comes in. It’s a brilliant way to document intent.
I instantly became a fan. And yet, I wouldn’t pull in the entire Guava library solely for that one annotation. That’s a dependency bridge too far for a single convenience. In such a scenario, I’d simply create my own `@VisibleForTesting` annotation. It’s a trivial amount of code for significant control and zero external baggage.
However, if my project started needing other Guava utilities – say, a `Multimap`, which allows multiple values per key and would take a significant amount of time to develop robustly from scratch – then the calculus changes. The value proposition shifts dramatically, and bringing in Guava becomes a much more sensible decision. As you can see, the “build vs. buy” decision is rarely black and white; it’s a spectrum of trade-offs.
For the remainder of this post, let’s assume you’ve concluded that building it yourself isn’t the optimal path. Now, the real work begins: selecting the best existing dependency for your needs.
Navigating the Minefield: Dependency Risk Management
Every dependency you introduce is, inherently, a risk. It’s a commitment, a potential future maintenance burden, and a vulnerability point. Just like any other risk in business or life, it demands a robust risk management strategy. This isn’t a one-and-done task; it’s an ongoing process:
Identify Risks
Before you even begin evaluating, list out what could go wrong. What are the potential pitfalls of relying on external code? This forms the basis of your evaluation criteria, which we’ll dive into shortly. Think about everything from legal issues to technical debt.
Analyze Each Risk
For each identified risk, consider its likelihood and potential impact. This is where organizational context is crucial. What one company deems a “low impact” risk, another might see as “critical.” A small startup might tolerate a higher bus factor for an open-source project, while an enterprise handling sensitive data would likely consider it a severe red flag. You know your organization best; tailor your analysis accordingly.
Plan Responses
Once risks are analyzed, document your mitigating actions. What steps can you take to reduce the likelihood or impact of each risk? And critically, what are the associated costs of those actions? Sometimes, the cost of mitigation outweighs the benefit, and you might decide to accept a certain level of risk. This should be a conscious decision, not an oversight.
Monitor!
Risk management is not static. A dependency that was perfectly safe last year could become a liability tomorrow. New critical CVEs emerge. Core committers might leave an open-source project, drastically reducing its “bus factor” (the number of people who can be hit by a bus before the project stalls). Monitoring might reveal that a crucial dependency needs dedicated resources, perhaps even a full-time employee, to ensure its continued maintenance and alignment with your needs.
Your Dependency Checklist: Key Evaluation Criteria
Now that we understand the strategic framework, let’s get into the nitty-gritty – the practical criteria you should scrutinize when choosing a dependency. This is where your risk identification truly comes into play.
License & Legal Aspects
This is, without a doubt, the most important aspect. You absolutely *must* understand the license. GitHub, thankfully, makes this relatively easy by encouraging `LICENSE` files and prominently displaying recognized Open Source Initiative (OSI) approved licenses. For standard OSI licenses, others have done the legal heavy lifting for you, providing clear implications. However, watch out for dual-licensed dependencies (Open Source and commercial); often, the open-source variant comes with restrictions that nudge you towards the commercial offering if your usage falls outside specific parameters.
Pricing
If you’re buying, pricing is naturally a major factor. You’ll encounter fixed prices, variable prices based on factors like CPU usage or user count, or a combination. Licenses can also be time-limited or perpetual. My best advice here is practical: clearly define your requirements, scope, and budget internally. Then, hand off the negotiation to your purchasing department. They are the experts in this arena and will get involved eventually anyway, so bring them in early.
Governance
Who runs the show? For commercial projects, it’s a company, offering financial backing and typically professional support. For open-source projects, governance can vary wildly: a foundation, a community of developers, or even a single benevolent dictator. Foundations like the Apache Foundation, Eclipse Foundation, or CNCF (part of the Linux Foundation) offer greater stability. However, they operate differently: Apache emphasizes individual merit, while CNCF is more company-centric with contributions from member organizations. The larger and more diverse the governing body, the harder it can be to influence the roadmap or even get a bug fix prioritized. Expect to engage in a bit of “politics” to achieve your goals, regardless of the governance model.
Maturity & Activity
Adding a dependency means trading development time for a loss of control. If that project goes unmaintained, you’re stuck: either migrate your code away from it or take on its maintenance yourself. Therefore, assessing a project’s maturity and ongoing activity is critical for risk assessment.
For maturity, look at its creation date (older often means more battle-tested), release history (regular releases are a good sign), and roadmap (clear but not overly detailed roadmaps suggest vision and agility). For commercial offerings, inquire about Long Term Support (LTS) options.
For open-source projects, dive into their activity: How many open issues are there, and what’s the typical resolution time? How many core committers are active, and what’s the project’s bus factor? Do these committers focus primarily on this project, or are their efforts spread thin? These metrics paint a vivid picture of a project’s health and future viability.
Support (Commercial & Community)
Most mature organizations require some form of guaranteed support. Commercial dependencies typically provide this. For open-source projects, support ranges from non-existent to professional companies (like Tomitribe or HeroDevs for Apache Tomcat) offering paid support, often employing project committers. Community support, while free, is best-effort. Investigate available channels (GitHub, Slack, Google Groups), observe the number of unique contributors, response times, and the quality of answers.
Developer Experience (DX)
Great developer experience is a true differentiator. Documentation is paramount here, ideally following the Divio system: tutorials (learning), how-to guides (problem-solving), reference guides (information), and explanations (understanding). Many projects excel at reference docs but lack crucial quick-starts. The absence of a simple “get started” guide is a significant blocker for new users.
Beyond documentation, nothing beats hands-on experience. Time-box a small prototype project using the dependency. This gives you a genuine feel for its API, error messages, and overall usability. If you’re making a significant investment, prototyping a couple of competing dependencies in parallel can be incredibly insightful.
Market Adoption & Ecosystem
Humans are social creatures, and sometimes, trusting the wisdom of the crowd isn’t a bad strategy. High market adoption suggests that many others have vetted a dependency, potentially reducing your risk. However, be wary of the “herd mentality” – what works for one organization in a specific context (cough, microservices, cough) might not be right for yours. Still, broad adoption often correlates with greater activity and future support.
Also, examine the surrounding ecosystem. A simple CSV parser might not have much of an ecosystem, but an LDAP library certainly does. Which LDAP providers does it support? Is it Azure Directory compatible? Finally, don’t overlook internal knowledge: if team members are already familiar with a dependency, onboarding and initial development will be smoother.
Miscellany
While I haven’t personally delved into these criteria in my own dependency choices, they might be relevant for your specific context. These include vulnerability management and response times, dependency health and update frequency, public security policies, public benchmarks and performance metrics, real-world scalability examples, and even the company’s stability and financial transparency behind a commercial offering.
Conclusion
Choosing a software dependency is far more than just picking the first library that pops up in a search. It’s a strategic decision, a form of risk management that impacts your project’s longevity, security, and developer efficiency. By systematically evaluating options against a comprehensive set of criteria – from legal implications and governance to developer experience and community support – you move from guesswork to informed decision-making. Don’t rush this process; investing time upfront to select the right dependencies will save you countless headaches and technical debt down the line. Your future self, and your team, will thank you.




