Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

> During the past 5–6 years of my JavaScript experience, every time I wanted to go back to any of my projects—from tiny to big, server-side or front-end—there was always a challenge, a problem to tackle or an obstacle to overcome before I can update or sometimes even just run my program.

why i moved mostly from writing node cmd tools to using bash. don't need to go on a bunch of side missions every time i run npm install

not enough pragmatism in the JS community (people). more about hot new thing as opposed to boring long term stability. maybe because of web/chrome as a constantly moving platform, and Apple/Jobs app-ification of everything, relative young age of JS community.



It's funny. The issue described (inability to replicate the conditions to build and/or run the original program using NPM) is something that gets brought up a lot, but people will appear who are downright adamant that it's not a problem. Not just that it's not prevalent enough to be concerned about, but that they've literally never seen it happen ever. We're living in completely separate worlds.

And let's be clear: this is an *NPMJS* problem, not a *JS* problem. For folks who have read and written lots of JS before and during NPM's reign over programmers' attention and will continue to do so afterward (when NPM as the dominant culture evaporates) and have kept NPM- and NodeJS-inspired "best practices" at arms length precisely for these reasons and more, it's irksome to see people full-on equate JS with what-the-NPMers-are-doing.


You're right that it's not the language per se, but I'd argue that it's not specifically NPM either - the same problems afflict any rapidly-moving not-yet-fully-mature software ecosystem. The whole tale definitely reminded me of the pain of trying to build projects in C and C++ from source in the early 2000s, with GNU Autotools everywhere, and before pkg_config was common. I've had similar "side quest" frustrations (I really like that description from the parent post!) more recently when python's involved.

But I guess NPM's particularly prone to it due to the sheer number of interdependent packages. I can't quite wrap my head around there being one npm package for every 6,100 human beings on the planet.


This article reminded me of my days as a sysadmin in the 90s. It seemed like every new system had a fresh issue with getting some shared library right.


Of course it's a JS problem. "Programs" being replaced by JavaScript apps doesn't mean some custom homegrown LTS framework. It means apps that aim to replace what used to be known as "Programs" have some sort of frontend JS component. frontend JS doesn't mean npm.js sure, but it means whatever flavour of bower is hot today, webpack or the other new kids on the block, react or other stuff. There is a reason why these big companies hire unlimited amounts of frontend devs. If you leave a react apps dependencies half a year and then try to update it none of it will work. It's "less" bad than it was 2 years go, but it's extremely cost-intensive to maintain nonetheless.

But it's not like backend js is any better. Most people run express.js in some shape of form, but then people roll their own (or use any of the existing 50) input sanitizing libraries and then half of those projects run into the same authentication bugs that Rails fixed almost a decade ago. There's a reason why people don't ask for JavaScript experience, but instead ask for Node.js experience in resumes.


> Of course it's a JS problem.

I've already explained why it isn't, in detail.


A month ago I found a bug in command line utility I wrote in C# and hadn't touched in 8 years. I checked out the project and opened it in Visual Studio. And it compiled. I fixed the bug and it just worked. End to end it took half an hour. I feel like there is an advantage to libraries and tools managed by adults with long term skin in the game.


As a counter point: I have simple node scripts, that serve the same purpose to me. And there was also the need to fix something 2 days ago in an 8 year old script. Opened the file, changed the code and running it again. Took 5 minutes and it just worked.

I don't use js because it is the hot new thing, but rather because it is simple. (But I avoid messy and obscure npm repositories wherever possible for example.)


> I don't use js because it is the hot new thing, but rather because it is simple.

It infamously isn't.

https://www.destroyallsoftware.com/talks/wat


Most of these are 'gotchas' that rarely happen in real code because they're all due to implicit type conversions


Yeah, nothing there affects regular programs even a tenth as bad as say quoting rules and space handling affect average Bash shell scripts.


Wouldn't shellcheck catch most of these?


Hm, video arguments are not my take, I did not watch it (yet), but in either case this seems to be opinion.

But of course, javascript is so simple, that it is not suitable for complex problems. No (sane) person would ever claim, that it is the right language for every problem.


Are you familiar with the No True Scotsman logical fallacy?


Yes, but I do not know, what you are trying to tell me.


I am suggesting that you are making exactly this kind of fallacious argument when you say “No (sane) person would ever claim, that it is the right language for every problem.”


"in which one attempts to protect their universal generalization from a falsifying counterexample by excluding the counterexample improperly"

This would be the wiki definition.

But where is your falsifying counterexample?

You mean the video, which says below:

