Writing Node Applications as a .NET Developer – My experience in Developing in Node vs .NET/C# (Part 3)

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?

The main problem I had when developing my Node application was figuring out a sound application structure. As mentioned earlier, there is a significant difference between Node and C# when it comes to declaring file dependencies. C#’s using statement is more of a convenience feature for specifying namespaces and its compiler does the dirty work of determining what files and DLLs are required to compile a program. Node’s CommonJS module system explicitly imports a file or dependency into a dependent file at runtime. In C#, I generally inject a class’s dependencies via constructor injection, delegating object instantiation and resolution to an Inversion of Control container. In Javascript, however, I tend to write in a more functional manner where I write and pass around functions instead of stateful objects.

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

While the first two items are fairly straightforward, the third can be a major point of frustration especially to those new to Javascript build tools and transpilers. Some of the biggest problems I faced with Javascript testing were with having my files transpile prior to being run through the test runner.  

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.

Much of the issues I faced with setting up a test harness for my Node application was related to the pain points inherent to transpilation. If I hadn’t been using advanced Javascript language features, this pain would have been eased slightly. However, this fact points to the differences in decision points one must face when developing a Node application compared to developing a .NET application.

Overall experience compared to C#

Aside from the pain points and confusion that I faced in the preceding sections, my overall experience in developing a Node application was delightful.  Much of this is due to my love for Javascript as a language but the standard Node library as well as the immense number of third party libraries available via npm allowed me to easily accomplish whatever programming goal I had.  In addition, I found that when I was stuck using a certain library or standard library module, I had plenty of resources available to me to troubleshoot any issues, whether they be Github issues or Stack Overflow articles.    As a last resort, if Googling my problem didn’t result in a resolution, I able was to look at the actual source code of my application’s dependencies which were available in the node_modules folder.

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.

Summary

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.

From a personal perspective, I thoroughly enjoy developing Node applications for a few reasons. The first being that Javascript is my favorite language and the more Javascript code I can write, the happier I am. Writing Node applications is also a great way to improve your skills in the language compared to Javascript development for the web as you can focus solely on your application logic and not be slowed down by issues related to working with the DOM or different browser quirks. Finally, I find Node to be a great tool for rapid development and prototypes.  The runtime feels very lightweight and if you have a proper build/tool chain in place, the developer feedback loop can be very tight and gratifying.

Overall, you can’t go wrong between the two frameworks but if you want to get out of your comfort zone and fully embrace the full-stack javascript mindset, I strongly recommend giving Node development a shot!

Writing Node Applications as a .NET Developer – Getting Ready to Develop (Part 2)

In the previous blog post, I provided a general overview of some the key differences between the two frameworks. With this out of the way we’re ready to get started writing an application. However, there are some key decisions to make regarding what development tools to use as well as getting the execution environment set up.

Selecting an IDE/Text Editor

Before I could write a line of code, I needed to decide on an IDE/Text Editor that I wanted to use to write my application. As a C# developer, I was spoiled with the number of features that Visual Studio offered a developer that allowed for a frictionless and productive developing experience. I wanted to have this same experience when writing a Node application so before deciding on an IDE, I had a few prerequisites:

  • Debugging capabilities built into the IDE
  • Unobtrusive and generally correct autocomplete
  • File navigation via symbols (CTRL + click in Visual Studio with Resharper extension)
  • Refactoring utilities that I could trust; Find/Replace wasn’t good enough

While I love Visual Studio, I find that its JavaScript editor is more annoying than helpful.  Its autocomplete often gets in the way of my typing and it will automatically capitalize my symbols without my prompting.  Add to the fact that since I was working with a new framework and was already spreading my wings, I wanted to expose myself to another tool for learning’s sake.

Given my preferences above, I decided that JetBrain’s Webstorm would fit my needs:

  • Webstorm offers a Node debugging experience that rivals VS’s. One can set breakpoints, view locals and evaluate code when a breakpoint is hit.
  • The IDE’s autocomplete features (although not perfect) offer not only the correct symbols I’m targeting but often times would describe the signature of the function I was intending to call.
  • By indexing your project files on application start, Webstorm allows for symbol navigation via CTRL + click.  I was even able to navigate into node_modules files.
  • When refactoring code, Webstorm will search filenames, symbols and text comments, providing a safe way of refactoring code without (too many) headaches.

