npm vs RubyGem vs PyPI
04 Feb 2016If you’re a Node developer, then you know how spoilt we are (all hail the almightly babysitter npm).
Let’s not talk about languages, because I firmly believe that languages are designed to suit certain needs, so I don’t take the “which language is better” argument.
Instead, I’d love to talk about packaging - because it’s so central to modern development. A good packaging manager is crucial to foster a good open source standard in a community.
This week I try to find out if we can do stuff the npm-way with the package managers of Python and Ruby, i.e. how do you publish a proper package there.
npm
Here’s a sample npm file structure that I wrote. Of course it’s more well polished than the two below cuz I’m mainly a Node dev.
If you head over to the site, it’s pretty damn active; in fact it’s the world’s largest package manager. People npm install
a lot.
It has:
- a nice search interface
- proper package page sourced from its Github’s
README.md
, with details on installation, usage, etc. - a side bar with relevant stats
Let’s quickly go over how we work with npm.
- Create a Github repo with
README.md, LICENSE, .gitignore
, and clone it. - Write your module under
lib/
, and import the needed methods to one point of entryindex.js
. - At root, run
npm init
to setup thepackage.json
, which will take care of everything nicely using simple JSON format. - Run
npm publish
and voila. Your new package is up and available immediately. Just donpm i <package>
to install.
At the time of writing, npm has about 800Mil downloads per week. That’s more than all the RubyGem downloads (700Mil) ever. This is the magic when doing a thing is so effortless (in npm), everyone does it without a second thought. I remember when I started as a newbie with npm I went through everything smoothly, thanks to the great README.md
most packages have.
RubyGem
Here’s a sample RubyGem file structure that I wrote. For guide, look at DigitalOcean’s.
RubyGem is the npm of Ruby, and the packages are called Gems. It the grand-daddy of modern dev, but there’s a few things that made me cringe. Grand-daddy is old now.
It has:
- a bad search interface: unintelligent, non-suggestive, and worst of all you have to go back to the homepage to search again. What year is this?
- the gem pages are mostly poorly written because there isn’t a robust standard for it in the community
- a side bar with some stats, Okay.
Let’s quickly go over how we work with RubyGem.
- Create a Github repo with
README.md, LICENSE, .gitignore
, and clone it. - Ahhh do
gem install bundler
first. At root,runrunnpm init
to setup thepackage.json
, which will take care of everything nicely using simple JSON format.bundle gem <gem>
to generate the necessary files. That’s pretty nice. But there’s a nightmarish part: the Gem specs are split across different files: write it in functional Ruby<gem>.gemspec
without a single standardized format, source the gem dependencies fromGemfile
, and add aRakefile
for publishing your gem. No, there is no standardizedpackage.json
to handle all these things for you under a single JSON file. Welcome to the brutal world you spoilt brat. - Write your module under
lib/<gem>
,and import the needed methods to one point of entryadd aindex.js
.version.rb
under it, then import the needed methods to one point of entrylib/<gem>.rb
. - Run ~
npm publish
and voila~gem push <gem>-<version>.gem
. Oh if you think that’s 3 arguments too long, wait till you see how to useRake
. Whyyy gosh whyyy? But you can dogem install <gem>
simply, thank god.
PyPI
Here’s a sample PyPI file structure that I wrote, along with a simple guide.
I love Python, but PyPI gives me cancer. Okay I get it, the user base is different from the sassy Node devs, and who gives a shit about user interface? Ain’t nobody got time for that (except for web developers).
It has:
- the most useless search interface using only simple regex. It floods the results with multiple versions of the same package, so good luck browsing.
- ~proper package page sourced from its Github’s
README.md
,~ PyPI can’t handle Markdown apparently, so enjoy your plain text formatting. Some important packages actually have details on installation, usage, etc. cuz otherwise you’d be fucking lost - goodluck finding the Github page of the package, even if it exists in the first place! a side bar with relevant statsMost serious users are scientific coders and they know exactly what package they’re looking for, so who cares bout stats in that case.
Let’s quickly go over how we work with PyPI. But first, good luck with the fragmentation - Python2 v.s. Python3, virtualenv v.s. pyvenv…
Now that you’re done choosing,
- Create a Github repo with
README.md, LICENSE, .gitignore
, and clone it. - Write your module under
<package>/
. Add<package>/__init__.py
, and import the needed methods within it. At root, runCopy thenpm init
to setup thepackage.json
, which will take care of everything nicely using simple JSON format.setup.py
from someone else who has written it, and there’s no standardization. Ohh wanna list your dependencies? Dopip install <deps>
as you dev, then at the end only specify these dependencies usingpip3 freeze > requirements.txt
RunNightmare isn’t over. First, register your package namenpm publish
and voila.python setup.py register
. If successful, then upload your smelly tar balls to PyPIpython setup.py sdist upload
(who the hell devs with tar files and manual installation today?). Your new package is up and availableimmediatelya century later before you can dopip install <package>
to install the just-published version.- Btw all the cray involving
pip
and packages are best done withvirtualenv
or whatever you choose.
Conclusion
I love all the three languages - Node, Ruby, Python. However, modern dev is so much about open source and external dependencies - you can’t write powerful code efficiently without relying on open source modules. No dev is an island now.
That being said, I love npm, but RubyGem and PyPI kinda made me went “ehmmmm, what year is this?” I’ll still have to use both of them (and cringe every time I do), but I just have to suck it up and stop being a spoilt brat. The world isn’t all nice, you know.