I Hate JavaScript, Thank You Blazor

Mabrouk Mahdhi
5 min readFeb 6, 2024
Photo by Nik on Unsplash

For years, JavaScript has been the undisputed monarch of web development, dominating client-side programming with its ubiquity across browsers and its vital role in web page interactivity. Despite its widespread use, my relationship with JavaScript has been fraught with frustration. From its loosely typed nature to the unpredictable behavior across different browsers, my journey with JavaScript has been a roller coaster of debugging and workarounds. That is, until I discovered Blazor.

The Frustrations of JavaScript

My grievances with JavaScript, though common among developers, stem from firsthand experiences that highlight the language’s peculiarities and inconsistencies. Here’s a closer look at the specific issues that have challenged me, complete with examples that might resonate with many who navigate the JavaScript landscape.

Dynamic Typing Woes

JavaScript’s dynamic typing is often celebrated for its flexibility, allowing variables to hold any type of value at any time. However, this feature can lead to unexpected behaviors and runtime errors that are difficult to debug. Consider the following example:

let value = "5";
console.log(value + 5); // Output: "55"

In this snippet, instead of adding two numbers, JavaScript concatenates a string and a number, resulting in “55”. This type coercion might be unexpected for those coming from statically typed languages where the type of a variable is known at compile time.

Variable Scoping and the `this` Keyword

JavaScript’s handling of variable scope and the this keyword can be perplexing. The scope of variables, especially with the use of var, can lead to unpredictable behavior:

for (var i = 0; i < 5; i++) {
setTimeout(function() { console.log(i); }, 1000);
}
// Output: 5, 5, 5, 5, 5

Due to the function-scoped nature of var, the loop does not behave as some might expect, printing the number 5 five times instead of 0 through 4. This is because the value of i has reached 5 by the time the setTimeout function executes.

The this keyword also behaves differently based on the context, which can be confusing:

const object = {
property: "Value",
method: function() {
console.log(this.property);
}
};

object.method(); // Output: "Value"
const detachedMethod = object.method;
detachedMethod(); // Output: undefined

In the second call, this no longer refers to the object, leading to undefined output.

Callback Hell

JavaScript’s asynchronous nature often leads to “callback hell,” where callbacks are nested within callbacks, making the code difficult to read and maintain:

getData(function(a){
getMoreData(a, function(b){
getEvenMoreData(b, function(c){
console.log('Got data:', c);
});
});
});

This nesting can quickly become unmanageable, especially in complex applications.

Enter Blazor

Blazor’s rise as a powerful framework for web development has fundamentally altered how I approach building web applications. Its innovative features and seamless integration with the .NET ecosystem have not only addressed my grievances with JavaScript but have also revolutionized my development workflow. Here, I’ll share more detailed examples and insights into how Blazor has transformed the web development landscape for me, particularly highlighting its component-based architecture, seamless code sharing, and the advantages of C#.

Component-Based Architecture Enhanced with Examples

One of Blazor’s most compelling features is its component-based architecture. This approach enables developers to build web UIs in a modular fashion, where each component manages its own functionality and design. Let’s delve into an example of a Blazor component:

@page "/counter"

<h1>Counter</h1>

<p>Current count: @count</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
private int count = 0;

private void IncrementCount()
{
count++;
}
}

This simple Counter component illustrates Blazor’s approach. It includes HTML for rendering and C# code for behavior, encapsulated in a single file. When the button is clicked, the IncrementCount method updates the count variable, and the UI automatically reflects this change. This encapsulation and integration of markup with logic are what make Blazor components reusable and easy to manage.

Seamless Code Sharing Between Server and Client

Blazor’s ability to share code between the server and client sides seamlessly has been a game-changer, particularly for projects that require a lot of logic to be shared across both. This capability reduces duplication and simplifies the maintenance of business logic. Here’s an example of how you can define a model that’s used both on the client (within a Blazor WebAssembly app) and on the server:

public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}

This Product class can be defined in a shared library and used on both the server for API responses and on the client for rendering and manipulation. This not only ensures that your client and server code are in sync but also leverages C#'s strong typing to reduce bugs.

Advantages of C# and Compile-Time Error Checking

The transition to writing UI logic in C#, a statically typed language, has significantly improved the development experience by reducing runtime errors and enhancing code quality through compile-time error checking. Here’s a comparative example to illustrate:

In JavaScript, a typo in a variable name might only be caught at runtime:

let userNmae = "Mabrouk"; // Misspelled variable name
console.log(userName); // ReferenceError: userName is not defined

In contrast, a similar mistake in Blazor would be caught at compile time:

string userNmae = "Mabrouk"; // Misspelled variable name
Console.WriteLine(userName); // Compile-time error: The name 'userName' does not exist in the current context

This immediate feedback loop significantly reduces debugging time and increases overall productivity.

Blazor’s Impact

Blazor has not only improved my productivity but also my outlook on web development. The frustration I felt with JavaScript’s idiosyncrasies has been replaced with the satisfaction of developing in a language and ecosystem I trust. Blazor’s integration with existing .NET libraries and tools means I can leverage a vast ecosystem without the need to constantly learn new frameworks or libraries.

The server-side rendering capabilities of Blazor Server and the client-side possibilities with Blazor WebAssembly offer flexibility in how applications are deployed and run, catering to a wide range of project requirements. This versatility, combined with the performance and security benefits of running on the .NET platform, makes Blazor a compelling choice for both new and existing projects.

Summary

While JavaScript remains a cornerstone of web development, and rightly so, my personal journey has led me to embrace Blazor as my go-to framework for building web applications. The productivity gains, the joy of coding in C#, and the robustness of applications developed with Blazor are why I say, “I hate JavaScript, thank you Blazor.

To those who share my frustrations with JavaScript, I encourage you to explore Blazor. It might just change your perspective on web development, as it did for me. For a world where the choice of technology can make or break a project, Blazor offers a compelling alternative, marrying the robustness of .NET with the dynamism of modern web applications.

--

--

Mabrouk Mahdhi

Microsoft MVP, Principal Software Engineer @ B&O Service AG