Why we gave up Java serverless and adopted Typescript

This article is a reprint of only the technical part of the personal blog. Why we gave up Java without a server and adopted Typescript -Junks, GC cannot sweep-

Also, as I wrote on the blog, there is an English version first due to various reasons. I wrote this as well, so please understand that it is not a theft.

\ [Original article ]: Why we replaced Java with Typescript for Serverless in dev.to

Introduction

** serverless ** is one of the hottest design methods these days, and perhaps many developers are starting to apply it to their products, more or less.

I myself am completely fascinated by serverless computing, and I don't feel like returning to the old-fashioned world of managing and operating servers and middleware.

If your application is designed with scaling and dispersibility in mind, the benefits of traditional server application features are relatively small, and the disadvantages of switching to serverless aren't that great. Recently, when I have a consultation about design, I always try to talk about serverless.

By the way, serverless is very different from the existing development method, so it is necessary to ** renew the knowledge that we have now and develop while reviewing the existing method and technology stack **. When it comes to reviewing, ** what language to use as the development base ** is, of course, subject to the technology stack that must be reviewed.

As the title suggests, we finally adopted ** TypeScript ** and have been developing and maintaining it for about a year and a half. And now, a year and a half later, TypeScript has done more than we expected, which is my personal impression.

So, in this article, I'd like to explain what the problems were with the language I was using before, and why I benefited from switching to TypeScript.

Why I had to give up Java

Now, before we talk about why we adopted TypeScript, let's first talk about why we had to give up Java, the very powerful language we used to use.


As I mentioned earlier, I like Java quite a lot. The first language I touched was Java. I've learned a lot about the JVM, and I'm pretty impressed with how the divine runtime works. (Maybe the one I made is a god) So, like some college students, ** Java is shit, legacy, or useless, I'm not going to say that in this article. ** ** Also, I'm not very happy with such comments. It's just that Java didn't really fit into the serverless system. We would appreciate it if you could understand that point.

Why I had to give up Java

Now, before we talk about why we adopted TypeScript, let's first talk about why we had to give up Java, the very powerful language we used to use.

In our service, the server side was basically written only in Java from the time the service was established. Of course, Java already has many advantages, especially

-** Platform Free ** -** Well done JIT compilation ** -** Yabai GC ** -** Well-structured grammar ** -** Static typing ** -** Functional support (especially these days) ** -** Diverse libraries ** -** Reliable community ** (developer, not Oracle)

There is no end to the list.

However, when I was experimenting with the code on AWS Lambda, I realized that Java wasn't very serverless.

The reasons are as follows.

-** JVM startup overhead is large ** -** It gets even more exciting when using the Spring framework ** -** The final package archive is too big (big is over 100MB) ** -** As the number of functions increases, it becomes harder to handle requests without a web framework ** -** Containers only run for about 30 minutes, so you can't take advantage of Java such as G1GC and JIT ** -** Lambda basically runs on an Amazon Linux container built on EC2, so platform-free is not relevant. ** (Not a drawback)

All of the above points are quite annoying, but this time I would like to write a little more about the issues that were particularly annoying.

Cold Start is serious and annoying

The most annoying thing was the overwhelming ** Cold Start overhead **. Perhaps many developers are also suffering from this. .. ..

We used AWS Lambda as our computing platform, but AWS Lambda launches a new container every time a user requests it.

Once started, it will ** reuse the same container instance ** for a while, but at the first startup, in addition to the Java runtime, the DI container and Web container used by the framework are all ** Must be initialized **.

Furthermore, ** one container can only process one request, not multiple requests **. (Even if you pool hundreds of request threads internally.)

What this means is that if multiple users send requests at the same time, Lambda will have to launch another container in addition to the one it's running. Normally, we cannot predict in advance how many requests will come at the same time at what time. In other words, even if you make some mechanism, you can not make all Lambda hot standby in advance.

This inevitably forces the user to wait a few seconds to 10 seconds or more, significantly reducing usability.

Realizing that Cold Start was terrible like this, we decided to abandon the tech stack that had been written over the last few years and choose another language.

