DEV Community

Mariusz Sołtysiak
Mariusz Sołtysiak

Posted on • Originally published at mariuszsoltysiak.hashnode.dev on

Should you try Kotlin as a PHP developer?

Its been one year since I decided to switch from PHP to Kotlin. I want to share with you my personal feeling about this change. Also, I want to recommend Kotlin as the possible choice when looking for a new opportunity.

Is PHP a bad language?

Of course not. The latest PHP releases(8.0, 8.1) introduced a lot of good things, like attributes, defining properties in constructors, match expression, null safe operator, enums, and never return type. When I was switching to Kotlin, all these things were missing.

The main issues for me with PHP were not the code style and code structures, these things are pretty much similar now:

As you can notice, PHP developers might be inspired by JVM-based languages. What are the potential benefits of switching to Kotlin/JVM?

Concise syntax

Everyone who had to make some operations on arrays or strings in PHP knows this pain. You need to learn a lot of array_* and str* and str_* functions that are not always self-descriptive. Take a look at some examples below.

https://gist.github.com/marrek13/2b48d9efc966bdd03324901e895abbc3

Now, lets compare it with the code in Kotlin and make your judgment on which is more readable.

https://gist.github.com/marrek13/58b213a1542a356e3a177f4a70fc49f4

Kotlin/JVM also supports things unavailable in PHP, like generics and extensions. Both are very useful and can make the code very clean and reusable.

Differences in functional composition

Lets first take a look at the fold function written in PHP and Kotlin

https://gist.github.com/marrek13/3780b947153526aa0c5a63bbb6981293

https://gist.github.com/marrek13/f57b1b526efe886a911d7e68b327a59a

PHP is not supporting typed/generic collections. When you iterate over the array you never know what kind of values are inside. In functional programming, it might be a problem, especially if you would like to write a high-order function working on a specific type.

In PHP you cant pass the structure of the callback function. It makes development harder because IDE will not resolve it. Also, its harder to write the function itself because again of no generic types support.

The last thing is that PHP has no extension functions support. It forces you to always write a standalone function that can not be connected to a specific class or interface.

Multi-module projects

JVM environment and tooling have much better support for organizing the code in multi-module projects. In PHP, to avoid using one class in another module the only thing you could do is to write some architecture test that will check for misuse of namespaces. In Kotlin you can specify that the class is internal, which makes it visible only in a single module.

From the tools perspective, Gradle and Maven provide out-of-the-box support for multi-module projects. You can enable different plugins and require dependencies per module. I don't remember this kind of possibility while using PHP Composer.

Performance

The services Im currently maintaining have a 99 percentile response time of around 6ms(running on Spring Boot 2.6.x). Achieving this kind of performance with PHP and Symfony framework is very hard and in most cases almost impossible. My personal best in PHP is an average of 30ms per request for a similar-sized project.

PHP is an interpreted language. That means the application instantiation needs to be created for every single request. That also means requests can not be processed asynchronously - there is no way to make the Nginx server suspendable as it needs to wait for the result. PHP now provides JIT and preloading, but the results are incomparable to the JVM stack.

Kotlin offers easy achievable async request handling by using coroutines. Frankly, without any tweaks, it can provide noticeable results and multiply the number of requests that could be handled using the same amount of resources.

For JVM there is another possibility to boost the performance - GraalVM, a high-performance JIT compiler. Its something that can be used with relatively low effort and brings huge benefits. Also, Spring is working on official support for GraalVM Spring Native.

Official libraries availability

PHP is not well officially supported by companies around the world. Usually, when looking for an SDK/library it is not provided from the official source. That means the quality is also questionable. It happened multiple times that the project was suddenly abandoned without replacement. Sometimes I was forced to fork the repository and add some required fixes on my own. Whats more, PHP numerous times misses the libraries for technologies.

Kotlin can use Java libraries. Java is well supported - almost all companies/projects I know release official SDKs/libraries for JVM. Whats more, many libraries support Kotlin directly. It brings a lot of stability and makes the project way more maintainable without fear of suddenly losing any of the dependencies.

Communication protocols support

When you work with microservices, the communication aspect is critical. Using a wrong, slow protocol may cause a lot of problems. It is enough to have only one bottleneck to slow down the whole architecture. I prefer to use gRPC as the communication protocol between (micro)services. It provides decent performance. Using the Protobuf models you can easily define the API contract for each microservice. There are other options like SOAP or Java RMI, but nowadays they aren't in common use, thats why I wont dig into those.

PHP is, unfortunately, offering not-so-good support to gRPC. You can generate a client, but running a gRPC server is hard(or impossible) to achieve. Also, not all Protobuf syntax is supported by the PHP generator. Someone can say, we can still use OpenAPI. Unfortunately, it is again a much less performant solution than gRPC with Protobuf and harder to work in the long run. There is a great comparison of those 2 protocols here.

Message brokers support

In PHP with Symfony, to consume messages from a broker like RabbitMQ or Kafka, it is necessary to run a command that is executed separately from the main application flow. On top of that, you need to set up a proper supervisor to keep it running forever. Now multiply it by the number of queues/topics to consume messages from. In JVM it can be performed easily with multi-threading. The application runs as a process and has access to CPU cores and threads. You can allocate one of the threads (or more) and run the consumers inside the same app instance. Writing event-based communication is much easier to implement and test. You can also think about creating a module that only performs message consumption.