"This talk does not represent anyone's actual opinion. For a more serious take on software, try .."?


It's fairly easy to find falsifying counterexamples — it's not such an uncommon opinion.

Also I believe the author of the video is clarifying in the statement you quoted that he isn't trying to take a position on the state of the industry.


People always underestimate how stable JS is. I would argue that it is more stable and backward compatible than a lot of backend languages. What is not stable in JS - is a whole ecosystem.


I've been laughed at for scripting in Java, but I have a bunch of such scripts from 15-20 years ago and guess what, they work out of the box like the first day.


You can also patch most classic .NET (4.8 and below) "binaries" in place with something like dnSpy. One example: I had to update a simple command line tool someone else wrote to poll an API that had undergone some changes. Was able to make the changes directly in dnSpy without having to even open Visual Studio. I haven't tried with any of the 5.0+ versions so I don't know if this is still the case.


Same thing with java. Literally pick up where you left off. The issue of not working after some time just isn't an issue.


That's how it should work. But of course last week I revisited a project I wrote in C# too, this only 3 years old, and apart from dotnet complaining about the target framework not being supported any more, I couldn't get it working again due to the libraries used.


This makes no sense. If you upgraded your libraries, thats in you to fix it tho.


> "why i moved mostly from writing node cmd tools to using bash"

You literally moved from one unmaintainable mess of an ecosystem (Node), to what is arguably an even worse unmaintainable mess of an ecosystem (bash). Glad to hear it wasn't Perl though.

