About the project

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 mean­ing­ful 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 repos­i­to­ry. This involved discussing requirements with the maintainers, fa­mil­iar­iz­ing myself with the project's code, doing several refactorings and then introducing a proper module sys­tem 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 func­tion­al­i­ty by at­tach­ing it to the global namespace. So I decided to start with mapping out the project by creating a graph of dependencies between script files. Un­for­tu­nate­ly, 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):

Graph of dependencies between files.
File dependency graph of frontend code after some refactoring.

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 par­tic­u­lar learning CoffeeScript was not a big problem for me, as it has the same se­man­tics as JavaScript and is ba­si­cal­ly 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 nec­es­sary 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 cre­ativ­i­ty and a few different strategies. For example, in some cases it helped to split a mod­ule 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 pre­req­ui­sites 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 re­or­ga­ni­za­tion 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 doc­u­men­ta­tion of SBT and sbt-web un­for­tu­nate­ly 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 be­come a part of the actual project. The first was to document all the changes I made, de­scrib­ing 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 clar­i­fi­ca­tion, 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 suc­cess­fully 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 ex­ten­sive use of: using branches and the stash to keep track of work in progress, (in­ter­ac­tive­ly) 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 doc­u­men­ta­tion, 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.