What I miss from PHP is the Symfony Messenger library. I could not find any similar project for Java/Kotlin, that would offer this kind of easy configuration for sending events to various message brokers or data storage. It also allows setting retry/dead-letter policies and sending to multiple destinations.

Creating separated modules/libraries

PHP has Composer, JVM has Maven/Gradle. Creating and managing a library in composer is not so straightforward. I consider it much easier in the JVM world, especially when using GitHub Actions with GitHub Packages. All you need to do is to use one step in the workflow.

https://gist.github.com/marrek13/4d5f01f769083c251626620295b66f8a

The package is automatically attached to the correct repository and can be consumed in other projects inside the same organization. You only need to add a repository to your Maven/Gradle file. Unfortunately, this kind of support is not offered for PHP.

Another important thing is local development. Using the mavenLocal() repository and publishToLocalMaven task you can easily test your changes on-the-fly. In the PHP world, you need to add a specific repository pointing to a local directory and later run the composer update action every time you change something.

Observability

In my job, we put a lot of effort into observability. Our JVM/NodeJS/Ruby-based services use the OpenTelemetry standard to collect the data and publish it to HoneyComb. PHP support for that is currently only in the pre-alpha stage and should not be used in the production environment. It is a massive downside in the world of distributed tracing. Having no possibility to properly apply the telemetry we are limited by the PHP services with how far we can observe. We can still use tools like NewRelic, although if we compare the prices it is a few times more and the functionality is not quite the same.

IDE/debugging support

Kotlin and IntelliJ are both developed by JetBrains. It is not surprising that the IDE support for Kotlin is almost perfect. Not only it always supports the most recent syntax but also provides great integration with JVM tools/frameworks like Gradle, JUnit, and Spring Boot.

The most visible difference is debugging integration. If you want to debug Java code locally or remotely it just works. For the local environment, you don't need to set up or start anything additional. For remote, you only need to provide a debugging port. Also, the debugger in Java has much less impact on the performance - the application starts a little slower, but later on, there is almost no difference.

For the PHP XDebug extension, there is a full article with all the steps to be done. As you might've noticed it is a lot. Some time ago working with XDebug usually meant that you couldn't even boot the Symfony framework if the cache was not warmed up without debugger enabled. I heard it changed a bit with XDebug 3, but I didn't have a chance to test it. One year ago PHP debugging was a painful experience.

Multiplatform code

A great strength of Kotlin is Kotlin Multiplatform.

You can create a multiplatform library with common code and its platform-specific implementations for JVM, JS, and Native platforms. Once published, a multiplatform library can be used in other cross-platform projects as a dependency. (https://kotlinlang.org/docs/multiplatform.html)

In my company, several libraries are used on both mobile platforms. There is no substitute in the PHP world.

However, because Kotlin is not only a backend oriented language like PHP, it has a downside. When you try to find a proper solution on the internet you will need to go through all the articles that usually are relevant only to the mobile world.

Frameworks/libraries support

It is probably the most surprising point for me, but I have to say that PHP frameworks documentation is way better than for Java/Kotlin. When working with Symfony almost everything could be resolved by looking into the official documentation and examples. For Kotlin I sometimes needed to spend several hours to find a proper solution for more complex cases. Maybe its because Im only using Spring Boot and a bit of Ktor. Maybe for other frameworks it is better?

If you care about clean separation of domain models and infrastructure you might also find it hard to define the database mappings in separate XML/YAML files like Doctrine in PHP. Annotations are most likely the only way to go. Similarly, it applies to validation - writing it in a separate file is not easy to achieve.

While working with ORM I also miss one thing about database migrations. Doctrine provides its own migrations library. It allows autogenerating the migration script from entity mappings. Its very convenient, especially when you start doing a new project and it happens often. Hibernate is not supporting it. You can achieve it by using external libraries but its not easy to do and will most likely take several hours of your life.

Should you try Kotlin as a PHP developer?

I mentioned things that I already experienced and considered the key factors for actually trying to switch from PHP to Kotlin/JVM. My feelings are positive. I will never decide to switch back to PHP. Working with Kotlin brings me a lot of fun that I lost after almost 15 years of work in PHP.

So whats my general answer to the question? I think it depends.

You need to know that the learning curve is high. Switch from PHP to Kotlin forces you to start thinking about your application and development differently. Things like concurrency, parallelism, garbage collection you need to learn and take care of them. You need to discover Gradle/Maven to configure your project. You need to find and get familiar with a new Kotlin/Java framework. You need to be aware that sometimes you also need to touch a bit of Java, especially when using libraries that have no Kotlin version yet.

If things above are not scaring you, you're good to go. I highly recommend starting from JetBrains Academy Kotlin Basics Course. Projects there are very well organized and by doing them you can learn the basics of the language. The next step is most likely to try to pick one of the frameworks like Spring Boot and create a small backend project. Later on, its only up to you how to proceed. It is best if your company supports you in the transition, but I believe anyone can switch with some passion and sacrifice of private time.

Top comments (0)