Some More Reasons to Love and Hate .NET
How I came to this point
I have many years of hands-on experience from developing browser-based user interfaces with ReactJS, which is a dominant JavaScript (and TypeScript) based library for doing just that. To be exact, I have been developing software almost on a daily basis with ReactJS since 2017. Before that, I used more primitive JavaScript libraries for UI development for about 7 years, beginning from around 2010. To mention some of these libraries, JQuery was one of the hottest those days. Combining JQuery with embedded JavaScript templates EJS, it was actually possible to get quite awesome UIs done. Picking the right libraries and unifying them with a consistent project structure, the developer experience wasn’t actually that bad - you could get quite close to what you would later get with ReactJS. Actually, there are things that you can achieve far better with JQuery than you can do with ReactJS. Even today! It just requires to have a bit different approach - with JQuery you have a DOM specific approach whereas with ReactJS you view things from the component angle. But that is not the point of this blog article. So let’s move on.
Before 2010, I implemented many browser-based user-interfaces with Flash-based Adobe Flex, from around year 2008 until 2011, when the announcement came from Apple that they would kill off Flash support in their browser. To me it appears that Adobe Flex was the precursor for ReactJS that would emerge years later. Adobe Flex was very similar to the early versions of ReactJS. From developer’s perspective the major difference was that it used ActionScript, not JavaScript, as the programming language. ActionScript was a programming language similar to JavaScript but it supported types. Therefore, ActionScript was actually something like a precursor to TypeScript programming language, which would emerge a decade later.
For these reasons, it felt natural for me to learn ReactJS when I realized in 2017 that it is a necessity.
Years later, in June 2023 to be exact, a twist of fate threw me in to work on a project at Mobidiag (a Hologic company).
I took the challenge and started coding with Blazor on .NET.
It was easy to get coding productively with Blazor. That’s mainly because Blazor is awesome but I was able to handle it because I was
already familiar with C#. After all, I had been writing backend code with C# at Expak from March 2013 until March 2017.
C#, on the other hand, was very similar to Java, which I already was familiar with since 1999.
Anyway, Blazor was like a mixture of many things that I already knew. But most essentially it was like coding a ReactJS project with C#.
I really liked it with Blazor and .NET at Hologic. A professional team, good management. But three quarters later, I happened to be working at a desk next to an open window and a gust of whirlwind blew me away to another customer. After landing in that other place I looked around and saw new faces around me. They asked me to start coding for them with ReactJS and TypeScript right away. I said, give me a break it doesn’t work like that. You see it’s been a windy morning. So let me first grab a coffee and please give me that desk in the corner - not the one next to the window!
:)
Just kidding. I just took the tram.
Oh yeah.
Anyways, it turned out that I had come to a pretty good place. It’s also great that I have been having an opportunity to bring my skillset on React up-to-date again. On the other hand I can compare it again with Blazor and .NET from a little different angle.
How I compare ReactJS and Blazor now
On JavaScript side, there are some really important libraries that make React programming a lot easier that I couldn’t find for Blazor. The first thing that comes to mind is the Styled Components library that really makes React coding fun because you can smoothly embed CSS in React components. Read my previous blog post to understand why I appreciate it so much! Another thing that disturbed me with Blazor that I could not find a proper state management library, which was a bit problematic yet not impossible to round-engineer. It scores for JavaScript for which there are many good state management libraries such as Zustand that I have been recently using. It’s noteworthy that by the time of writing this, Zustand has taken the crown from the previous king of the hill, Redux toolkit, which now has less than 3 million weekly downloads compared to Zustand’s over 4 million.
The ways how Blazor on .NET is more straightforward
Having said these things about ReactJS, I feel compelled to praise Blazor for a few very important things which may tip the scales in its favour in certain sense. How you can manage your packages and subprojects in a .NET environment is superior to the mess of JavaScript and NodeJS.
Let’s say that you want to share code between your projects. A very typical situation is that you need to build multiple different versions of your software that all contain some special code yet also sharing some common code. Just google and you find many recipes to do that but it seems that all of them are in one or another way flawed. You got Yarn workspaces, Lerna workspaces, you got Vite, you got Webpack, you got multiple entry points etc. Should you use a monorepo or perhaps after all just Git submodules?
What you have is a really fragmented landscape for managing subprojects and shared code. There are hundreds of chefs offering their own recipes while messing up the kitchen with their own breaking changes. This is the JavaSript world.
There are Solutions
Solutions for JavaScript
The abundance of the JavaScript world does not of course mean that there are no solutions to these problems, and it definitely does not mean that there are no good solutions. There are, but it might take a while to find the good ones. There are some advanced build tools for web applications, such as Vite that come with fine-grained tree-shaking features. This means that the compiler is able to automatically remove unused redundancies from your bundle. This may be very useful if you need to create alternative builds from your code base with slight differences. But if you need to create applications that are significantly different from each other, any lightweight build-time alteration may not be enough.
It’s a very common case that a company has multiple applications that share some common features, yet each one also having their own functionality and their special components. In such situation, everybody sees that it would be real waste if the teams had to re-implement the same features in their code bases all over again. On the other hand, the teams would greatly benefit if they could rather keep the common components in one place where they could be shared among the projects.
The only question is how to do this in a feasible way.
I have been working on many projects over ther years that have been trying to address this issue - with varying results. One solution that I have seen in some companies is that the team creates their own propietary NPM package repo for shared components. This is a very hard path to take. It’s a really heavy weight solution and potentially slows down the overall development because any changes to the shared components requires new package release and all dependent code bases need to be exclusively updated. Oftentimes there are breaking changes and and each dependent application needs to be separately fixed to cope with the changes. This slows down the development quite significantly - probably by one order of a magnitude, at least!
Let’s think about the case that there are multiple drastically different applications yet with some common features and components the house. These days NextJS has emerged as the de facto state of the art framework for React-based applications. NextJS is being development and maintained by Vercel, the company that also provides Turborepo build management tool. With Turborepo, you can easily have multiple different NextJS based React projects that partially use common components which are also their own NextJS library project beside the actual application projects. You can start each application with one command side by side in different ports. When you change some shared component, each dependent app is automatically updated with hot reload mechanism. Then you can immedialtely see how each app is affected by the change. It makes library development really fun - it’s a way better alternative reality than the one where you would end up with a separate NPM repo to share packages between projects.
Solutions for .NET
.NET is a more managed ecosystem than the JavaScript jungle. There are solutions - literally, those things called “solution files”. The way you can create projects as “solutions” and split them into sub-projects with solution files is a really neat and solid - ehm, solution, itself! Read more about .NET solution files and class libaries.
I even personally created an example for you about how to split a main project to two sub-projects. Checkout my Kalabaw Foods Demo App to demonstrate how I created a main project that is then split into two sub projects, the Frontend and the Database solutions.
Okay, enough for now. I’ll be back to problems and maybe even solutions! Until then!