While the previous posts described what one needs to know prior to starting a Node project, what follows is some of my experiences that I came across while writing a Node application.
How do I structure my project?
This difference in styles and structure had me question my design choices and made me decide between the following:
- Passing a module’s dependency(s) in as a function parameter OR
- “Require-ing” the dependency module via Node’s module system
Right or wrong, I opted for the latter. Doing so allowed my module to encapsulate its dependencies and decoupled its implementation from its dependent modules. In addition, for unit testing purposes, I was able to mock and stub any modules that I imported via “require” statements using the library “rewire”.
After feeling as though this was the “wrong” way of designing my application, I came to realize the following:
The CommonJS module system is a type of IoC container
In fact, when “require-ing” a module, the result of that module is cached and returned for subsequent require calls to that same file path within an application context. After realizing this, my anxiety around application structure melted away as I realized I could use the same patterns I would use in a C# application.
How do I write unit tests?
Being the disciplined developer that I am, I rely heavily on unit tests as a safety net against regressions as well as to implement new features through Test Driven Development. In C# (with Visual Studio’s help), the testing story is straightforward as one only needs to create a test project, write tests and use the IDE’s built in test-runner to run them. If using NUnit or VisualStudio’s Test Tools, tests and test fixtures are denoted via attributes that the test runner picks up while running tests. The developer experience is quite frictionless as testing seems like a first-class citizen in the ecosystem and within Visual Studio.
Setting up a testing environment in a Node project is a different story. The first decision one must make is the test framework to utilize; the most popular being Jasmine and Mocha. Both require a configuration file that details the following:
- Which files (via a file pattern) should (and shouldn’t) be considered tests and therefore processed by the test runner
- What reporter to use to output test results and detail any failed tests or exceptions
- Any custom configuration related to transpilation or code processing that will need to be performed prior to running your tests
My first approach was to use Webpack (since I was using it in development and production for bundling and transpilation) to create a bundle of my test files which would run through the test runner. This required having a separate webpack configuration (to indicate which test files needed to bundled) along with configuring my Jasmine config file to point to this bundle. While this did work, it was painfully slow as a bundle had to be created each time and run through the test runner. In addition, it felt like a hack as I’d need to cleanup this generated bundle file after each test run. My eventual solution was to use babel-register as a helper to allow Jasmine to run all of my files through this transpiler utility. This worked well (albeit slow) and seemed like the cleaner solution as babel-register acted as a transpilation pipeline, transpiling your code in memory and providing it to Jasmine for testing.
Overall experience compared to C#
After clearing these initial hurdles, the overall development experience in Node was not that much different from developing an application in C#. The major difference between the two platforms is the standard tooling for .NET applications is arguably the best available to the community. Visual Studio does so much for the developer in all facets of application design, which is great for productivity but can abstract too much of what your application and code are doing under the hood that it can be an impediment to growing as a programmer. Although at first it seemed like a step backwards, having the command line as a tool in my Node development process exposed me to the steps required to build the application, giving better insight into the process.
At the end of the day, both .NET and Node are very capable frameworks that will allow you to create nearly any type of application that you desire. As with many things in technology, deciding between the two generally comes down to your project’s resources and time at hand, as well as the amount of familiarity and experience on your team for a given framework. Both frameworks have pros and cons when compared against each other but one can’t go wrong in choosing one over the other.