For self-contained little tools or hobby projects that can run cross-platform, use Python. For anything beyond that - use a proper strongly typed language (C, C++, C#, Java, etc).


Only use python if you plan on compiling it with something like docker or podman to pickle your resulting stew in epoxy for all time.

Otherwise you'll still be in some dependency heck as you run down why your library updated doesn't work (oh, switched to TLS encryption; that's good I guess) or you're thing uses v2 and everything now uses v3.

golang, rust, at least, make a static binary out of the gate. In 8 years it'll probably be full of hideous out-of-date code and full of security vulnerabilities, but at least you won't have to look at it and feel bad.

If static binaries were good enough for Ultrix, they're good enough for you.


I've been writing tools like this in Python for a very long time and haven't run into anything close to what you're describing. However, if this happened to me and I was annoyed enough to do something about it, I would use a tool (e.g. pip-compile) that creates a requirements.txt file, which specifies all the libraries and dependency version numbers explicitly. If something broke one day, you can stick that script in a directory with a venv and just run it from there. There's no need to resort to compiled languages like Go and Rust which will very likely give you a large raft of other unrelated problems (slower development velocity, comparatively limited libraries, etc.). Going through all of that just to have a binary in hand doesn't seem remotely worth it from my perspective (YMMV).


The OCI container is the binary. Docker is a tool to take any existing runtime and turn it into a static binary you can feed to any future linux(ish) kernel.

I on the other hand, have had plenty of situations where some system somewhere is managed with some config management tool (such as puppet) and it is told "make this application with these dependencies" and the application, such as "manage elasticsearch index rotation" uses the system python and does pip install to install all the things. This idiom seems fine, but ultimately ends up with a hideous mess where it worked one day and didn't work a year later, because either the system python is different or the dependencies are all messed up or the pip tool itself on the system python isn't compatible with modern package distribution.

You can (correctly) say "don't do that" but the same idiom in a shell script will almost certainly work across decades regardless of if "sh" is bash or ash or ksh, to some degree of "works" (again, you can _correctly_ say that no shell script ever works correctly).


It is interesting that the data science and ML folks are willing to weather Python’s dependency mess Vs. the huge momentum Golang and (increasingly) Rust have built around their static binary philosophy.

Perhaps this is the future of Kubernetes , to be the only thing brave enough to run epoxied globs of .NET, Java and Python.


Python and docker, with compose is a really good fit. Everything works, everything is boring, everything is stable all the time. And importantly, most problems are easily googled.


Just be sure to archive your artifacts. Both the ones you make and the ones you use to build output artifact.

Otherwise, your docker build tool will work today and be a screaming mess of broken dependencies tomorrow.


I think the trick is to not have any dependencies, except Python itself, when writing such command line tools. Python does have a large standard library after all. While Python itself surely could be nicer, it is still easier to maintain such a script than a script of similar size of GNU Bash code.


Bash scripts don’t break, when left unattended for months/years. Python scripts do.


It can’t break if it were never correct in the first place. Bash scripts are always chock-full of bugs, and only work when everything in its environment is the same. That folder now has two files instead of one? Now it just stops working.


In my experience, they don’t have more bugs than Python scripts. That’s assuming they’re shorter than 50 LOC. Long before my scripts reach this size I convert them straight to Go. That’s the most problem-free strategy.


Pin your versions. Also - to make the equivalent safe bash program compared to a typical python implementation is ... a lot of work. Enough that imo the python version is worth the maintenance.


Pinning versions doesn’t help when the old version of some dependency no longer works with your new OS or hardware.

I mostly only code in Python but this article really spoke to me. I have <10 personal Python scripts that I use heavily for my job, but they are such a bear to maintain.

Meanwhile my two old Autohotkey scripts that I wrote 10+ years ago and rarely touch still chug along perfectly.


The recent deprecation warning message of `egrep` is a prime example that bash scripts can break (depending on stderr processing). They will definitely break once the alias is removed.


egrep has been on a deprecation path for 15 years, and the replacement is incredibly straightforward. Also, I think egrep will generally just continue to work.

I'm not sure what you mean by "recent", but this is more longevity than we get in the node/JS world.

I'm primarily a JS (now TS) dev, who also throws bash at things when it makes more sense, but let's not kid ourselves that it's the same.


*Statically typed, not strongly typed


In the past years Java is a strong candidate for cmd tools.Using Quarkus + Picocli + GraalVM for native compiling, gives you a standalone binary which can be used on any platform.


The python build/install/distribute situation is so bad, XKCD made fun of it years ago https://xkcd.com/1987/


> don't need to go on a bunch of side missions every time i run npm install

Lol what a great way to describe what running a simple "npm install" entails.


Try doing this on a 5 year old project. You'll very likely end up in dependency hell.

There is a solution though - use of nvm and .nvmrc (to control the version of node and npm that you use), and use of npm ci (which installs packages as they were at the time, rather than installing newer versions than specified in package-lock.json (because too many devs rarely ever pin versions) instead of npm install / npm i).

nvm (Node Version manager): https://github.com/nvm-sh/nvm npm ci: https://docs.npmjs.com/cli/v6/commands/npm-ci


I rarely if ever get version mismatches for a normal npm install because upgrades by default only do minors. If a package has a breaking change in a minor it's not a JS issue, it's not a npm issue, it's a "this package author made a breaking change in a minor" issue.

And regarding nvm: That's obvious. This is the same for almost any runtime. If you have the wrong jdk version it doesn't work, if you have the wrong (whatever iOS uses for xcode) version it doesn't work, if you have the wrong version of gcc it doesn't work.

Obviously wrong is not always the same, more up-to-date versions of gcc can compile older programs (maybe) but that's also the same for Node unless otherwise specified in the packages.


Why learn cmd and bash when you can just learn js? Easier to maintain 1 language than 1+.

My software in js from 7 years ago still works.


But it's not that simple, for an example I have older personal projects as well which I'm unable to run without doing considerable changes to the code after moving to M1 chip.

Just because I'm unable to run older versions of node and thus unable to run some of the dependencies and thus need to update the dependencies and then the code etcetc.

Yes, I could use docker and containers... Yes, I could use Rosetta...

But it doesn't run natively like it did before.

But bash still works...


Exactly. Dependency hell is easy to avoid by avoiding dependencies. Modern JS with modules and classes is really good for simple projects, esp. prototypes that don't have to work everywhere. No framework, no special utilities that all have their quirks. And no packaging either. Much, much simpler this way.


Likewise, concurrency stops being a problem if I avoid threads and async as much as possible.

I'm starting to feel old now that I can no longer pretend I've only got two threads, network and UI, where everything is fine if I wrap the network response with "do on main thread" and crashes reliably and instantly whenever I forgot.


This comment here is exactly the problem with JS people. If you are making a big thing out of learning(!) cmd(!!!) then you shouldn't be working in software development, period. 7 years is a flex only in a JS world. As others mentioned, try 35.


My scripts in ksh from 25 years ago still work.


because js should never be the first choice in any case...


To avoid a rm -rf / ?


Web has always been about the hot new thing. It was part of why I left-in 2001.


I left for a couple of years for Windows desktop and Android native development, turns out that the GUI civil wars at Microsoft, and the whole Java vs Kotlin vs AndroidX vs JetPack vs NDK being like a 10% project, are even worse than dealing with Web quirks.

So even though I rather do native development, here we are back at the Web and distributed computing.


> the GUI civil wars at Microsoft

The wars are done.

Look at what Microsoft actually uses for GUIs, not what they recommend. All the new Microsoft apps are written in Electron.


Actually not all of them use Electron as such.

Teams is thankfully now using WebView2 (less resource heavy), new Outlook is a PWA.

However I do agree with the gist of your comment, it appears everyone from the GUI civil wars that doesn't want to stay until the end has jumped ship to "Azure OS", or the competition (Amazon/Google), and most UIs are Web based or the classical Win32 ones.

Naturally "Azure OS" applications use the Web as UI.

Only WinDev themselves seem head down on using WinUI, and still don't grasp the competition, not only the WebView2 based stuff into their turf, the other OSes that don't require dealing with COM and C++ for basic stuff like OS widgets.


> All the new Microsoft apps are written in Electron.

Is this why the new calculator app takes over 5 seconds to show up on screen?


Nope, that is the UWP security container most likely.

https://github.com/microsoft/calculator


Is that what causes typing "Notepad" in the search bar take 5+ seconds to show me notepad, sometimes after it showed it just having typed "No..." before deciding it's not sure whether it wants to show me something else instead?


No idea, for me search mostly works.


The best thing about bash is portability indeed. Node requires an entire runtime, while Rust may have a problem with library versions and requires a heavy toolchain too to recompile. I use it for small CLI tools but I could not envision anything over 1k LOC in bash. I think the ideal would be a language that introduced a nicer syntax and compiled it to bash. I wonder if there's anything like that...


Why has nobody mentioned that you can (and should) just lock your dependency versions…?


Because that stop short that complain train.


nvm is my solution to this

It isolate and pins npm installs so that the environment is the same in the future without messing up your main system

Your projects also need to consider pinning their dependencies to a specific version

Other languages/frameworks with package managers have similar concepts


> Your projects also need to consider pinning their dependencies to a specific version

At that point, you should consider just using your version control system to handle versioning instead of trying to route around it, poorly.


As a long-time ruby user where bundler has done version pinning for decades, I think this is a core feature of any dependency management system, not some kind of "routing around it."

I'm not sure what "your own version control system" means. Checking all dependencies into (eg) git? I'm not sure how you deal with indirect/second-level dependencies, but any kind of roll your own like that to me is what I'd call "routing around" the failures of your platform dependency management system.

Correct dependency pinning also allows you automated ways to upgrade dependencies, resolving requirement trees, within stated bounds specified per-dependency (like keep to same major version). It just happens when you want, not every time you install or deploy.


> I'm not sure what "your own version control system" means.

Me neither. Where did that come from? I didn't write it. (It's not in my comment, just yours.)


Ah apparently my brain inserted `own`, looking back you said "just using your version control system". OK, I think I'd write the rest of my comment the same still; does it mean putting all your dependencies (source/binary) in your version control (eg) git?


Yes—using your VCS/SCM to version control the source code.


shameless plug If you want to avoid having to write your own args parser everytime or think getopt is a pain, you should check out my little project:

https://github.com/andsens/docopt.sh

No dependencies, the code is directly inlined into your script, and you write the args parser by writing the help-text.


hey='you can define variables' do_this='without commandline parsing' ./thing

#!/bin/sh

hey=${hey:='default one'}

do_this=${do_this:='default two'}

not_that=${not_that:='because getopts is a nightmare'}

echo "${hey} ${do_this} ${not_that}"


If you want to be more DRY (do not repeat yourself) with regard to the variable names you can use the `:` command inside the script (which just expands its arguments) as in

    : ${hey:='default one'}
or even more briefly just use that `:=` {or `=`} assign if empty or unset {or assign if unset} at the first use case.

Also, besides shells most prog.langs have easy ways to receive these { getenv in C, os.environ.get("do_this", "default two") in Python, etc. }.

--

I think what people really miss here is the (rarely used, I guess?) shell calling/invocation syntax @cduzz points out of:

    var1=val1 var2=val2 program
which is notably even more terse than GNU long options:

    program --var1=val1 --var2=val2
Also missing is a documentation standard/convention like:

    help= program
to dump out settings possibilities and their defaults and maybe their types (integer, string, bool, etc.). One virtue of the `:` syntax above is that it is rare enough in "ordinary shell code" that you could probably auto-generate the help from such a table at the top of the script via

    grep '^: ' "$0"
at least if you are willing to assume the invoker sets $0 to a full path.

Soon enough you may outgrow shell programming and, if you become used to such nice conveniences and are willing to learn Nim, I might then recommend something more like https://github.com/c-blake/cligen


I’ve been bashing for decades and never thought of that. Thank you



Nim is great for this use case.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: