Contributing to the open-source simulation app NetLogo Web
I resolved a long open issue of adding a proper module system and bundler to the project.
This involved getting familiar with an unknown codebase and making extensive refactorings.
But the effort was worth it for the great feedback from the maintainers!
My motivation for working on this project was to learn how to contribute to a larger open-source project and
how to become familiar with an unknown codebase.
I wanted to do this by making a meaningful contribution to an open-source project and was fortunate enough to be introduced
to the application NetLogo Web thanks to my bachelor's thesis advisor.
I decided to help out by solving a long-standing "issue" from the
project's GitHub repository.
This involved discussing requirements with the maintainers, familiarizing myself with the project's code,
doing several refactorings and then introducing a proper module system and integrating a bundler into the project's build system.
The result
Before getting into the details of how I approached this challenge, here is a quick summary of the results of my efforts:
The changes I submitted have already been merged and are now part of the project.
The project's frontend code now has a more solid foundation with a proper module system and bundler to build on in the future.
Some of the refactorings I did (like getting rid of circular dependencies or removing dozens of global variables)
also improved the readability of the project's code and made it easier to see dependencies between different parts of the project.
I received some very grateful feedback on the changes I contributed.
Below is a quote from one of the project's maintainers:
🎉 Wow! 🎉
🙇♂️ Thank you, thank you, thank you, thank you, thank you for submitting this enormous and incredibly valuable pull request! 🙇♂️
I have an immense amount of respect and appreciation for going through all the trouble to do this,
and doing things that I should have done years ago, myself.
This is so exciting, and makes the technical foundations of this project feel so much more legitimate. Thank you!
Honestly, looking this over, while I have a number of small quibbles, I think this PR is of incredibly high quality.
At nearly every important crossroads, you made what I consider to be the most intelligent refactoring decision. I find it really impressive! 👏
- Jason B., maintainer of NetLogo Web
My approach
Getting familiar with the project
The first step was to open a discussion with the project maintainers about their thoughts and preferences
regarding the module system and bundler, and whether they would like me to take on this task.
The next task was to familiarize myself with the project's codebase.
At the time, the project's frontend code didn't have a module system, and each file exposed its functionality by
attaching it to the global namespace. So I decided to start with mapping out the project by creating a graph
of dependencies between script files.
Unfortunately, I didn't manage to dig up the original dependency graph I made, but
below is one that already includes some changes I made (for example, there are no more circular dependencies):
Part of getting familiar with the codebase was also learning to read and to some extent write
code in CoffeeScript and Scala, which were the main languages used by the project. But in particular learning
CoffeeScript was not a big problem for me, as it has the same semantics as JavaScript and is basically
just a different syntax for the language.
Extensive refactoring
After acquainting myself with the project, it was time to do some refactoring! Since the goal
was to use ECMAScript modules with their import and export statements,
it was necessary to make the code work in JavaScript's strict mode.
It was also necessary to remove circular dependencies between files, as circular imports do not
play well with ES modules. Untangling some of the circular dependencies required a little creativity and
a few different strategies. For example, in some cases it helped to split a module containing multiple classes or functions
into separate files, in another case the problem was solved by passing an additional parameter instead of directly importing a dependency.
Once these prerequisites were met, it was finally possible to refactor the code to use import and export
statements and get rid of dozens (if not over a hundred) global variables. Some changes and reorganization
were also needed in other parts of the project, such as the code of tests or the application's backend.
Adding a bundler
Even though making changes across most of the entire codebase was a lot of work,
the hardest part of this project for me was working with the project's build system, which uses
SBT as a build tool.
(I think some of the difficulties I had came from having too many layers of abstraction, most of which were new to me:
the sbt-web library on top of the SBT build system with several layers of its own, on top of Scala, running on the JVM, and borrowing some things from the Java ecosystem).
But after a lot of time spent looking at other projects using SBT and reading the source code of sbt-web itself
(the documentation of SBT and sbt-web unfortunately wasn't sufficient to solve some of the more complex problems),
I managed to successfully integrate Rollup into the build pipeline.
After overcoming the challenges with SBT, configuring Rollup to do the bundling was a breeze.
Finishing it off
There were a few more things that needed to be done before the changes I made could become a part of the actual project.
The first was to document all the changes I made, describing my thought process and other important details where necessary.
The second was to write a summary of how the new build setup worked, focusing especially on the bundling,
since the maintainers weren't familiar with Rollup.
Finally, it was time to submit my work to the project by creating a pull-request with the changes.
The overall feedback from the maintainers was very grateful and positive.
After discussing a few details that needed clarification, and fixing a few minor issues discovered during code review,
the changes were accepted and merged into the project.
What I learned
Even though at some points of this project I was having doubts about being able to successfully finish it,
I am very glad that I decided to take on this challenge and I learned a lot while working on it.
I learned how to quickly get up and running in an unfamiliar codebase of a larger project, which in addition used
some programming languages and tools I was not familiar with.
I also became much more comfortable with the Git version control system, which I made extensive use of:
using branches and the stash to keep track of work in progress, (interactively) rebasing to clean up the commit history
and keep up with changes in the upstream repository and submitting my first larger contribution to an open-source project.
It also took a lot of perseverance while I struggled with the build tooling and, thanks to its sometimes insufficient documentation,
I learned how to find the information I needed by directly reading the source code.
Finally, I would like to thank the maintainers of NetLogo Web for their warm welcome and helpful
feedback when reviewing my code.