posted: November 30, 2019
tl;dr: Syntax is not actually the major difference in these two implementations...
I recently had the pleasure of porting a devops script I originally wrote in Python, as a proof-of-concept, into NodeJS. I don’t often get the chance to rewrite a program in a new language. It’s a fun intellectual exercise, and offers a great opportunity to compare implementations head-to-head.
The script starts with the output of a web scraper, a directory tree containing all the site files: HTML, CSS, JS, and other assets. It traverses the site files and does some movement of the shared site resources, which requires adjusting links in the site files. It then packages the resulting files and directories into a specific file format used by another tool, which involves ZIPping various directories and then creating a single ZIP archive of everything.
The results by the numbers
|Lines of code||167||213|
|Script file size (bytes)||7470||8397|
|Number of files||1||2|
|Third-party dependencies (explicit)||0||2|
|Third-party dependencies (total)||0||6|
But the biggest difference in the implementation is not due to syntactical differences in the two languages. It instead results from Python’s richer, more powerful standard library that ships with the Python3 run-time environment.
When I write Python devops scripts, knowing that others may someday run them on their own machines, I always try to see if I can write the script by using only the Python standard library. That way, when the script is run on another machine, there is nothing else that needs to be installed. As long as the user has Python itself, the script should run. This can save a lot of hassles: installing dependencies can be fraught with unforeseen difficulties and conflicts.
For this task, the Python standard library provides everything needed, and there was no need to go to the Python Package Index to ‘pip install’ a third-party library. Python itself provides powerful libraries for file system manipulations, ZIP files, and even spawning other processes if there is a need to invoke other programs.
I gave up when I realized that the ‘fs’ module doesn’t provide a way to move an entire directory with all its contents. This is a pretty common situation, and sure enough someone has extended the ‘fs’ module by creating fs-extra, which features a ‘fs.moveSync()’ function, which behaves very similarly to Unix’s ‘mv’ command. The usage stats for ‘fs-extra’ show it to be quite popular; perhaps the NodeJS folks will consider bringing it directly into NodeJS someday. Doing so would involve bringing in four other packages, as ‘fs-extra’, like many NodeJS modules on npm, itself has dependencies.
The other third party package I had to research, find, and use was adm-zip for creating ZIP files and archives. ZIP files have been around for decades, but they are not yet natively supported by NodeJS.
Having to rely upon third-party libraries introduces multiple challenges. Standard libraries are tested and supported by the core language development team; third-party libraries are of less certain quality. There are more stability and security issues with third-party libraries. Choosing the best third-party library can be hard; often there are multiple options. The quality of the documentation for third-party libraries varies and is typically not as good as the standard library. There are usually fewer blog posts, tutorials, and other learning materials available for third-party libraries. Third-party libraries can be extremely helpful, and I certainly used them in this NodeJS project, but if the functionality they provided was in the standard library, less work would be required to use them. Python’s “batteries included” standard library wins out, in this case.