Even Server-Side TypeScript Needs the Option to Avoid Asynchronous Processing
Tags: typescript, javascript, node
Published: 2024-06-26 17:15:11

I am developing a TypeScript ORM library called [Accel Record](https://www.npmjs.com/package/accel-record).
Unlike other TypeScript/JavaScript ORM libraries, Accel Record adopts a synchronous API instead of an asynchronous API.

In the process of examining the ORM interface, we compared the advantages and disadvantages of asynchronous and synchronous APIs. In this article, I would like to organize those thoughts and discuss the idea that we might need an option to develop in synchronous processing even in server-side TypeScript.

## What Is Asynchronous Processing in TypeScript/JavaScript?

When running JavaScript on the server side, Node.js is often used.
Node.js uses a single-threaded asynchronous I/O model, and it is common to implement applications that use asynchronous processing.

The way to write asynchronous processing has historically changed, but currently, writing with `async/await` is mainstream.

```ts
// Functions that perform asynchronous processing are marked with `async` and return a Promise
const fetchUsers = async (): Promise<User[]> => {
  // Process to retrieve users from the DB
  // ...
};

// Use await to wait for the result of the asynchronous process
const users = await fetchUsers();
```

As shown above, functions that perform asynchronous processing are implemented by marking them with `async` and returning a Promise. On the caller side, the result of the asynchronous process is awaited using `await`.

In the past, JavaScript achieved asynchronous processing using callback functions, but recently, using `async/await` has made writing asynchronous processing more intuitive. While the development experience has greatly improved, the necessity to be aware of whether the called function performs asynchronous processing and write `await` accordingly remains unchanged.

Calling an asynchronous function without `await` can lead to unintended behavior. Therefore, it is necessary to consider whether the called function is synchronous or asynchronous and decide whether to write `await`, a task that needs to be done every time.

## Asynchronous Processing Used on the Server Side

If there are hardly any asynchronous calls, the above task may not be much of an issue. However, in server-side development for web applications, asynchronous processing is often used. This is because DB access in JavaScript libraries is basically implemented as asynchronous processing.

In server-side processing for web applications, the main flow is to receive an HTTP request, perform DB access such as data retrieval or writing, and return the final result as an HTTP response. The more complex the application, the more places where DB access is needed, and asynchronous processing is often used.

When there are many places to write asynchronous processing, the necessity to be aware of whether to write `await` increases. Compared to cases where asynchronous processing is not used at all, the cost of caring for such detailed parts increases, reducing development efficiency.

## Benefits of Using Asynchronous Processing

So, what are the benefits of asynchronous processing, and why is it used?

The most significant advantage is the improvement of system performance.

In execution environments like Node.js, using asynchronous processing allows the time spent waiting for I/O to be utilized for other processes. As a result, it is expected that the overall system performance will be better than if asynchronous processing is not used. For example, when there is a process to access the DB upon receiving an HTTP request, it becomes possible to accept other requests while waiting for the response from the DB.

Node.js has the concept of an event loop, and it is considered important for performance to not block the event loop by properly using asynchronous processing.

## The Option to Avoid Asynchronous Processing

In the process of examining the ORM interface, I began to think that we might not necessarily need to use asynchronous processing just because we are in a JavaScript execution environment.

Implementing the application primarily with synchronous processing may lead to some performance degradation compared to using asynchronous processing[^1]. However, there is the benefit of reducing the burden of deciding whether to add `await` based on whether the called function performs asynchronous processing, thereby improving development efficiency.

Depending on the nature of the product being developed, prioritizing development efficiency over system performance might be desirable. I believe this is a rather common case.

In other languages used for server-side development, not using asynchronous processing is common. It is often adopted because there are benefits in other aspects even without pursuing performance through asynchronous processing. (On the contrary, I feel that choosing TypeScript/JavaScript for server-side development is not yet mainstream.)

## Advantages of Choosing TypeScript for Server-Side Development

So, if prioritizing development efficiency, why choose TypeScript for server-side development? I believe there are mainly two significant advantages.

### 1. Reducing Context Switching by Unifying Development Languages with the Frontend

Currently, TypeScript is widely used for frontend development in web applications. By adopting TypeScript for server-side development as well, the commonality with the frontend can be improved, and the burden on developers can be reduced by lowering the cost of switching languages.

### 2. Improved Development Experience Through Type Safety and Type Support

TypeScript is a statically typed language, which makes it easier to receive editor support such as autocompletion and allows for early bug detection through type checking. This type safety is a very powerful factor, especially in the development of large-scale applications. Compared to other languages chosen for server-side development, which are not always highly type-safe, the advantages of choosing TypeScript are significant.


These two advantages make it worthwhile to choose TypeScript for server-side development, even when prioritizing development efficiency.

## Enhancing Development Efficiency in Server-Side TypeScript

From the above two points, development in TypeScript has the characteristic of maintaining high development efficiency. However, the current TypeScript server-side development environment, which requires an asynchronous processing-centric implementation, seems to be a factor that lowers that development efficiency. Moreover, it seems to affect various libraries. Due to the assumption of asynchronous processing, ideal interfaces may not always be adopted, resulting in compromised usability.

As a result, the advantage of choosing TypeScript for server-side development might be halved.

For server-side TypeScript development to become more widespread, I believe it is necessary to have the option to develop without using asynchronous processing. It is necessary to be able to choose a development experience where there is no need to care for asynchronous processing every time there is DB access.

When developing a new TypeScript ORM library, I decided to adopt a synchronous API. The reason is that by using a synchronous API, the interface can be more abstracted, and I believe the experience of library users will improve more than with an asynchronous API.

Until now, server-side JavaScript might have been chosen for performance.

However, I think server-side TypeScript might be chosen for development efficiency. And to support that, I believe the option to avoid asynchronous processing is necessary.

## Conclusion

I discussed the idea that to improve development efficiency in server-side development using TypeScript, it might be necessary to have the option to develop without using asynchronous processing.

Please check out '[Introduction to "Accel Record": A TypeScript ORM Using the Active Record Pattern](https://dev.to/koyopro/introduction-to-accel-record-a-typescript-orm-using-the-active-record-pattern-2oeh)' and the [README](https://github.com/koyopro/accella/blob/main/packages/accel-record/README.md) to see what kind of interface Accel Record can achieve by adopting a synchronous API.

[^1]: Depending on the environment, there may be cases where performance is not adversely affected, or ways to avoid performance degradation through system configuration. Please refer to '[Why We Adopted a Synchronous API for the New TypeScript ORM](https://dev.to/koyopro/why-we-adopted-a-synchronous-api-for-the-new-typescript-orm-1jm)' which I wrote previously.