Author points to TigerBeetle as an example, which I wasn't familiar with, so I went down a rabbit hole.
Wow. Yeah. If you're writing a financial ledger transactions database from scratch in Zig, where safety and performance are your top two goals, so that you can credibly handle a million transactions per second on a single CPU core, well, damn right you can't afford to take any risks on introducing any dependencies. Makes absolute perfect sense to me (no sarcasm).
But the average developer, writing most line-of-business CRUD systems, well, quite honestly they're not that strong to begin with. Most dependencies may be bug-infested garbage, but they're still higher quality compared to what most developers are capable of. Most companies are bottlenecked by the caliber of talent they can realistically recruit and retain; and internal development standards reflect the average caliber on the payroll.
So like most advice you read on the internet, remember, everybody is in different circumstances; and polar opposite pieces of advice can both be correct in different circumstances.
+100, context is the key thing, both TigerBeetle and rust-analyzer have strong culture of how the things are done, but the _specific_ culture is quite different, because they solve very different problems.
That being said, I _think_ you might be pattern-matching a bit against the usual dependencies good/dependencies bad argument, and the TFA is on a different level. Note the examples of dependencies used: POSIX, ECMA-48, the web platform. These are not libraries, these are systems interfaces!
Dependency on a library is not a big deal --- if it starts to bite, you can just rewrite the code! But dependency on that underlying thing that the library does is usually something that can't be changed, or extremely costly to change. Answering "No" to "is doing X in scope for my software?" is powerful
To refer to the sibling comment, if there's a team whose core business is writing matrix multiplication code, they _can_ use random library #24 for something else, but often, if you apply some software design, you might realize that the product surrounding matrix multiplication _shouldn't_ handle concern #24. It doesn't mean that concern #24 isn't handled by anything at all, rather that we try to find _better_ factoring of the overall system to compartmentalize essential dependencies.
The problem I have with this line of thinking is that it only works when you're talking about bottom of the barrel developers.
The tech world has this tendency to dumb down every advice so it caters to the lowest common denominator, but I honestly have never worked in such an environment where developers couldn't learn to duplicate the functionality of shitty dependencies while at the same time fixing the problem.
And as much as people love to mock CRUD, bad abstractions can be a horrible drain on teams doing CRUD work. And even the popular stuff can often suck and be a timesink unless you're doing absolutely basic stuff that's just repeating the tutorial.
I've seen a few people from the bottom of the barrel outside on the real world...
The funny thing is that no advice is dumbed-down enough for them. They will take anything you can say and implement wrongly.
That idea that if you dumb-down everything, it will be helpful is just plain bullshit. People that can't duplicate a dependency just can't choose the right dependency either, and if you force them to use some good one, they will use it wrong.
> but I honestly have never worked in such an environment where developers couldn't learn to duplicate the functionality of shitty dependencies while at the same time fixing the problem.
I have absolutely seen this. It’s not a matter of them being bad developers, but no one is an expert in all things and gaining expertise takes time which costs money. All dependencies have a lot of trade-offs baked in that must be re-evaluated if you decide to go the NIH route, and that’s usually where expertise is needed. If you lack the expertise you will still be making trade-offs, but you will lack the knowledge to foresee the long term consequences of these decisions.
In my own opinion core business differentiators are where engineering resources should be used. That’s not to say a dependency that is more generic than the problem your business is trying to solve should never be pulled in house, but the decision to do that shouldn’t be taken lightly as it will increase the burden of learning, maintaining, documenting, testing, etc for a team that is being judged on the success of business objectives. To put it another way, the business will be hesitant to give you time to work on something that is only tangentially related to their objectives and quality can and usually will suffer which will put you in a worse position.
I think software development has some unique characteristics that makes NIH a problem. If you’re an electrical engineer you will never be given the resources to make a custom microcontroller or a new way of manufacturing a PCB unless that is what your company is selling; the upfront costs would be staggering and that would not be allowed. The limitations of the technology available is simply that, a constraint on what the business can do given current tech. Perhaps there is an opportunity for something better, but that would be best served as a new company focused on providing that solution if it can be done in an economically viable way. Software doesn’t have these massive upfront manufacturing costs that are obvious like the example above, but they still exist.
It doesn't even have to be related to quality of developers. Whatever tool chain or product you use, you're using someone else's dependencies. In some places more than others, but most people aren't implementing their own matrix multiplication code, and the ones that are, aren't implementing random library #24 which isn't in their core business. So this whole discussion happens on black and white terms when in fact people only care if they have regulatory obligations, or they have a particular personal interest in implementing something, or they got attached to that idea for a specific library. But nobody is applying this fully or they'd still be at the beach collecting sand.
We apply this pretty much fully at TigerBeetle [1].
Reason being that TigerStyle is not only about shipping safer software, but shipping it in less time [2], factoring in the Total Cost of Ownership to end users. In other words, not only optimizing our development time, but also all the time spent in production with subsequent fixes.
> But nobody is applying this fully or they'd still be at the beach collecting sand.
To this point I posit almost all of the "this good, that bad" type of posts are just "at my point on the abstraction continuum, this thing is better than that thing" without taking into account any context.
For most assembly is too low level for their context/use case, but for some, the C programming language is too HIGH level, as it was originally designed to be (but not for me).
> But the average developer, writing most line-of-business CRUD systems, well, quite honestly they're not that strong to begin with.
This is a wild take. Developers don't usually get to pick the system they work on, resource constraints exist during development time. We make tradeoff decisions every day and pulling in a "cheap" dependency will often make the difference between a shipped, working piece of software and plain "nothing".
You seem to be fairly little involved in actual software development, considering how generic and wrong this take is.
The problem, IMO, is that the trade-offs seem to always land on the side of “what ships faster.” That may well be the fault of PMs rather than SWEs, but either way, it doesn’t usually make for a sustainable product.
Isn't the industry still growing pretty quickly? If five years is enough to count as "senior", most won't be that good just because they haven't had time to get good yet. And any segment that's big enough or low enough margin won't be able to escape that average.
When looking at CVs and interviewing actively, it's honestly very easy to believe the quoted claim. Of course I work with some very skilled folks on line-of-business CRUD too so who knows.
I also don't quite like TigerBeetle as an example, because it is very new startup. They are pre-1.0 and just a bit more than a year since production release. It's way too early to tell whether their approach actually paid off.
While the company is 3 years old, TigerBeetle as an open source DBMS project actually started in 2020.
What we mean by "production" is also typically a bit different to what is typically meant.
For example, TigerBeetle is one of the first DBMS's to withstand an explicit storage fault model (i.e. disk corruption across all replicas). So the tolerances are a bit tighter for TigerBeetle, also with things like static memory allocation (cf. NASA's Power of Ten Rules for Safety-Critical Code).
Beyond this, when TigerBeetle was designed, it was (along with FoundationDB) one of few DBMS's to invest in a Deterministic Simulator in-house. Most DBMS's before 2020 were typically not designed from the ground up for Deterministic Simulation Testing (DST) and so now can only use Antithesis if they want to get into DST.
However, TB invests heavily in both, not only an external DST audit function, but more importantly, also our own internal DST audit function, which we designed and built entirely inhouse, and which can do considerably more damage to TigerBeetle because it's protocol-aware and understands how to push TB's consensus and storage to the breaking limit. In other words, not one DST simulator, but two, with “the VOPR” (the name for TB's own simulator) tailored to our fault models, and able to reach into any part of the code, across any machine in the simulation, and verify expectations. For example, do things like verify cache coherency between user space page cache and simulated storage engine.
Finally, if you're interested in the results of whether this rigid TigerStyle approach pays off, Kyle Kingsbury's Jepsen audit of TigerBeetle was one of the longest Jepsen engagements to date, and these were the findings: https://jepsen.io/analyses/tigerbeetle-0.16.11
I work at a medium company that is in a comparable sector implementing comparatively performant and externally constrained things pretty much wholly in C and pretty much wholly with our own dependencies with external dependencies being mostly located in ops, testing/qa and other stuff not in the critical path of what the people who pay us want the products to do. For us it's not about "built here" it's about control and uniformity. The company is a decade old and very profitable for its headcount though not subject to wild delusions about future hockey sticks because of what we build and for who.
So the approach clearly can work. It won't kill you. But it's also unclear the degree to which this approach contributed to vs detracted from our success since it's not like there's a control company that did it the other way you can compare to. It takes constant effort to do things this way, but so does managing dependencies. While unilateral control, and the responsibility for that, that comes with writing your own dependencies is a key aspect of how we do what we do with the headcount we do it's not like it's part of our marketing. It's just a decision that was made that we're sticking to because it seems to work for us. It's not some silver bullet, it takes effort to do well, like anything else done well.
I have worked at huge companies where they were biased toward using existing stuff where it existed and tweaking it just the bare minimum needed and that worked very well for them too and definitely had its pros too.
I pointed to tigerbeetle because they're one of the few companies I know of who 1) have a philosophy about dependencies and 2) talk about it openly in an easy to quote document.
I'm not sure if I succeeded, but I wanted to get across that I mean "dependency" in a very broad sense. Not just libraries, or services you interact with, but also what you need to build and deploy.
It wasn't a call to just not use dependencies. It was a call to think about them and be clear what you're depending on. Tigerbeetle have done that and given reasoning.
From the beginning, TigerStyle was intended not only for TigerBeetle as infrastructure, but for software (up and down the stack) in general.
Nobody wants buggier, slower software. And so TigerStyle as a methodology was codified primarily to address this problem: How to write “higher quality software in less time”? [1]
Before designing TigerBeetle, I was finding the principles more and more valuable, regardless of whether I was doing frontend or backend work, and so brought them into TigerBeetle.
Of course, software higher up is likely to use some dependencies, but there's always a cost, and this principle (“do more with less”), at least in my experience, tends to prove valuable when applied.
NIH is amazing as long as you are realistic about what you are taking ownership of.
For example, the cost of maintaining a bespoke web frontend "framework" that is specific to your problem domain is probably justifiable in many cases.
The same cannot be said for databases, game engines, web servers, cryptographic primitives, etc. If you have a problem so hard that no existing RDBMS or engine can support, you should seriously question the practicality of solving your problem at all. There's probably some theoretical constraint or view of the problem space you haven't discovered yet. Reorganizing the problem is a lot cheaper than reinventing the entire SQLite test suite from zero.
> The same cannot be said for databases, game engines, web servers, cryptographic primitives, etc.
It absolutely can in many cases.
- Many applications don't need much more of a database than files plus perhaps a runtime index. Spawning a database server or even embedding SQLite can be overkill in many cases.
- Most games would be better off with a bespoke game engine IMO, especially those made by small teams. The only real advantage to using an established engine is the familiar asset pipeline for replaceable artists but you pay for that with a huge overhead. Remember that custom engines or at least heavily modified ones maintained by the game developer used to be the norm - "just use Unity^WUnreal" is a relatively recent trend.
- There is no real difference in complexity between a simple web server and FastCGI application.
- Not all uses of cryptographic primitives are a security issues. If you calculate a hash to check against corruption you can implement that yourself (or copy an existing implementation) instead of pulling in a huge library. If your use cases is decrypting existing data offline then again you don't really care about cryptographic security only about getting the correctly decrypted output.
And there are many more cases like these. Learned helplessness when it comes to "hard" subjects helps no one.
Just because some existing solution "solves" your problem doesn't mean its the best or most efficient way to do it.
The latter already adds a lot of complexity, especially if the application has to scale up or out. If scaling up, the index will increase in complexity and re-implement some clever algorithms that have already been solved by the other. If scaling out, you'll need some locking mechanism if multiple processes can write. It quickly becomes logical to switch to an established solution then.
But the choice becomes more logical then; if one picks a scalable database or whatever without knowing they're going to need it, that's a lot of wasted effort.
> - Most games would be better off with a bespoke game engine IMO, especially those made by small teams.
I disagree; writing a game engine, even for simpler "indie" graphics, requires specialized knowledge and a dedicated engineer, whereas with off-the-shelf engines, non-programmer / creatives can build a good game without in-depth knowledge. A small team needs to be especially careful with what they choose to spend their time and money on, and solving a solved problem like building a game engine is a huge investment. Even big studios struggle with this, see also the dramatic release of Cyberpunk 20something by long-time own-engine-building veterans CDPR. They're switching to Unreal for Witcher 4.
> - Most games would be better off with a bespoke game engine IMO, especially those made by small teams. The only real advantage to using an established engine is the familiar asset pipeline for replaceable artists but you pay for that with a huge overhead. Remember that custom engines or at least heavily modified ones maintained by the game developer used to be the norm - "just use Unity^WUnreal" is a relatively recent trend.
I think we can take Square-Enix as a case study: Final Fantasy XV and Final Fantasy XVI both used their own engines (though XVI used a modification of XIV's engine, from what I hear) and both took a long fucking time to make. Granted, XV had many issues outside of just building a new engine, but it definitely added one more problem onto the pile. My understanding is that Final Fantasy XVI's development cycle was pretty smooth, it still took 7 years from the launch of Final Fantasy XV!
Final Fantasy VII: Remake and Final Fantasy VII: Rebirth both used Unreal Engine 4. While Remake had a long development cycle, Rebirth was done in 3 years and contained a much bigger world!
I do totally get that part of the argument is "reuse the same damn engine and tooling," and I totally agree with that, too. It's just a bit easier overall when you can reach out to a community with your problems instead of learning every problem for yourself.
The adventure of writing a custom DBMS, game engine, or other complex and advanced software classes can be justified by 1) knowing that no existing solution is adequate but 2) it is possible to write something suitable and 3) it will be useful enough to justify the cost.
For example, to insist on the example of Tigerbeetle, 1) no current popular or specialized DBMS is particularly optimized for ledger use, 2) but suitable techniques are well understood; I'm not sure how often 3) it will be preferred to a more general purpose DBMS.
> - Most games would be better off with a bespoke game engine IMO
You have it backwards.
Most games won't benefit from a bespoke game engine at all. Most games should use an existing engine (not necessarily one of the big names, just one that works) if their goal is to actually deliver a game.
Some games are so unique they won't benefit from an existing engine, and only then the dev team must take the extra step (and eat the delay) of building their own engine.
I mean commercial games of course. Experimental/hobby devs are free to do whatever, since in that case it's the journey and not the destination that matters.
Why are there so many different database engines then? Is each instance of a different database out their an instance of NIH?
The answer is of course that every computer system of any complexity has to make trade-offs - do you need constraints, do you need scalability, do you need concurrency, security? Is your data of a specific form that benefits from a particular compressible storage form, is it optimised for write once read many or read/write etc etc..
In terns of the thrust of the main article - which is about the cost of dependencies - I find that I'm typically much happier to take a dependency if that dependency is very keen on minimising it's own dependencies! - ie I don't want to take on a whole forest of stuff.
In my view many automatic dependency management systems have helped create the mess that they claim to try and solve, and using careful manual dependency management can help cut down the burden.
i can think of two reasons for using a third-party dependency
1) a dependency on a third-party service provider that publishes the dependency. So long as that service provider is current, the dependency should be maintained
2) short-cut to code i don't want to write
I have no arguments with (1), there's a business reason and the lifecycles should match. However, I should still expect major version breaking changes in order to keep my application running. For (2), the wins are less clear, more dependenent on the perceived complexity of what I can avoid writing.
Taking on any kind of dependency means that someone else can dictate when I need to spend time updating and testing changes that don't add anything to my product. Taking on a third-party dependency is always taking on a responsibility to maintain a codebase or the risk of not doing so.
I would argue that 2 is the much more important reason. A dependency is worth it if it saves you a lot of time building the same thing. For example, if you wanted to ship a general computing device, you should probably run Linux on it rather than building your own OS from scratch, because you'll save literal years of work. Even if Linux had stopped being maintained, this would still be the right call compared to building your own (of course, it would be even better to choose some other OS still being actively maintained, if any is available).
Theres a third one, when it comes to compliance and security tools, you don't want to build it even if you can because.
1. It is a liability
2. There is trust deficit during audit and other events. If audits are internal only sure you can build it but when it is 3rd party audited, auditors often know the product and familiar with the features.
This is where using boring languages like Go and Java come into their own: less frequent breaking changes.
There are some languages where communities aim for libraries to be stable for several months, and there’s others that think in terms of a decade or longer.
There is another solution which is to just retain the source for your dependencies and bring them in-house if needed. You still may need to abide by licenses, and many things shouldn’t need to rely on external deps, but I’ve seen a lot of wasted time that continues because we came up with our own way of doing something that others do better, and that can be difficult to get rid of because of unwarranted team pride or familiarity in the homegrown code or not wanting to trust the lone dev that says try this instead.
1) even though reality has proven us wrong time and time again, we can just not look at the dependency too closely and just act as if it's written and maintained by competent, caring people and is of highest quality. No worries!
2) in case shit hits the fan, let's assume worst case and there is a vuln in the dep and you get hacked... It's somebody else's fault! \o/
You fairly quickly run into problems a RDBMS can't solve. They're above all incredibly hamstringed by being built around supporting concurrent mutation of the data set and mutable datasets in general.
If you don't need that, even a fairly naive index implementation will get orders of magnitude more performance out of a computer than you will with a RDBMS if you can assume the data is immutable.
I'd tend to argue the opposite. Unless you have a problem that very explicitly is a poor match for an RDBMS, they are the easiest, most reliable, and most flexible way to manage data, separate your data from your application, and adapt or add functionality as new requirements come along.
There are plenty of RDBMS here (wikipedia lists some 100+ of them), there are plenty of problems most of them can not solve, but some of them do solve.
These people considered practicality of their solution and went forward doing the implementation.
Absolutely. A bunch of them also predated the www, or started just when the www was gaining popularity, meaning that information on possible products might be more limited than it is today. Some have narrow use-cases, and some might have started as really narrow in terms of scope, but then ballooned after gaining popularity, sales (and feature requests), and some probably started because the alternative was deemed too expensive compared to just making it in-house.
I think the main point bob1029 was trying to make is that it can be worthwhile doing somehting in-house if the alternatives doesn't match the use-case, are too expensive or whatever else - but that you seriously need to consider if your architecture is the best way to solve the problem before going down that route.
> as long as you are realistic about what you are taking ownership of
Including training and onboarding. There's a reason "popular" libraries, languages, patterns, etc. are popular. One "win" is the network effect when looking for talent - they can hit the ground at least jogging.
The technology is only part of the problem. If you aren't happy with any existing database, throwing even more technology at it is definitely not going to help - statistically speaking. You're up against millions of engineering hours in this space.
At some point, we need to get up from the computer and go talk to the business and customer about their problem in terms that don't involve anything more sophisticated than excel spreadsheets. There is definitely some aspect you missed if you think you need to build a fully custom technology vertical to get them to pay for a solution.
Of course, all of this advice is pointless if what you are doing is for amusement or as a hobby. I think a lot of arguments about technology would be diffused if we prefaced with our intended applications.
Dependencies introduce risks, but not using them at all puts you at a competitive disadvantage against those who are using them and thus achieve faster development time and time to market.
What you need is a process to manage dependencies:
1) Only consider open-source dependencies.
2) Introducing new dependencies requires a review. Not just a code review on the pull request introducing it, but checking the license, estimating how much work it would be to rip out, auditing it for history of security vulnerabilities or bugs, whether it is live and still gets updates, how vibrant the community is, and so on.
3) If possible, review your dependencies for possible security issues. Doing this at scale is expensive and the economics of this are still an unsolved problem (I have my ideas: https://blog.majid.info/supply-chain-vetting/).
4) Do not adopt a dependency you are not willing and able to take over the maintenance of, or fork if necessary. At a minimum, it means you have built it from source at least once, not just used binary packages maintained by someone else.
5) Preemptively fork all your dependencies. People can and do delete their repos out of pique, see left-pad.
Both 4) and 5) are very important, but often forgotten.
Even for my own personal (small) projects, i've gotten hit with problems when i take an extended leave of absence and then return to a project, only to find my dependencies have become either completely outdated and unusable, or the repo was entirely deleted (with only a remote copy to build with).
I've since adopted the "fork" method; the dependency's source is forked (privately), and get the dependency built; this is recursively done with their dependencies (stopping at the language level libraries), just to get familiar with their build chain. Only then, will i feel good enough to add the dependency to my project (and use their publicly released artefacts from their publicly hosted library repository). It's a bit of work, but i think this effort is spent upfront, and removes future effort if the project lives long enough to see the ecosystem move/change directions (and you dont want to follow).
Sometimes i do find that source libraries (rather than pre-built binaries) to be better in this sense. I merely need to fork and link the sources into the project, rather than have to learn anything about build chains of dependencies...
For #4, while I agree sometimes, I also recognize that SQLite (and other similar types of dependencies) are 100% going to outlive the product I'm building. So it's a bit arrogant to say my product is going to outlive them. I'm not going to build the Linux kernel just because it's a dependency.
I think it still applies if consider you can build SQLite from a fork of the source and it probably needs no maintenance. In some ways, you could consider the SQLite package that ships with a given distro/OS a mini-fork
Still, surprises happen. Key contributor(s) could become ill, license changes can happen, ownership/stewardship change. Although super popular projects you can _probably_ rely on someone else forking
Iirc one of the MariaDB engines was maintained by some singular dude that would go offline for months at a time and maintained it as a hobby.
4 and 5. Not at least once, all of your code should be at the very least buildable with a network cable yoinked out, preferably without any binary artifacts, but that is not always possible.
With 5, forking may be a bit excessive, as keeping your fork up to date adds a big maintenance burden. Vendoring dependencies (just pushing them into git, git LFS, or operating a caching proxy) is valid though, especially for long-lived software projects. Maybe less so for NodeJS based ones as their dependencies use many small files, but there's Yarn and maybe PNPM that will keep dependencies in more convenient archive files instead.
Being in the energy sector dependencies is something we intentionally avoid because we'd actually have to go through and review changes. What has helped this immensely is AI code assistance. One of the primary uses is to use it to write CLI tools for code and config generation in the tool chain. All of it is around making your life easier, without pulling external dependencies.
An example is that we create openapi docs with LLM's. Then we serve them with Go's net/http + FileServer, meaning that we never leave the standard library. Of course the LLM itself is a third party dependency, but when you use it to write CLI tools that then do the code generation, it never actually sees the code. That also means that the quality of those CLI tools are less important, because it is their output that matters.
It only goes so long of course. I'm not sure any of our front-end engineers would want to live in a world where they weren't allowed to use React, but then, their products are treated as though they are external anyway.
Anyway, it's a lot easier to make engineers stop using "quality of life" dependencies when you give them something that still makes their lives easy.
Doesn't the LLM spit out the code of the dependency it has been trained on?
How is that any different from just forking the dependency and treating it like your own?
One advantage might be that you would only implement the (small) part of the library that you actually need, potentially avoiding bugs such as Log4Shell.
The risk of code duplication is a serious one though, and it would be nice if AI could automatically detect and clean this.
I guess we are in an annoying "in-between" state of things, with a pretty unsure future.
Not necessarily, you can task the AI Agent with writing your tool without the use of external dependencies. Often the tool itself will be absolutely horrible, but this doesn't matter if the output of the tool is fine. As in the case of OpenAPI documentation, you basically get the LLM to write the equivalent of C#'s Swashbuckle (or whatever it's called these days) for your language. What it produces is horrible in comparison to the third party dependencies you would have pulled 5 years ago, but the output is the same.
You can also let it use outside dependencies, but then you're right, then it would make little difference in regards to security.
We figured this out because Go didn't have a "Swashbuckle", and nobody wanted to write the documentation or use codegens to go in the opposite direction. When it turned out to be so easy to use LLM's for these things, it grew into it's own thing in regards to replacing a lot of dependencies. Obviously the LLM is still the dependency, but you can replace all other external dependencies for a lot of things like this. Which means you won't acidentially pull something malicious.
I imagine we're going to see more and more of these in-house dependency replacement tools. Coming from Go, I obviously use SQLC (which is run inside it's own isolated container that is only available for requests from developers and is only updated by hand). If we couldn't run SQLC in total isolation then I imagine we would have had to build our own "SQLC". I haven't tried but I'm pretty confident that you could use LLM's to build a similar (but much worse in quality) tool. In an ideal world, we would have been allocated the resources we needed, but in reality, it would have just made us slower as "IT" is still viewed as a cost center on par with HR except that we aren't even "IT".
It’s easier to incrementally review the generated, specific code of an AI agent than it is to review a generic, overly featured long-lived library— and to keep on top of (and review) all changes to that library over time.
As well, paid dependencies usually only have one source of support, and when the company goes under or stops supporting the product you are in rough seas.
Given very few companies last forever, you have to assess if the trajectory of your project would be impacted by being coupled to their ability to support you.
For sure, this goes into the terrain of acquisition though, for which there are long-running procedures and assessment criteria. Long-term support / company longevity is one of them.
But likewise, these companies have the incentive to look like they have long-running success and can be relied upon for years / decades to come.
I've experienced some bad paid dependencies forced on us by a non-engineering team. I've had a few good experiences with "open core" kinds of dependencies that are widely used by the community, e.g. sidekiq, and therefore less likely to suddenly vanish one day as they would almost certainly get forked and maintained by others in the same boat.
The upside of paying for something is that, assuming the owner or company is stable, I don't have to worry about some unpaid solo maintainer burning out and never logging back in.
> My two cents. If a dependency is paid, than it is usually bad. Because the company providing that dependency has an incentive to lock you in.
Vendor lock-in is a risk for both purchased components and FOSS ones where the organization is unwilling to assume maintenance. The onus is on the team incorporating third-party component(s) to manage their risk, identify alternatives as appropriate, and modularize their solutions.
If a dependency is paid and it is bad, then maybe you just aren't paying enough for it.
If my code has a dependency then I want there to be people whose feel it is their job to support it.
Either there have to be enough people who are paid to support it, or there have to be enough people whose self-worth and identity is so wrapped up in the code that they take it as a point of honor to support it.
I don't need a company that's likely to abandon a code product and leave me hanging. I also don't need a free software author who says "bugs are not my problem - you have the source, go fix it yourself." If those are my choices, I'd rather write it myself.
> I want there to be people whose feel it is their job to support it.
their "feeling" will not change reality, which might conflict. For example, a specialized database vendor would prefer that you cannot move away, and even if they feel like they want to support you, there are other economic factors to consider which could override this.
I think the idea is that if you are paying, the dependency needs to implement some sort of open standard/interface to which there are at least one other implementation you could move to. The vendor cannot lock you in with this requirement, since you always would have the option to move (despite it being a bit expensive, it's just there as a threat).
Well, as a battle-scarred old war horse, I can say that "It Depends™."
I have found that "It Depends™" is a mantra for almost everything that I do, and experience has given me the ability to choose a fork in the road, when an "It Depends™" moment happens.
When I was younger, my world was governed by "hard and fast" rules. There could be no exceptions, and some of the worst code I wrote, consisted of the gymnastics required to shoehorn an unsuitable library/paradigm into my projects.
I tend to use a lot of self-developed dependencies. They are really distillations of things that I do frequently, so I factor them into standalone packages. That way, I don't have to reinvent the wheel, and I'm confident of the Quality and provenance.
But if there's functionality that is required, and beyond me, for whatever reason, I am always open to including dependencies, as long as I can reconcile myself to their quality and other issues.
People love to claim this, especially on this site, but in my experience it's the opposite. Many people like writing new code and will do it even when it's detrimental to the business, but 9 times out of 10 even using a "bad" dependency is far more effective than writing in-house.
Most vocal people work on "disposable" end of software. It's cheaper for software giants to just throw engineer-hours at rewriting piece of code that has fallen into organizational obscurity than to maintain (hehe) maintainability. There is usually no sense for small branding/webshop factories to churn out high quality, maintainable code.
However, I suggest you revisit the reason why the dreaded "enterprise patterns" exist in the first place. The main reason to use these architectures is so that five years down the line, when documentation is badly outdated, there is no organizational memory left behind that component, original developers have transitioned to either different teams/departments or left the company altogether, the component is still well isolated, analyzable and possible to work on.
Introduction of external dependency(-ies) carry two inherent business risks: either support for dependency will be dropped, meaning you will have to either absorb maintenance burden yourself or switch dependencies, or it will introduce breaking changes, meaning you have to stick to unmaintained version or update your product code. Both situations will eventually impact your feature flow, whatever it is.
Compromise between trunk and leaf (push of dependencies vs pull of deps) is intrinsic to modularization and is always there, however with internal components this compromise is internal, rather external.
> Many people like writing new code and will do it even when it's detrimental to the business, but 9 times out of 10 even using a "bad" dependency is far more effective than writing in-house.
If you are a SaaS company - most probably yes as it is the short-term outcome that is determinate of business success. However, if you work in any industry with safety and support requirements on software or put the burden of long term support on yourself, long-term horizon is more indicative of business success.
Remember, writing new code is almost never the bottleneck in any mature-ish organization.
> five years down the line, when documentation is badly outdated, there is no organizational memory left behind that component, original developers have transitioned to either different teams/departments or left the company altogether, the component is still well isolated, analyzable and possible to work on.
This will be far more true for an external dependency - even one that's no longer actively developed - than for an internally developed component, IME. Just at the most basic level an external dependency has to have some level of documentation and at least be usable by someone other than the original author to even get picked up.
> Introduction of external dependency(-ies) carry two inherent business risks: either support for dependency will be dropped, meaning you will have to either absorb maintenance burden yourself or switch dependencies, or it will introduce breaking changes, meaning you have to stick to unmaintained version or update your product code. Both situations will eventually impact your feature flow, whatever it is.
Sure, you need stay up to date, potentially even take over maintenance yourself, or accept the risk of not doing so, and none of that is free. But writing an internal implementation basically puts you in the worst-case scenario by default - you have to maintain the code yourself, and it's probably less maintainable than an external codebase.
Can I ask how seriously your company takes security vulnerabilities and licensing? I used to have a pretty lax attitude toward dependencies, but that changed significantly when I joined a company that takes those things very seriously.
I've worked with many companies over the years. License management should be automatic or mostly-automatic if you're taking dependency management seriously (particularly these days where so many projects use well-known open-source licenses and everything is machine-readable metadata), and I've never seen a single in-house codebase (even at e.g. F500 financial institutions) that took security more seriously than your average open-source library.
I think just about every experienced developer I know - most of whom are not from NZ - would agree with this article. We've all been burned by using the wrong dependency for the job at some point, or the pain of having to deal breaking changes when upgrading a library that really wasn't necessary to use in the first place.
To push back on this article's thrust, those are actual issues that can occur with dependencies. It's just that they usually don't, and most dependencies are harmless, small, and transparent, so articles like this and people complaining about dependencies are almost always overstating their case.
And therefore, adopting a "zero dependencies" policy is absolutely an overreaction.
Wow. Yeah. If you're writing a financial ledger transactions database from scratch in Zig, where safety and performance are your top two goals, so that you can credibly handle a million transactions per second on a single CPU core, well, damn right you can't afford to take any risks on introducing any dependencies. Makes absolute perfect sense to me (no sarcasm).
But the average developer, writing most line-of-business CRUD systems, well, quite honestly they're not that strong to begin with. Most dependencies may be bug-infested garbage, but they're still higher quality compared to what most developers are capable of. Most companies are bottlenecked by the caliber of talent they can realistically recruit and retain; and internal development standards reflect the average caliber on the payroll.
So like most advice you read on the internet, remember, everybody is in different circumstances; and polar opposite pieces of advice can both be correct in different circumstances.
+100, context is the key thing, both TigerBeetle and rust-analyzer have strong culture of how the things are done, but the _specific_ culture is quite different, because they solve very different problems.
That being said, I _think_ you might be pattern-matching a bit against the usual dependencies good/dependencies bad argument, and the TFA is on a different level. Note the examples of dependencies used: POSIX, ECMA-48, the web platform. These are not libraries, these are systems interfaces!
Dependency on a library is not a big deal --- if it starts to bite, you can just rewrite the code! But dependency on that underlying thing that the library does is usually something that can't be changed, or extremely costly to change. Answering "No" to "is doing X in scope for my software?" is powerful
To refer to the sibling comment, if there's a team whose core business is writing matrix multiplication code, they _can_ use random library #24 for something else, but often, if you apply some software design, you might realize that the product surrounding matrix multiplication _shouldn't_ handle concern #24. It doesn't mean that concern #24 isn't handled by anything at all, rather that we try to find _better_ factoring of the overall system to compartmentalize essential dependencies.
The tech world has this tendency to dumb down every advice so it caters to the lowest common denominator, but I honestly have never worked in such an environment where developers couldn't learn to duplicate the functionality of shitty dependencies while at the same time fixing the problem.
And as much as people love to mock CRUD, bad abstractions can be a horrible drain on teams doing CRUD work. And even the popular stuff can often suck and be a timesink unless you're doing absolutely basic stuff that's just repeating the tutorial.
The funny thing is that no advice is dumbed-down enough for them. They will take anything you can say and implement wrongly.
That idea that if you dumb-down everything, it will be helpful is just plain bullshit. People that can't duplicate a dependency just can't choose the right dependency either, and if you force them to use some good one, they will use it wrong.
I have absolutely seen this. It’s not a matter of them being bad developers, but no one is an expert in all things and gaining expertise takes time which costs money. All dependencies have a lot of trade-offs baked in that must be re-evaluated if you decide to go the NIH route, and that’s usually where expertise is needed. If you lack the expertise you will still be making trade-offs, but you will lack the knowledge to foresee the long term consequences of these decisions.
In my own opinion core business differentiators are where engineering resources should be used. That’s not to say a dependency that is more generic than the problem your business is trying to solve should never be pulled in house, but the decision to do that shouldn’t be taken lightly as it will increase the burden of learning, maintaining, documenting, testing, etc for a team that is being judged on the success of business objectives. To put it another way, the business will be hesitant to give you time to work on something that is only tangentially related to their objectives and quality can and usually will suffer which will put you in a worse position.
I think software development has some unique characteristics that makes NIH a problem. If you’re an electrical engineer you will never be given the resources to make a custom microcontroller or a new way of manufacturing a PCB unless that is what your company is selling; the upfront costs would be staggering and that would not be allowed. The limitations of the technology available is simply that, a constraint on what the business can do given current tech. Perhaps there is an opportunity for something better, but that would be best served as a new company focused on providing that solution if it can be done in an economically viable way. Software doesn’t have these massive upfront manufacturing costs that are obvious like the example above, but they still exist.
AI may change this calculus.
HN is a bubble, the world runs on "meh".
Reason being that TigerStyle is not only about shipping safer software, but shipping it in less time [2], factoring in the Total Cost of Ownership to end users. In other words, not only optimizing our development time, but also all the time spent in production with subsequent fixes.
[1] https://tigerbeetle.com/blog/2025-02-27-why-we-designed-tige...
[2] https://www.youtube.com/watch?v=w3WYdYyjek4
To this point I posit almost all of the "this good, that bad" type of posts are just "at my point on the abstraction continuum, this thing is better than that thing" without taking into account any context.
For most assembly is too low level for their context/use case, but for some, the C programming language is too HIGH level, as it was originally designed to be (but not for me).
This is a wild take. Developers don't usually get to pick the system they work on, resource constraints exist during development time. We make tradeoff decisions every day and pulling in a "cheap" dependency will often make the difference between a shipped, working piece of software and plain "nothing". You seem to be fairly little involved in actual software development, considering how generic and wrong this take is.
While the company is 3 years old, TigerBeetle as an open source DBMS project actually started in 2020.
What we mean by "production" is also typically a bit different to what is typically meant.
For example, TigerBeetle is one of the first DBMS's to withstand an explicit storage fault model (i.e. disk corruption across all replicas). So the tolerances are a bit tighter for TigerBeetle, also with things like static memory allocation (cf. NASA's Power of Ten Rules for Safety-Critical Code).
Beyond this, when TigerBeetle was designed, it was (along with FoundationDB) one of few DBMS's to invest in a Deterministic Simulator in-house. Most DBMS's before 2020 were typically not designed from the ground up for Deterministic Simulation Testing (DST) and so now can only use Antithesis if they want to get into DST.
However, TB invests heavily in both, not only an external DST audit function, but more importantly, also our own internal DST audit function, which we designed and built entirely inhouse, and which can do considerably more damage to TigerBeetle because it's protocol-aware and understands how to push TB's consensus and storage to the breaking limit. In other words, not one DST simulator, but two, with “the VOPR” (the name for TB's own simulator) tailored to our fault models, and able to reach into any part of the code, across any machine in the simulation, and verify expectations. For example, do things like verify cache coherency between user space page cache and simulated storage engine.
Finally, if you're interested in the results of whether this rigid TigerStyle approach pays off, Kyle Kingsbury's Jepsen audit of TigerBeetle was one of the longest Jepsen engagements to date, and these were the findings: https://jepsen.io/analyses/tigerbeetle-0.16.11
So the approach clearly can work. It won't kill you. But it's also unclear the degree to which this approach contributed to vs detracted from our success since it's not like there's a control company that did it the other way you can compare to. It takes constant effort to do things this way, but so does managing dependencies. While unilateral control, and the responsibility for that, that comes with writing your own dependencies is a key aspect of how we do what we do with the headcount we do it's not like it's part of our marketing. It's just a decision that was made that we're sticking to because it seems to work for us. It's not some silver bullet, it takes effort to do well, like anything else done well.
I have worked at huge companies where they were biased toward using existing stuff where it existed and tweaking it just the bare minimum needed and that worked very well for them too and definitely had its pros too.
I pointed to tigerbeetle because they're one of the few companies I know of who 1) have a philosophy about dependencies and 2) talk about it openly in an easy to quote document.
I'm not sure if I succeeded, but I wanted to get across that I mean "dependency" in a very broad sense. Not just libraries, or services you interact with, but also what you need to build and deploy.
It wasn't a call to just not use dependencies. It was a call to think about them and be clear what you're depending on. Tigerbeetle have done that and given reasoning.
From the beginning, TigerStyle was intended not only for TigerBeetle as infrastructure, but for software (up and down the stack) in general.
Nobody wants buggier, slower software. And so TigerStyle as a methodology was codified primarily to address this problem: How to write “higher quality software in less time”? [1]
Before designing TigerBeetle, I was finding the principles more and more valuable, regardless of whether I was doing frontend or backend work, and so brought them into TigerBeetle.
Of course, software higher up is likely to use some dependencies, but there's always a cost, and this principle (“do more with less”), at least in my experience, tends to prove valuable when applied.
[1] Some of the background motivation behind TigerStyle: https://www.youtube.com/watch?v=w3WYdYyjek4
Deleted Comment
For example, the cost of maintaining a bespoke web frontend "framework" that is specific to your problem domain is probably justifiable in many cases.
The same cannot be said for databases, game engines, web servers, cryptographic primitives, etc. If you have a problem so hard that no existing RDBMS or engine can support, you should seriously question the practicality of solving your problem at all. There's probably some theoretical constraint or view of the problem space you haven't discovered yet. Reorganizing the problem is a lot cheaper than reinventing the entire SQLite test suite from zero.
It absolutely can in many cases.
- Many applications don't need much more of a database than files plus perhaps a runtime index. Spawning a database server or even embedding SQLite can be overkill in many cases.
- Most games would be better off with a bespoke game engine IMO, especially those made by small teams. The only real advantage to using an established engine is the familiar asset pipeline for replaceable artists but you pay for that with a huge overhead. Remember that custom engines or at least heavily modified ones maintained by the game developer used to be the norm - "just use Unity^WUnreal" is a relatively recent trend.
- There is no real difference in complexity between a simple web server and FastCGI application.
- Not all uses of cryptographic primitives are a security issues. If you calculate a hash to check against corruption you can implement that yourself (or copy an existing implementation) instead of pulling in a huge library. If your use cases is decrypting existing data offline then again you don't really care about cryptographic security only about getting the correctly decrypted output.
And there are many more cases like these. Learned helplessness when it comes to "hard" subjects helps no one.
Just because some existing solution "solves" your problem doesn't mean its the best or most efficient way to do it.
The latter already adds a lot of complexity, especially if the application has to scale up or out. If scaling up, the index will increase in complexity and re-implement some clever algorithms that have already been solved by the other. If scaling out, you'll need some locking mechanism if multiple processes can write. It quickly becomes logical to switch to an established solution then.
But the choice becomes more logical then; if one picks a scalable database or whatever without knowing they're going to need it, that's a lot of wasted effort.
> - Most games would be better off with a bespoke game engine IMO, especially those made by small teams.
I disagree; writing a game engine, even for simpler "indie" graphics, requires specialized knowledge and a dedicated engineer, whereas with off-the-shelf engines, non-programmer / creatives can build a good game without in-depth knowledge. A small team needs to be especially careful with what they choose to spend their time and money on, and solving a solved problem like building a game engine is a huge investment. Even big studios struggle with this, see also the dramatic release of Cyberpunk 20something by long-time own-engine-building veterans CDPR. They're switching to Unreal for Witcher 4.
I think we can take Square-Enix as a case study: Final Fantasy XV and Final Fantasy XVI both used their own engines (though XVI used a modification of XIV's engine, from what I hear) and both took a long fucking time to make. Granted, XV had many issues outside of just building a new engine, but it definitely added one more problem onto the pile. My understanding is that Final Fantasy XVI's development cycle was pretty smooth, it still took 7 years from the launch of Final Fantasy XV!
Final Fantasy VII: Remake and Final Fantasy VII: Rebirth both used Unreal Engine 4. While Remake had a long development cycle, Rebirth was done in 3 years and contained a much bigger world!
I do totally get that part of the argument is "reuse the same damn engine and tooling," and I totally agree with that, too. It's just a bit easier overall when you can reach out to a community with your problems instead of learning every problem for yourself.
Perhaps, but that would mean most of those games would never get shipped.
> If you calculate a hash ... instead of pulling in a huge library.
This is a bit of a strawman; what hash calcs require "a huge library"?
For example, to insist on the example of Tigerbeetle, 1) no current popular or specialized DBMS is particularly optimized for ledger use, 2) but suitable techniques are well understood; I'm not sure how often 3) it will be preferred to a more general purpose DBMS.
You have it backwards.
Most games won't benefit from a bespoke game engine at all. Most games should use an existing engine (not necessarily one of the big names, just one that works) if their goal is to actually deliver a game.
Some games are so unique they won't benefit from an existing engine, and only then the dev team must take the extra step (and eat the delay) of building their own engine.
I mean commercial games of course. Experimental/hobby devs are free to do whatever, since in that case it's the journey and not the destination that matters.
The answer is of course that every computer system of any complexity has to make trade-offs - do you need constraints, do you need scalability, do you need concurrency, security? Is your data of a specific form that benefits from a particular compressible storage form, is it optimised for write once read many or read/write etc etc..
In terns of the thrust of the main article - which is about the cost of dependencies - I find that I'm typically much happier to take a dependency if that dependency is very keen on minimising it's own dependencies! - ie I don't want to take on a whole forest of stuff.
In my view many automatic dependency management systems have helped create the mess that they claim to try and solve, and using careful manual dependency management can help cut down the burden.
Don't forget, do you need someone you can call for support (or throw under the bus) when problems come up?
1) a dependency on a third-party service provider that publishes the dependency. So long as that service provider is current, the dependency should be maintained 2) short-cut to code i don't want to write
I have no arguments with (1), there's a business reason and the lifecycles should match. However, I should still expect major version breaking changes in order to keep my application running. For (2), the wins are less clear, more dependenent on the perceived complexity of what I can avoid writing.
Taking on any kind of dependency means that someone else can dictate when I need to spend time updating and testing changes that don't add anything to my product. Taking on a third-party dependency is always taking on a responsibility to maintain a codebase or the risk of not doing so.
1. It is a liability
2. There is trust deficit during audit and other events. If audits are internal only sure you can build it but when it is 3rd party audited, auditors often know the product and familiar with the features.
There are some languages where communities aim for libraries to be stable for several months, and there’s others that think in terms of a decade or longer.
1) even though reality has proven us wrong time and time again, we can just not look at the dependency too closely and just act as if it's written and maintained by competent, caring people and is of highest quality. No worries!
2) in case shit hits the fan, let's assume worst case and there is a vuln in the dep and you get hacked... It's somebody else's fault! \o/
If you don't need that, even a fairly naive index implementation will get orders of magnitude more performance out of a computer than you will with a RDBMS if you can assume the data is immutable.
There are plenty of RDBMS here (wikipedia lists some 100+ of them), there are plenty of problems most of them can not solve, but some of them do solve.
These people considered practicality of their solution and went forward doing the implementation.
I think the main point bob1029 was trying to make is that it can be worthwhile doing somehting in-house if the alternatives doesn't match the use-case, are too expensive or whatever else - but that you seriously need to consider if your architecture is the best way to solve the problem before going down that route.
Deleted Comment
Including training and onboarding. There's a reason "popular" libraries, languages, patterns, etc. are popular. One "win" is the network effect when looking for talent - they can hit the ground at least jogging.
Sure, but if you aren't happy with existing DBs you are probably wrong in thinking you need a general DB instead of a file layout on a filesystem.
Portability is a problem as well.
You do not need an SQL database however, there are others available.
At some point, we need to get up from the computer and go talk to the business and customer about their problem in terms that don't involve anything more sophisticated than excel spreadsheets. There is definitely some aspect you missed if you think you need to build a fully custom technology vertical to get them to pay for a solution.
Of course, all of this advice is pointless if what you are doing is for amusement or as a hobby. I think a lot of arguments about technology would be diffused if we prefaced with our intended applications.
What you need is a process to manage dependencies:
1) Only consider open-source dependencies.
2) Introducing new dependencies requires a review. Not just a code review on the pull request introducing it, but checking the license, estimating how much work it would be to rip out, auditing it for history of security vulnerabilities or bugs, whether it is live and still gets updates, how vibrant the community is, and so on.
3) If possible, review your dependencies for possible security issues. Doing this at scale is expensive and the economics of this are still an unsolved problem (I have my ideas: https://blog.majid.info/supply-chain-vetting/).
4) Do not adopt a dependency you are not willing and able to take over the maintenance of, or fork if necessary. At a minimum, it means you have built it from source at least once, not just used binary packages maintained by someone else.
5) Preemptively fork all your dependencies. People can and do delete their repos out of pique, see left-pad.
Even for my own personal (small) projects, i've gotten hit with problems when i take an extended leave of absence and then return to a project, only to find my dependencies have become either completely outdated and unusable, or the repo was entirely deleted (with only a remote copy to build with).
I've since adopted the "fork" method; the dependency's source is forked (privately), and get the dependency built; this is recursively done with their dependencies (stopping at the language level libraries), just to get familiar with their build chain. Only then, will i feel good enough to add the dependency to my project (and use their publicly released artefacts from their publicly hosted library repository). It's a bit of work, but i think this effort is spent upfront, and removes future effort if the project lives long enough to see the ecosystem move/change directions (and you dont want to follow).
Sometimes i do find that source libraries (rather than pre-built binaries) to be better in this sense. I merely need to fork and link the sources into the project, rather than have to learn anything about build chains of dependencies...
Still, surprises happen. Key contributor(s) could become ill, license changes can happen, ownership/stewardship change. Although super popular projects you can _probably_ rely on someone else forking
Iirc one of the MariaDB engines was maintained by some singular dude that would go offline for months at a time and maintained it as a hobby.
The only problem I really see is very tall dependency trees, seen in e.g. the JavaScript world.
An example is that we create openapi docs with LLM's. Then we serve them with Go's net/http + FileServer, meaning that we never leave the standard library. Of course the LLM itself is a third party dependency, but when you use it to write CLI tools that then do the code generation, it never actually sees the code. That also means that the quality of those CLI tools are less important, because it is their output that matters.
It only goes so long of course. I'm not sure any of our front-end engineers would want to live in a world where they weren't allowed to use React, but then, their products are treated as though they are external anyway.
Anyway, it's a lot easier to make engineers stop using "quality of life" dependencies when you give them something that still makes their lives easy.
The risk of code duplication is a serious one though, and it would be nice if AI could automatically detect and clean this.
I guess we are in an annoying "in-between" state of things, with a pretty unsure future.
You can also let it use outside dependencies, but then you're right, then it would make little difference in regards to security.
We figured this out because Go didn't have a "Swashbuckle", and nobody wanted to write the documentation or use codegens to go in the opposite direction. When it turned out to be so easy to use LLM's for these things, it grew into it's own thing in regards to replacing a lot of dependencies. Obviously the LLM is still the dependency, but you can replace all other external dependencies for a lot of things like this. Which means you won't acidentially pull something malicious.
I imagine we're going to see more and more of these in-house dependency replacement tools. Coming from Go, I obviously use SQLC (which is run inside it's own isolated container that is only available for requests from developers and is only updated by hand). If we couldn't run SQLC in total isolation then I imagine we would have had to build our own "SQLC". I haven't tried but I'm pretty confident that you could use LLM's to build a similar (but much worse in quality) tool. In an ideal world, we would have been allocated the resources we needed, but in reality, it would have just made us slower as "IT" is still viewed as a cost center on par with HR except that we aren't even "IT".
Dead Comment
My two cents. If a dependency is paid, than it is usually bad. Because the company providing that dependency has an incentive to lock you in.
As another point, "dependency minimalism" is a nice name for it. https://x.com/VitalikButerin/status/1880324753170256005
Given very few companies last forever, you have to assess if the trajectory of your project would be impacted by being coupled to their ability to support you.
But likewise, these companies have the incentive to look like they have long-running success and can be relied upon for years / decades to come.
Or, even worse, gets acquired by someone like Salesforce
The upside of paying for something is that, assuming the owner or company is stable, I don't have to worry about some unpaid solo maintainer burning out and never logging back in.
and continues to be stable for the lifetime of your product.
Vendor lock-in is a risk for both purchased components and FOSS ones where the organization is unwilling to assume maintenance. The onus is on the team incorporating third-party component(s) to manage their risk, identify alternatives as appropriate, and modularize their solutions.
If my code has a dependency then I want there to be people whose feel it is their job to support it.
Either there have to be enough people who are paid to support it, or there have to be enough people whose self-worth and identity is so wrapped up in the code that they take it as a point of honor to support it.
I don't need a company that's likely to abandon a code product and leave me hanging. I also don't need a free software author who says "bugs are not my problem - you have the source, go fix it yourself." If those are my choices, I'd rather write it myself.
their "feeling" will not change reality, which might conflict. For example, a specialized database vendor would prefer that you cannot move away, and even if they feel like they want to support you, there are other economic factors to consider which could override this.
I have found that "It Depends™" is a mantra for almost everything that I do, and experience has given me the ability to choose a fork in the road, when an "It Depends™" moment happens.
When I was younger, my world was governed by "hard and fast" rules. There could be no exceptions, and some of the worst code I wrote, consisted of the gymnastics required to shoehorn an unsuitable library/paradigm into my projects.
I tend to use a lot of self-developed dependencies. They are really distillations of things that I do frequently, so I factor them into standalone packages. That way, I don't have to reinvent the wheel, and I'm confident of the Quality and provenance.
But if there's functionality that is required, and beyond me, for whatever reason, I am always open to including dependencies, as long as I can reconcile myself to their quality and other issues.
Most vocal people work on "disposable" end of software. It's cheaper for software giants to just throw engineer-hours at rewriting piece of code that has fallen into organizational obscurity than to maintain (hehe) maintainability. There is usually no sense for small branding/webshop factories to churn out high quality, maintainable code.
However, I suggest you revisit the reason why the dreaded "enterprise patterns" exist in the first place. The main reason to use these architectures is so that five years down the line, when documentation is badly outdated, there is no organizational memory left behind that component, original developers have transitioned to either different teams/departments or left the company altogether, the component is still well isolated, analyzable and possible to work on.
Introduction of external dependency(-ies) carry two inherent business risks: either support for dependency will be dropped, meaning you will have to either absorb maintenance burden yourself or switch dependencies, or it will introduce breaking changes, meaning you have to stick to unmaintained version or update your product code. Both situations will eventually impact your feature flow, whatever it is.
Compromise between trunk and leaf (push of dependencies vs pull of deps) is intrinsic to modularization and is always there, however with internal components this compromise is internal, rather external.
> Many people like writing new code and will do it even when it's detrimental to the business, but 9 times out of 10 even using a "bad" dependency is far more effective than writing in-house.
If you are a SaaS company - most probably yes as it is the short-term outcome that is determinate of business success. However, if you work in any industry with safety and support requirements on software or put the burden of long term support on yourself, long-term horizon is more indicative of business success.
Remember, writing new code is almost never the bottleneck in any mature-ish organization.
This will be far more true for an external dependency - even one that's no longer actively developed - than for an internally developed component, IME. Just at the most basic level an external dependency has to have some level of documentation and at least be usable by someone other than the original author to even get picked up.
> Introduction of external dependency(-ies) carry two inherent business risks: either support for dependency will be dropped, meaning you will have to either absorb maintenance burden yourself or switch dependencies, or it will introduce breaking changes, meaning you have to stick to unmaintained version or update your product code. Both situations will eventually impact your feature flow, whatever it is.
Sure, you need stay up to date, potentially even take over maintenance yourself, or accept the risk of not doing so, and none of that is free. But writing an internal implementation basically puts you in the worst-case scenario by default - you have to maintain the code yourself, and it's probably less maintainable than an external codebase.
[1]https://en.wikipedia.org/wiki/Number_8_wire#:~:text=Accordin...
And therefore, adopting a "zero dependencies" policy is absolutely an overreaction.
Deleted Comment