less_retarded_wiki/dependency.md
2024-10-15 22:22:58 +02:00

53 lines
8.9 KiB
Markdown

# Dependency
Dependency of a piece of [technology](technology.md) is another piece of technology that's required for the former to [work](work.md) (typically e.g. a [software](software.md) [library](library.md) that's required by given computer [program](program.md)). Dependencies are [bad](shit.md)! Among programmers the term **dependency hell** refers to a very common situation of having to deal with the headaches of managing dependencies (and [recursively](recursion.md) dependencies of those dependencies). Unfortunately dependencies are also unavoidable. However we at least try to minimize dependencies as much as possible while keeping our program functioning as intended, and those we can't avoid we try to abstract (see [portability](portability.md)) in order to be able to quickly drop-in replace them with alternatives. It turns out with good approach we can minimize dependencies very close to zero.
Having many dependencies is a sign of **[bloat](bloat.md) and bad design**. Unfortunately this is the reality of mainstream "[modern](modern.md)" programming. For example at the time of writing this [Chromium](chromium.md) in [Debian](debian.md) requires (recursively) 395 packages [LMAO](lmao.md) xD And these are just runtime dependency packages, we aren't even counting all the hardware features each of this package relies on etc...
Though dependencies are primarily bad because they endanger whole functionality of a program as such, i.e. "it simply won't run without it", they are also bad for another reason: you have no control over how a dependency behaves, if it is implemented well and if it behaves consistently. [OpenGL](opengl.md) for example caused a lot of trouble by this because even though the API is the same, different OpenGL implementations performed differently under different situations and made one game run fast with certain combinations of GPUs and drivers and slow with others, which is why [Vulkan](vulkan.md) (lower level API) was created. It is also why some programmers write their own memory allocation functions even though they are available in the standard library etc. -- they know they can write one that's fast and will be fast where they want it to be. Even if your own function might on average be slower than that offered by the language, the consistency, control and knowledge of how exactly it behaves is often worth the price.
In [software](software.md) development context we usually talk about software dependencies, typically [libraries](library.md) and other software [packages](package.md) such as various [frameworks](framework.md). However, there are many other types of dependencies we need to consider when striving for the best programs. Let us list just some of the possible types:
- [software](software.md)
- [libraries](library.md)
- [compiler](compiler.md) supporting specific language standard, extensions etc.
- [build system](build_system.md)
- [GUI](gui.md) capabilities
- [operating system](operating_system.md) and its services such as support of [multitasking](multitasking.md), presence of a [window manager](window_manager.md), [desktop environment](desktop_environment.md), presence of a [file system](file_system.md) etc.
- ...
- [hardware](hardware.md)
- sufficient [computing resources](computing_resources.md) (enough [RAM](ram.md), CPU frequency and cores, ...)
- [graphics card](gpu.md) with supported features
- [floating point unit](fpu.md) and other [coprocessors](coprocessor.md)
- CPU features such as special instructions, modes, ...
- [network](networking.md)/[Internet](internet.md) connection
- [mouse](mouse.md), [speakers](monitor.md) and other I/O devices
- ...
- other:
- know-how/education: Your program may require specific knowledge, e.g. knowledge of advanced math to be able to meaningfully modify the program, or nonnegligiable amount of time spent studying your codebase.
- running cost: e.g. electricity, Internet connection cost
- culture: Your program may require the culture to allow what it is presenting or dealing with.
- ...
Good program will take into account ALL kinds of these dependencies and try to minimize them to offer [freedom](freedom.md), stability and safety while keeping its functionality or reducing it only very little.
Why are dependencies so bad? Because your program is for example:
- **more [buggy](bug.md)** (more [fuck up surface](fuck_up_surface.md))
- **less [portable](portability.md)** (to port the program you also need to port or replace all the dependencies)
- **more expensive to [maintain](maintenance.md) (and create)** (requires someone's constant attention to just keep the dependencies up to date and keeping up with their changing [API](api.md))
- **less [future proof](future_proof.md)** and **more fragile** (your program dies as soon as one of its dependencies, or any dependency of these dependencies...)
- **more [bloated](bloat.md) and so probably less efficient**, i.e. slower, eating up more [RAM](ram.md) than necessary etc.
- **less under your control** (in practice it's extremely difficult to [fork](fork.md), modify and maintain a library you depend on even if it's [free](free_software.md) as you just take up another project to learn and maintain, so you're typically doomed to just accept whatever is offered to you)
- **less "secure"** (more [attack surface](attack_surface.md), i.e. potential for vulnerabilities which may arise in the dependencies) -- though we don't fancy the [privacy](privacy.md)/[security](security.md) hysteria, it is something that matters to many
- **more dangerous [legally](law.md)** (reusing work of other people requires dealing with several to many different licenses with possibly wild conditions and there's always a chance of someone starting to make trouble such as threatening to withdraw a license)
- **more complicated to develop and work with**, customize, modify etc. -- a nice program with few dependencies is built very simply: you just download the source and compile it. A program with tons of dependencies will require a complex set up of all the dependencies (and their dependencies) first, making sure they're of the required versions, and then you have to build EVERYTHING of course, usually adding the need for some complex build system to even make recompiling bearable (because building everything from scratch may take hours).
- ...
Really it can't be stressed enough that **ALL dependencies have to be considered**, even things such as the [standard library](stdlib.md) of a programming language or built-in features of a language that "should always" come with the language. It is common to hear C programmers say "I can just use float because it's part of C specification and so it has to be there" -- well technically yes, but in practice many C implementations for some obscure platforms will end up being unfinished, incomplete or even intentionally non-compliant with the standard, no standard can really physically force people to follow it, OR the compiler's floating point implementation may simply suck (or it HAS TO suck because there's no floating point hardware on the platform) so much that it will technically be present but practically unusable. This will mean that your program COULD work on the platform but DOESN'T, even if some piece of paper somewhere says it SHOULD. So REALLY REALLY do not use non-trivial features that you don't really need, it really does help. If you really want to make your program truly dependency light, always ask something like this: "If our civilization and all its computers disappear and only the literal text of my program survives, how hard will it be for future civilizations to make it actually run?".
## How to Avoid Them
**The final solution** to dealing with dependencies is to make your system (program, OS, whatever) **[bootstrap](bootstrap.md)** from a very simple system -- let's say some abstract [bytecode](bytecode.md) that's quite easy to implement from scratch. If your program and all of its dependencies only rely on a machine capable of running such bytecode, your program will run anywhere where you implement the bytecode and where there is enough computing resources. Although this is ideal, it's quite a lot of work to create your whole computing environment from scratch, so in most cases you will probably settle for using something that already exists. Here just try to choose good, **[minimalist](minimalism.md)** technology ([C](c.md), [Forth](forth.md), plaintext formats and so on) to build your system on top of, and further minimize what you can -- libraries, programming language features, hardware you rely on etc. Think VERY hard about what you absolutely NEED and drop anything that's unnecessary. Make optional what can be made optional and if possible, offer alternatives (e.g. pure [software rendering](sw_rendering.md) as an alternative to GPU accelerated rendering). Don't use libraries for everything -- if it's simple enough, write it yourself; if you just have to make a ball bounce off of the floor, you don't have to include a whole physics library. You get the idea.
TODO: more