Why I chose TypeScript

It's a shameful story, but honestly, I didn't decide by scrutinizing and comparing all the languages supported by Lambda. But to be honest, I had no choice but TypeScript in the situation.

First of all, ** I removed the dynamically typed language **. Maintenance and maintenance by developers with disparate skills over a long period of time. I don't really want to use dynamic typing because it's extended code.

Therefore, ** Python ** and ** Ruby ** weren't an option quite early on.

As for ** C # ** and ** Go **, most teams are currently developing mainly Java, so if you use a language that is too far from the existing language, it will be difficult for new developers to join. Judging that it was **, it was shelved this time.

Of course, I know that these two major languages are getting a lot of attention these days, and especially Golang is gradually increasing its share. However, we had to move development to serverless in a hurry, so we had to forgo it, considering our own catch-up time.

Benefits of TypeScript

That's why we started using TypeScript. What are the advantages of TypeScript?

-** Static typing ** -** Small package archive ** -** Almost 0 seconds startup overhead ** -** Java and JavaScript knowledge can be reused ** -** NodeJS libraries and communities can be used ** -** Functional programming is easier than JavaScript ** -** Easy to draw code structured by Class and Interface **

It is not necessary to talk about how much the statically typed language can bring great benefits to projects that will be operated and developed over a long period of time, so I will not write it here. Here, I would like to mainly write about what TypeScript is familiar with serverless development. The benefits of using TypeScript other than static typing are huge,

Small package and small startup overhead

I think this was probably the most important in terms of the benefits of using TypeScript serverless. (Because the other merits are almost the merits of TypeScript itself ...)

As I mentioned earlier, Java has a very large overhead for starting the DI / Web container used by the JVM itself and the framework. In addition, due to the nature of Java, AWS Lambda has the following weaknesses.

** Multithreading and the ecosystem that surrounds it **

Multithreading is a very powerful feature, and in fact we have solved many performance problems thanks to this feature. The JVM itself also leverages multithreading by default for garbage collection and JIT compilation to achieve that great runtime. (For details, see G1GC and JIT Compile -in-time-compiler /))

However, if you look at the startup time alone, you can see that it takes 100 milliseconds to a few seconds to finish setting up all the threads used for the application. This function itself is an overhead that can be almost ignored for applications running on EC2 with the old so-called Krasaba model, but it can never be ignored for serverless applications running on FaaS such as Lambda.

** TypeScript is NodeJS based and is basically single threaded **. Asynchronous is managed by job queue, event loop, etc., not by another thread or process.

Therefore, most libraries and frameworks do not require thread expansion at startup and require little overhead to start the runtime.

** Huge package archive **

In serverless, source code package archiving is basically ** small **.

At startup, the Lambda container downloads ** source from the S3 bucket for source code managed by AWS and deploys it to the container. ** **

Download time from S3 is usually very short, but when it comes to 100MB or 200MB it cannot be ignored.

NodeJS packages are basically smaller than Java.

To be honest, I haven't studied and don't know why this happens, but I think the following reasons may be related. (If you know this, please let me know in the comments)

--Many Java frameworks and libraries are comprehensive and bring in dependencies that are not necessary for the functions you originally want to use, but JavaScript has many purpose-specific libraries, and it is possible to suppress the dependencies to the minimum necessary There are many. --JavaScript (NodeJS) allows you to write multiple modules in one file, and it is easy to maintain, but the important point of maintainability in Java is that the source tends to grow due to file division and package management.

Actually, when I was writing in Java, I could make packages of ** 200MB ** or more at the maximum, but after switching to NodeJS, it is only about ** 35MB **.

This huge package archive is largely due to our attempts to reuse old code written in Spring, but in fact even optimized code without these unwanted frameworks absolutely requires 50MB. It has become.

Get access to JavaScript knowledge and ecosystem

Since we are also web developers, we basically write the front end as well. Therefore, I had some knowledge of JavaScript and NodeJS.

