Compile Time Safe Code - Java and JavaScript Examples
This post covers how to avoid errors before running the application, explains what compile-time safe is and how to use it, and example with Java full-stack application.
Join the DZone community and get the full member experience.
Join For FreeCompile Time Safe Code Is True Gem In Development World
Compile Time Safe Code is the code that has a guarantee that after compilation it will work as expected. Such code is valid by design. Some languages and frameworks give Compile Type-Safe (not Time) solutions but this article covers more than just Compile Type Safetiness. Keeping your code Compile Time Safe reduces the number of potential bugs and makes code more reliable.
Compile Type-Safe (Not Time Safe)
Compile Type Safeness gives a guarantee that all variables are assigned to values with the correct type. Meanwhile, Compile Time Safe code is a more general notion that assures developers that code is not just type-safe but consistent in general.
So having Compile Type Safetiness you just can't assign Date type to a String variable. Framework or language won't allow it to happen. Let's write a simple application and assign the wrong type to variable in JavaScript and Java languages:
JavaScript is Not Compile Type Safe
We start with JavaScript (which actually even don't have a compilation step):
So as far as we don't have compile step, our bug will be revealed only at runtime (when it's too late to fix it)
Java has Compile Type Safetiness
Now let's try to write the same code but in Java:
So in the second case, we can identify the problem even before running it. This practice gives us a huge advantage, many bugs can be identified even before running or testing them.
Applying Compile Time Safe Practices In Java FullStack App
Let's review how we can apply the Compile Time Safe approach for classical full-stack applications. In most cases, Java Web applications are represented by 3 layers:
- UI (JavaScript page)
- JVM (Spring/JavaEE/Plain Java + external services)
- Database Integration: JDBC queries, ORM (Hibernate, etc)
How to Make JavaScript Compile Type-Safe?
It's not possible to make JavaScript compile type safe because it doesn't even have a compilation step. But it can be achieved differently. There are 2 options:
- Use TypeScript (I personally recommend)
- Add Flow Framework for JavaScript code (Static type checker)
TypeScript is JavaScript With Safe Types
TypeScript is a version of JavaScript that can check types before compilation. TS is backed by Microsoft and became standard as a UI language in some companies. It's reliable and recommended to use. TypeScript has one disadvantage - once you start using it you can't easily integrate other JavaScript-based components (and it takes time to migrate them to your TS-based system).
Let's write our buggy code and confirm that TS finds that bug:
Flow is a Static Type Checker for JavaScript
As an alternative to TS, you can use Flow Framework (backed by Facebook) that can highlight type inconsistency by adding @flow annotation on top of your JS code. Let's see how it work for our code:
Integrating SQL Databases with Compile-Time Safe Approach
Now we integrate SQL databases but not just in Compile Type-Safe way but Compile Time Safe. Java has many solutions for database integrations from Jdbc to Spring Data. So which of them provides a Compile Time solution? The best example - JOOQ. Before we start, let's write compile not safe solution using Jdbc:
As you can see in the example there are at least 3 potential threats that might be discovered only during runtime:
- Query with mistake
- Wrong column name
- Wrong column type
So one problem is related to inconsistent types that we might read from the results set. Another problem is a possible syntax mistake in the query.
Making JDBC Calls in Compile Time Safe Style Using JOOQ
In order to make all queries compile-time safe, we need to create an OOP solution that might validate the query before it reaches runtime. JOOQ framework provides a query builder that can create queries based on the database schema. Such a builder is compile-time safe. Let's introduce the schema and database and generate JOOQ entities used for query builder:
Selecting one single as UserRecord
Selecting all records as a list of Pairs
Comparing Plain JDBC request and JOOQ
Problem
|
Plain JDBC Request
|
JOOQ Builder
|
Can the query be invalid?
|
Yes
|
No
|
Can the column have the wrong type?
|
Yes
|
No
|
Can the column have the wrong name?
|
Yes
|
No
|
JOOQ solved all problems we had in plain JDBC requests. Meanwhile, JOOQ Builder is flexible as any plain query. JOOQ is a good example that shows that a big majority of problems can be sorted even before compilation.
Compile Time Safe Is More Than a Set of Frameworks
So far we achieved Compile Type-Safe Code in Java (it's given by default) and in JavaScript (by switching to TypeScript). For Database connectivity, we achieve Compile Time Safetiness by using JOOQ.
Is there anything else we can do? Yes, we can. The idea of code safetiness is not limited by some framework or language. Each developer has the power to write code in a safe style. The only question is how much effort it requires.
Solving A Problem Using Compile-Time Safe Approach
Let's solve a problem by using the Compile Time Safe approach. In the next example we deserialize data from the received HTTP response (responseText object):
So during deserialization, we can't know for sure what object is returned in positive and error cases.
What we can do with it? As a solution, we can generate a TypeScript class returned from Java API. Let's review how to do it in the next chapter.
Code Generation Way to Achieve Compile Time Safe Code
In some sense making compile safe code means to limit available instructions only by valid options. One of the known ways is to generate all valid instructions even before we write the code (In the JOOQ example we also had a generation step).
Generating TypeScript Object according to exposed Java API
To have valid parsing we take Java Objects returned by backend and generate corresponding TypeScript classes. We can create our own generator but to simplify it we can use the existing typescript generator. Now let's review our Java API:
In the controller, we return 2 types of objects. For normal cases, we return the User class. For exceptional cases (if the user's name is shorter than 3 chars) we return a User Exception object. To run generator start maven plugin:
mvn typescript-generator:generate
As a result of the execution we have the next typescript objects:
Now let's use generated interfaces and make deserialization valid:
Having safe parsing we can launch our code with valid and invalid users:
The source code of this example is available on github in this project.
Code Generation Using GRPC
As an alternative to the previous, a bit artificial example, it makes sense to describe a much more popular and useful technology - GRPC backed by Google. GRPC provides a way to write classes universal for many languages like JS, Java, Python, C#, etc.
Having a proto file you can define a contract between any client-server communication between any mentioned languages. For example, the next proto file decides the format for the Greeter service with HelloRequest and HelloReply.
GRPC communication has now become pretty popular in the enterprise development world due to its performance and multi-language "compatibility".
The Carelessness of Unsafe Code
According to my personal opinion, I find that one of the reasons for the big number of buggy codes is the exception-based approach. Now in most languages, we have such a notion as Exception. By design, it had to stand for abnormal behavior but in practice, it's used as just one more returned value. I believe that such an approach deprived programmers of the responsibility to write predictable and safe code.
Human consciousness, by its associative nature, has replaced the concept of exceptions by code with errors. Just take a look: NullPointerException is top #1 according to OverOps.
The top 3 exceptions say that developers didn't take care about validation or didn't follow the type-safe code approach.
Final Message
People are not perfect beings and we tend to write code with mistakes but it's necessary to think twice about code safetiness and as a consequence code quality. Here I provided just simple examples as food for thought. So as a developer you can find your own ways how to achieve safe code.
Opinions expressed by DZone contributors are their own.
Comments