While not at the same level as Visual Studio’s C# development experience, Webstorm offers the user the next best thing, allowing for an environment that offers a familiar developer experience.  Although there are other (free) options available (Sublime Text, Atom, Visual Studio Code) I found that with these editors, I had to do more work to set up an environment that would allow me to develop at a productive pace.

Embracing the Command Line

Due to the power of Visual Studio as a tool and its ability to abstract away mundane operations, your average .NET developer tends to be a little wary of using the command line to perform common tasks.  Actions such as installing dependencies, running build commands and generating project templates are handled quite well in Visual Studio through wizards and search GUIs, preventing the user from having to know a myriad of tool-specific commands.

This is not the case when working with the Node ecosystem and its contemporary toolset.  Need to install a dependency via npm? A quick `npm i -S my-dependency` is required.  Want to run a yeoman generator to scaffold out an express application?  You only need to download the generator (if you don’t have it) using the same npm tool, run the generator with `yo my-awesome-generator` and walk through the prompts.  How about a build command?  Assuming you have an npm script set-up, typing `npm run build:prod` will do, (even though this is just an alias for another command line command that you will have to write).  In Node development, working with that spooky prompt is unavoidable.

While it might feel tedious and a step backwards as a developer, using the command line as a development tool has many benefits. You generally see the actions that a command line command is performing which gives you better insight into what is actually happening when you run `npm run build:prod`.  By using various tools via the command line, you have a better grasp of which tool is meant for what purpose.  This is in comparison to Visual Studio where at first blush, one equates Nuget, compiling via the F5 key and Project Templates to Visual Studio as a whole, not grasping that each of the commands you perform are separate toolsets and dependencies that Visual Studio invokes.  Having better insight into your toolchain can help in troubleshooting when a problem arises.

Running Your Code

The final step in writing a Node application is preparing your environment to run your Node code.  The only thing you will need to run your application is the Node runtime and the Node Package Manager (included in the same download and installed alongside Node).

Node.exe is the actual executable that will run your Node application.  Since Javascript is an interpreted language, the code you write is passed to this executable which parses and runs your application.  There is no explicit compilation step that a user must perform prior to running a Node application.  Furthermore, unlike applications written in a .NET language, Node programs are not dependent on a system-wide framework to be present. The only requirement for your code to run is to have the node.exe on the system path. This results in the deployment story of a Node application to be simpler and allows for cross platform deployment that is not yet readily available to .NET applications.

The neat thing about Node is that if you type in the `node` command without any file parameters, you get access to the Node REPL right in your console.  While this is great for experimentation or running/testing scripts, it’s a little lacking and I’ve only used it for simple operations and language feature tests.

While node.exe is what runs your application, npm is what will drive your application’s development.  Although the “pm” might stand for Package Manager to pull in your project dependencies, it’s more of a do-all utility that can run predefined scripts, specify project dependencies and provide a manifest file for your project if you publish it as an npm module.

Summary

Oftentimes with new frameworks and technologies, I have experienced frustration in getting my environment set up so that I could write code that runs at the click of a button. However with Node, the process is very straightforward, simply requiring one to install the runtime and package manager which are both available as an MSI that can be found on Node’s website.  From there, you can run your Node program by accessing the command line and pointing to your entry file.  In all honesty, the hardest part was deciding on an IDE that offered some of the features I became accustomed to when working in Visual Studio.

In the next and final post in this series, I will provide my overall experience with writing a Node application, detailing some questions I had surrounding application structure and testing, as well as giving a summary on my feelings on the runtime.

Writing Node Applications as a .NET Developer

As a .NET developer, creating modern web apps using Node on the backend can seem daunting.  The amount of tooling and setup required before you can write a “modern” application has resulted in the development community to display “Javascript Fatigue”; a general wariness related to the exploding amount of tooling, libraries, frameworks and best practices that are introduced on a seemingly daily basis.  Contrast this with building an app in .NET using Visual Studio where the developer simply selects a project template to build off of and they’re ready to go. [Read more…]