From the heyday of jQuery to the development of modern frameworks like React / Vue, I've suppressed some linguistic features, and I'm going to understand to some extent how to write code.

** TypeScript is a JavaScript extension language that will eventually be transpiled to JavaScript. ** **

Many grammars and idioms are inherited from JavaScript, so in fact we could start developing the service in less time.

In addition, ** most major NodeJS libraries provide the type definitions needed for TypeScript **, so it was a great pleasure to enjoy the benefits of the NodeJS ecosystem.

Very easy to implement functional

In talking about recent technological trends, we cannot talk without the rise of functional programming. Functional implementations, by their very nature, contribute significantly to writing stable, simple, testable, low-risk code.

Especially in the case of AWS Lambda, since code that always externalizes the state is required, the functional implementation that isolates the state and side effects is very compatible and easy to maintain.

In the first place, as John Resig, the creator of jQuery, said in JavaScript Ninja's Secret, JavaScript has some support for functional programming in the first place. Functions are first-class citizens in JavaScript, and jQuery is actually created with the expectation that it will be written as a function type.

But on the other hand, trying to write functional code in a dynamically typed language can sometimes be very annoying. For example, the functions that can be expressed only by primitive types are very limited, and it is usually quite dangerous to take Object as a return value or argument.

However, TypeScript allows you to specify a type for arguments and return values.

In addition, the following TypeScript features broaden the representation of the functions we write and help us write safer and simpler code.

-** Type: Commonly used types can be typed according to the context. (* string * and * UserId , * Promise * and * Response , etc.) ** - Interface / Class: Arguments and return values represented by Object can be represented by the type that matches the context. ** ** -** Enum: No need to talk ** -** Readonly: You can make your own type Immutable ** -** Generics: Wider range of representations for function interfaces **

TypeScript has many other features that are very useful when trying to write functionally, but I won't list them all here. (Most of them are derived from JavaScript)

I would like to write an article about functional programming and TypeScript somewhere in the future.

You can reuse best practices learned in Java

When you learn TypeScript grammar, you'll be surprised that you can ** write something very similar to Java or Scala **.

In the first place, we have accumulated some good code practices in Java while developing for a certain period of time in Java. The accumulated know-how, such as how to design Class and Interface, how to use enum efficiently, and how to write Stream API to improve maintainability, was something that could not be thrown away.

In addition to interfaces and classes, TypeScript supports access modifiers and readonly (final properties in Java), so we were able to introduce the know-how cultivated in Java as it is.

This includes ** object-oriented best practices and design patterns **. (Function-oriented and object-oriented are not antinomy, so I think it's okay to use them at the same time in a project. Personally.)

If we were to adopt Python or Ruby, which has a slightly unique grammar, I think we would have spent a lot of time deciding how to apply the practices for writing higher quality code to this language. .. (It's fun, I know, just time ...)

Of course, I didn't copy and paste all the design and logic, but rather rewrote most of the code. However, I think it should be noted that the rewriting was completed in a reasonable short period of time with a reasonable quality, even though the approximate part was rewritten with scratches.

Conclusion

We still need to study TypeScript at a level that can be said to be a beginner, but we are already enjoying the benefits with all our might.

When asked now, I'm wondering if Golang is good, Micronaut and GraalVM might be interesting, or maybe there were other options, but I'm very happy with TypeScript at the moment and it's the best. I believe it is one of the options.

Of course, the processing is slow, but batch processing, parallel processing, distributed processing, workflow design, API Gateway timeout handling, data consistency assurance, server, etc. I ran into a lot of problems caused by less and TypeScript.

But it's been a lot of fun working on it as a geek, and some of this is already the best practice for now, right? I also found some methods. (I want to write this in an article later.)

If you're working on serverless in Java right now and you're looking for a serverless shit, a tight shit, or a normal server, you should definitely try TypeScript as well. I'm hoping that it will be more productive than I imagined.

Thank you for your long relationship. If you have any comments or corrections, please do not hesitate to contact us.

Recommended Posts

Why we gave up Java serverless and adopted Typescript
java algorithm Artery Time rounding up and down