4 ms·
Why are we still developing software like we used to 40 years ago? Why not just import external dependencies into your project at a function/class level rather
by KronisLV 5y ago
Why are we still developing software like we used to 40 years ago?
Why not just import external dependencies into your project at a function/class level rather than at a package one: if you only use FooPackage.BarClass and FooPackage.bazMethod(), you should be able to choose to make your project depend on just those two things, ideally in a completely transparent way by your IDE.
Then having to manage the full scope of packages and their versions becomes less relevant, because the IDE can check whether a new version has been released in the package manager of choice, check whether those two things have changed and if they have, then demand that the developer have a look at the code changes to refactor code if necessary, otherwise not requiring any action on their part. Furthermore, if you ever need to migrate to a different package or even rewrite the functionality itself, you could just look at the few signatures that you use, rather than having to remove the package entirely and see what breaks in your IDE. Why can't we have itemized lists of everything that's called and everything that we depend on, as opposed to the abstraction of entire packages?
Better yet, why even depend on binary blobs or hidden code (that's ignored by your IDE) in the first place? Why not just download the source for every package that you use and upon updates be able to review the code changes to the package much like a regular Git diff?
Of course, this would probably require getting rid of reflection and other forms of dynamic code, which i fully support, since those have never been good for much in the first place and only destroy any hopes of determinism and full control flow analysis.
As for the possible counterargument of this being hard to do: it wouldn't really be with more granular packages. Instead of trying to shove an ecosystem inside of a single package, why not split it into 10-20 bits of reusable code instead? Smaller packages, which would be easier to review and manage.
Context: i dislike how Spring and Spring Boot in Java force a huge ecosystem of fragile dependencies upon you, with their reflection which ensures that your apps will break at runtime, for example, when moving from Spring Boot 1.5 to 2.0. Furthermore, in the JS world, the node_modules folders are probably 10-1000x too large for what's actually necessary to display a webpage with some interactive behaviour.
Disclaimer: i have no delusions about any of the above being technically feasible right now. Perhaps "Why?" would be a good question to ask. In my eyes, perhaps the industry is too set in its current ways and as long as we don't have languages and entire ecosystems that approach established practices from a wildly different angle, no one can actually contest the decades of already built packages and tools.
On the bright side, WireGuard kind of displaced OpenVPN somewhat and there are numerous benefits to it being smaller, which is a good example of getting rid of bloated software. Furthermore, Nix may or may not do that to alternative approaches to package management, but its usage still remains really low.
In my eyes, the only long term solution is to be able to tell exactly what's necessary for your code to build and work, and to test every dependency update that comes out against this automated process. Static dependencies but at the speed of updates of dynamic dependencies. Then you'd just have to wait for a day until the devs fix the newest regressions of a new dependency release before getting a new statically linked app, as opposed to using dynamic linking and finding that some dependency breaks your app as it happens in prod.
- nemetroid 5y agoJoe Armstrong had some similar thoughts: "Why do we need modules at all?". https://erlang.org/pipermail/erlang-questions/2011-May/058768.html https://erlang.org/pipermail/erlang-questions/2011-May/05876...
- KronisLV 5y agoYou know, the "all functions have unique distinct names" idea is pretty interesting! Honestly, that reminds me of the PHP standard library a bit, which feels oriented towards procedural programming at times. Now, the language and the actual implementation of the functions aside, i found that pattern really pleasant to work with, especially since it let me work more in line with functional programming principles as well - pure functions and no global state (even if passing data around was more difficult). Now, i won't say that the approach fits every project or domain out there, but at the very least having a clear idea of what your code depends on and what's going on inside of your code base is an idea that i still stand by. Sadly, the only tool that i found that at least tries to make this easier was Sourcetrail, which is essentially dead now: https://www.sourcetrail.com/ https://www.sourcetrail.com/
- PaulDavisThe1st 5y ago> Why not just import external dependencies into your project at a function/class level rather than at a package one: if you only use FooPackage.BarClass and FooPackage.bazMethod(), you should be able to choose to make your project depend on just those two things, ideally in a completely transparent way by your IDE. TFA is about programs that require a linker at either compile and/or run time. The references in the rest of your comment to Java and JS suggest that your experience with programming in languages that require linking against compiled libraries might be limited. What you describe is precisely what the linker is for! It looks at the code you wrote (and compiled), sees that it calls FooPackage.bazMethod(), and then goes and looks for that call along the linker search path using a combination of implicit and explicit library names. If it's the static linker, it imports the code for that call, and then recurses to check the dependencies of FooPackage.bazMethod(). If it's the dynamic linker, it does the same, except differently (runtime pointer swizzling etc. etc) When you link your program against libfootastic.a, the linker is doing exactly what you suggest, and in most IDEs that step is going to happen automatically. When you link your program against libfootastic.so, the linker will do exactly what you suggest, but at runtime. > Better yet, why even depend on binary blobs or hidden code (that's ignored by your IDE) in the first place? Why not just download the source for every package that you use and upon updates be able to review the code changes to the package much like a regular Git diff? Many large end-user desktop applications do precisely this. For Ardour (I'm the lead dev), our build system downloads 80+ source code packages and builds them locally to create a 2GB installed dependency tree of compiled libraries and ancillary files. There are a lot of arguments against doing this, and some arguments in favor. However, we can't compile each file from each dependency as part of the Ardour build because the build systems for those dependencies are complex and independent. There's no way to force the developers of libfftw (Fastest Fourier Transform in the West) to somehow prepare their code structures so that we can trivially replicate their entire build system as part of ours. If there was only a single build system for EVERYTHING, sure, maybe this would be feasible. But there isn't, and I'm completely certain that there never will be.