Coroutines vs Virtual Threads and the Kotlin Java Decision in Practice: A Conversation with José Dimas Luján Castillo and Ron Veen
How to avoid “Java-style” Kotlin, modernize enterprise stacks with Jakarta EE, and evaluate modular monoliths, microservices, and Kotlin Multiplatform in real teams
Kotlin has moved from “Android-first” to a practical option for Java teams that want safer, more concise JVM code without abandoning their existing Java investments.
In this conversation we speak with José Dimas Luján Castillo and Ron Veen, co-authors of Kotlin for Java Developers (Packt).
José is a mobile-focused technologist with 15 years of experience building Android, iOS, and Flutter applications and leading teams globally; he has worked on 500+ mobile apps, written 7+ development books, and taught at 25+ universities across Latin America.
Ron is a seasoned JVM engineer with 20+ years in the Java ecosystem, spanning mainframes to microservices; he’s an Oracle Certified Java Programmer and Sun Business Component Developer, serves as a special agent and lead developer at Team Rockstars IT, speaks at international conferences, and has authored books on Jakarta EE cloud-native migrations and modern concurrency (including virtual threads and structured concurrency).
Together, they discuss what it takes to make Kotlin a first-class citizen alongside Java in production: writing idiomatic Kotlin, choosing between coroutines and virtual threads, modernizing enterprise systems with Jakarta EE, navigating microservices versus modular monoliths, and adopting modern Android and cross-platform approaches such as Jetpack Compose and Kotlin Multiplatform.
You can watch the full conversation below or read on for the complete Q&A transcript.
Kotlin and Language Evolution
1. From your perspective, what are the biggest benefits Kotlin offers to today’s senior developers compared to Java? And in what areas do you still find Java holding its ground?
José Dimas Luján Castillo: When we started using Kotlin on Android, the difference was very obvious because Java was too verbose. Android is doing some things in mobile development with the Java characteristics. So, for example, it was very easy to see the real benefits—for example, null safety. It’s automatic. So in this case it was very, very fast. The interoperability with Java—because at the end, if you have legacy code in another language, it’s where you want to try a different language just because it’s modern, even if you have details with the language, because you will have a lot of problems if you change to a new technology, framework, or language. So interoperability at the beginning—obviously, we didn’t believe we had good interoperability. But when we tried it, we saw, OK, maybe I can do the next steps in my applications with Kotlin, but I don’t need to fight with the legacy code even if it’s in another language. So I think interoperability was a good point to start with Kotlin for mobile development, and obviously we have other things as pushing the programming in a very easy way to add it—or the synchrony. But I think those two points to start for any mobile development, when we try to start with Kotlin, it’s a good point. Well, at the end we need to remember the first step for Kotlin was mobile development, and it was very easy to be clear if I would start with Kotlin—but if Kotlin doesn’t use this null safety and interoperability, probably the adoption was slow or more complex for the people. Because, as I mentioned two minutes ago, the main problems are still there even if you change the language. So I think that’s my point for this comment.
2. How should engineers decide when to use Kotlin versus Java when it comes to new projects?
Ron Veen: Yeah, I think my experience comes more from enterprise and not so much mobile development. What I’ve seen there is, well, there’s a natural eagerness from developers to learn new things. And like José said, when you switch from Java to Kotlin, it really feels—I don’t know—it makes programming a bit more fun again. That’s something I really found. I could see developers getting enthusiastic. I think one of the benefits is you actually have more concise code, so you write less code. And also, like mentioned, the code tends to be less error-prone. You know, null safety is really a big thing. You can actually see that a lot of frameworks are working towards that now, also with regard to new Java versions, but nullability will always be a thing in the JVM, and Kotlin takes care of that for us.
Now, why would you adopt this technology? Well, I think there could be a number of attractive points. Again, like I said, there will be less code—and less code is good: less code to maintain. There are less errors in the code. It might make your development team actually more attractive to new hires because you’re using a very modern language. And we shouldn’t forget Java really evolved. Java had Project Amber, where it added a lot to the core language—like records and sealed classes and pattern matching—things that already were in Kotlin. Java gets them added slowly—they’re getting added—but I think Kotlin is just always quicker with adding those new features that developers really crave.
3. Many Java veterans fall into the trap of writing Kotlin in a Java style. What are some common mistakes or mindset shifts that Java developers need to overcome to write idiomatic Kotlin?
Ron Veen: I think that’s the thing we all get to at some point. We start with Kotlin and then we write it in this Java style, right? And this is not what we should do. It is a natural reflex—let’s be honest—because first: OK, I want to do a new language, but I also have a project to finish, or a task to finish, or a sprint to complete. But also, we’re still trying to write code in the way we know it and just use the little things. So that can kind of give you some problems there.
But sometimes, as a developer, you have to be willing to relearn the language. You know Java, and now you’re going to do Kotlin. You can do everything in Java style in Kotlin, but you really should try to relearn the language. It’s not a drop-in replacement. You really have to be willing to learn.
I can remember I once pitched it at a project and developers really got, “OK, this looks good, this looks fine.” And then, just to force myself to really do it in a Kotlin way, I tried to shrink the number of lines that were in there. The original from 250 went down to under 100 or something, and that was not technically needed, but it was: “OK, how can I leverage Kotlin’s native way of doing things and make things faster?” So sometimes you just have to pick up a piece of existing code and decide to rewrite it completely—and forget about everything you know about Java.
4. Could you share best practices to avoid “Java-esque” Kotlin and fully leverage Kotlin’s language features?
José Dimas Luján Castillo: As Ron mentioned, that’s the thing. When we start with Kotlin, I think 99% of developers start by just translating the code. That’s the problem, but it’s part of the beginning—because we have one line of code in Java and we want to see how we need to write this line of code in Kotlin.
But later you hear about the benefits in Kotlin, and if you are translating each line, you will see you don’t have less code—you have the same code in a different way. Maybe it’s easier to read, but it’s the same code. But when you start asking that kind of questions, you will see the benefits because you will start trying to look inside how Kotlin is doing that. And you will see five lines or 10 lines in Java—maybe it’s two lines in Kotlin, or three. So you will see the real perspective from Kotlin, and this is the first step, I think, to look at good practices.
For example, you will see not only fewer lines or differences, but the achievement in these cases. For example, immutability first—you will see, “OK, I need to think in immutability first,” because it’s a different way to start the problem. So, for example, you are automatically using good practices in the general programming work without doing anything, because you don’t know sometimes, or you don’t have it clear. We are creating in Java, but we are not thinking in immutability first. So after a couple projects, or some examples you are trying to execute, you will start seeing you are using good practices sometimes—because it’s natural here in Kotlin as immutability.
But now you can do the same thing in other languages, even Java, OK? But you need to do something to have this in your code. In Kotlin, sometimes you do good practices by default. You don’t have to change the code to have it because, by default, you have these good practices. And you will see a lot of those cases—not just immutability. For example: the collections and streams, the lambdas. Lambdas is the same base. Lambdas is not something advanced when you are learning other languages; it’s not the first subject, the lambdas, for example. And here in Kotlin, when you are starting the code, you will see lambdas since the beginning sometimes. Even if you don’t know it’s a lambda—you know it’s code—but later you will see it’s a good point to start doing something. So I think that’s a good way to start using good practices, and sometimes you don’t even know you are using these good practices.
5. I’d like to get your perspective on concurrency. Java’s recent releases have introduced virtual threads and structured concurrency to simplify multithreading. According to you, how should engineers approach concurrency now? For instance, when building a high-throughput service, how do you choose between Kotlin’s coroutine model and Java’s Loom-based virtual threads?
José Dimas Luján Castillo: Well, I think the way to—maybe it’s not the easy way to understand that—but I think if you are coming from Java, you can see concurrency as a model. It’s a—we have a definition about how we can do some stuff—and coroutines is a model, a structure, to think about it.
What are the important or main parts for this? You have cancellation, you have propagation, you have control of the whole cycle. That’s the thing. You don’t need to think too much in all the scenarios because you have the structure. So I think that’s the main concern when we are trying to understand, because sometimes you need to think by yourself in all these scenarios, but not in this case. Coroutines is very clear: you have the ingredients to start doing anything—OK—with coroutines.
Versus, for example, virtual threads: you will have a way—a very simple model—for example, it’s very traditional. We have it very, very clear, because the thread is a—Way to do the things. We have excellent things, but at the end, they can work together, because maybe you can use one for some specific problems and you have other options for other specific things.
It’s not a model about who is better, because that’s another thing. A lot of people, they want to know the faster way to do that: “Let’s go to the way to do that.” And it’s not the case about, in this case, coroutines. If you have some specific problems and you don’t have the model, well, think about: we have coroutines. But if you have a very complex situation, for example, and you need to put less complexity in your system, maybe you can use threads, for example.
That’s the thing: it’s not too complicated to use, for example, the Java virtual threads, because if you have a very complex structure with layers, probably this is the advantage—you can do that. But if you don’t have that kind of level of complexity, you can use coroutines, for example, for other things.
And at the beginning, obviously, the main complexity when you are using the JVM to do that kind of task—the problem is, you have a monolithic focus or scope for that, and now you don’t need to think just in the monolithic way to have an answer. I think that’s my comment for this.
6. How you see these two concurrency paradigms (virtual threads and coroutines) complementing each other in practice.
Ron Veen: Yeah, first, we should say that I think both virtual threads and coroutines basically try to solve the same problem, which is executing async code, but making it appear sequentially in the code so the developer can really reason about, “OK, what is the flow of my application?” So there’s not this thing called callback hell, where we have a million places where there are callbacks all through the code.
Both systems, I think—really, even though in the end they’re running on native operating systems, that’s both virtual threads and coroutines—they’re actually managed by the runtime itself, and it just switches the threads to execute things. So you can really see that throughput is a lot higher with both of them, where, on the side of virtual threads, it is really good for blocking—when there’s blocking things in between. You shouldn’t—like, if you have very memory- or CPU-intensive action, I don’t think virtual threads, in general, is a good solution because it won’t give away control.
But in general, like José said, I don’t think it’s like a race between, “Oh, you should use this,” or “You should use that.” I think you should sometimes just look at what is best for your specific situation. Of course, virtual threads, they also have structured concurrency, which they build upon, which gives you a very nice framework—so that could actually be a good reason to choose.
Again, if you have these difficult, really difficult use cases in general, I think both virtual threads and coroutines is a paradigm shift for developers in their mindset because, normally, as Java developers, we were always told, like, you know, threads are really expensive. So you should be careful with it. We should pool the threads and stuff like that.
And I think what we see now is, with both of these things, that we can actually—calling a coroutine or calling a virtual thread is just as cheap as calling another function in your code. So it’s also a mindset of where you want to use this in your application.
Enterprise Architecture and Team Practices
7. Enterprise Java is undergoing a renaissance with the release of Jakarta EE 11, which brings a modernized, cloud-optimized platform—introducing features like the Jakarta Data API and aligning with Java 21’s virtual threads for scalable concurrency. Ron, given your experience with cloud-native migrations, what do these developments mean for teams looking to modernize legacy Java or Jakarta EE systems?
Ron Veen: Yeah, I think with Jakarta EE 11, the whole ecosystem made an enormous step because now, for the first time, Java 17 is the baseline language level. So we’re really optimizing here. That means suddenly we can use things like records. Now we can use the switch expression, we can use non-sealed classes—all these things which were added by Java via Project Loom—they’re now actually available to also use on the enterprise side. So I think that’s already quite interesting.
Like you said, there’s this new API, Jakarta Data, which has this repository-based approach. And for people familiar with, for instance, the Spring Framework, it’s very close—not similar, but very close—to the repository pattern that Spring uses. So I think that is really good.
They also came—well, they already came earlier—with the Core Profile. Jakarta EE has multiple profiles, and the Core Profile is very interesting because it’s a very slim runtime that you’re getting then, which means it’s ideal for microservices situations.
But yeah, I really think it uses great chances. It promises Java 17 as a minimum standard, but there’s also this technology compatibility kit that goes to Java 21. And then you’re right—suddenly virtual threads also come within reach. And actually, using virtual threads, you have to run Java 21, of course, because that was the first official release where it was a final version. But there’s this thing called ManagedExecutorDefinition, which has this property “virtual,” and if you only set that, you can actually use virtual threads in your Java applications—or Java EE applications. So I think they’re making a real big step.
And about the migration part—just to get back to the question about the migration part—I think there’s many steps that you can actually take. But if it is a simple upgrade, you should first see: Am I already on Jakarta EE at all, or am I still on Java EE?
Now, if you’re still on Java EE, then there are multiple ways to migrate your sources, right? There’s this book—you’re right—from Packt Publishing, where we actually outline a number of these things. There are tools that you can use. There are even dedicated plugins for IntelliJ, for instance, that can help you a lot. It’s a lot about namespace conversion, but there are a few other tricks as well.
Now, if you are already on the Jakarta EE part, then I think upgrading is actually quite simple—basically upgrading your Java version. And this Jakarta Data project is actually quite interesting, and I would just advise architects and developers to say, “OK, use it if you’re building a new feature,” because it’s completely backwards compatible with JPA. So it has the same—you know—so there’s nothing new you need to change. If you write something new with new database tables, just try to use this Jakarta Data for those specific situations and services.
8. How can architects best leverage these new tools—like repository-style data access and virtual threads—when migrating monolithic applications to cloud-native microservices, and what common pitfalls should they watch out for during such transitions?
José Dimas Luján Castillo: Yeah—for example, about the first part, the modernization: it’s clear the enterprise is not dying. We are evolving everything. That’s the first part because, obviously, a lot of people love these phrases to put in a blog. But now, I think the enterprise is very clear—it’s evolving.
And the idea is, obviously, we want to create good tools for everyone, and we want to create good code for legacy, because at the end you will keep using it.
And about microservices and monoliths—obviously, you will find a lot of discussions on the internet and Reddit and blogs and YouTube channels, and everything about what is better for your project or your company. The thing is: the problem is when you are just reading without the context, and you need to understand each context is different. I think that is the first part.
The second is: microservices, in my experience, is not the goal, OK? It’s the consequence for that. Because when you always see microservices as the goal for each software developer or architect, probably that’s the issue—that’s the problem. Because if you don’t have developers with experience, and you don’t have a good architecture definition, you will have microservices with the same problems as monoliths. That’s the thing.
The other part is: the monolith—in these cases, people are looking back sometimes, in some cases, at monoliths as old code. And obviously, that’s a lie, because you can use monoliths without problems for huge systems, and you can save the complexity of microservices. You can use monoliths to scale. Actually, you don’t have to always use microservices to scale. It’s easier to understand and to maintain this because you have less complexity in your code.
So the question to use—“Hey, do I need to use microservices, yes or no?”—for me, I always try to answer a question before, or maybe two questions: Are we prepared for paying the real cost to use microservices—not just the money? (and) are we prepared to use this architecture or not? Because if you are doing this before you have the knowledge for that, probably you will have a huge problem. Because it’s not too easy to change your architecture, change your definitions, your business rules, and everything—and then you need to roll back to monolith because you are not prepared.
That’s my concern, obviously, when I work in teams and they are just focusing on changing to microservices because they read it in a blog. OK—that’s my recommendation, always.
9. What criteria or signals help you decide if a modular monolith might be a better choice for long-term maintainability, and how do you manage the trade-offs for scalability and team ownership?
Ron Veen: Well, this is really kind of a subject very close to my heart because I guess we’ve all been through this wave—there was this FAANG group: Facebook, Apple, Amazon, Netflix, Google—and they all came with microservices, right? So we thought, “This is the way we need to go. This is the wagon we need to jump on.” And I think a lot of us did. And like José said, I think we also found maybe it’s not the right choice, because you should ask yourself: if you have 200 employees, are microservices—for your business—the right solution? Can you actually afford it?
Because microservices, on the DevOps side, require a lot more overhead. There’s a lot more monitoring involved. You need to watch these services, you need to see what is coming out, so there are a lot of metrics needed to keep them running in production. You need to make sure they’re still running in production, because before you had just one monolithic application.
And another thing is that monoliths have become like a negative name, right? Like dinosaurs almost—which it isn’t. I mean, it’s still brilliantly functioning code running on application servers that have been there for a very long time. So there’s nothing bad about them. They’re just being opposed to being “old” compared to microservices.
So you have one running, and that’s easy to monitor, it’s easy to do logging, it’s easy to do debugging as a developer—you know, you just do it remotely. But when you’re switching to a microservices platform, you’ve got dozens or hundreds of services running. You need to make sure each of them is still running. And if you trace a problem, you need to somehow combine all the logs so that you can actually go through the logging and try to find out what happened. So there’s a lot of work there trying to debug a problem with microservices—they’ll keep you busy for a bit. So there are a lot of things there that are happening, I think, where you have to be really careful.
And yes, like José said, it should never be a technology choice, but it should really be a choice based on what we need. From my experience, what I have learned is: I would start with what I would call modular monoliths. The classical monolith is where all the modules are intertwined without very clear boundaries. If you have a modular monolith, basically what it would mean is you still have your modules, but they can’t interact directly with one another. There’s a predefined API somewhere, and one module is only allowed to access another module via this predefined API, which really makes the code less cluttered and far less risky to change—so things will break less.
Because if I would go find an API, then the API will change and I will see it—or the API won’t change, but I can change internal methods without something breaking there. So my suggestion would always be: start with this modular monolith, be very clear on your boundaries, force that we go through APIs, and then just monitor the system—watch it.
And if there are typical situations—like if you find there’s just one module, let’s say a customer module, that requires a lot of changes, which means a lot of redeployment—then that might be a case to say, “Well, maybe I should factor this out, make it a microservice,” and combine the two. There’s nothing against combining microservices with a modular monolith. Or maybe there’s different resource utilization, different scaling requirements—well, that could be another case where you say, “Okay, if this is really the case, maybe I should factor it out.”
But even then, I would say: look at how much the costs are, and only when the cost of keeping it in starts to outweigh the cost of switching to microservices—that would be the moment to make this choice. But again, microservices require a different mindset. You’re also getting the distributed tax that you’re paying, and that can be really, really expensive, and you should be really careful. But I guess then we’ll get into the realm of domain-driven design and bounded context, which might be a bit too much for now.
10. It has been said that introducing Kotlin into an established Java codebase isn’t just a technical change but a cultural one. Key advice from Kotlin adoption experts is to “win the hearts and minds” of skeptical Java developers—not only through hard facts (letting the improved code quality speak for itself) but also via soft factors like easier onboarding and community support. Showing Kotlin’s concrete benefits—for example, its focus on safety and conciseness that addresses fundamental Java shortcomings while staying 100% interoperable—can help gain buy-in. Drawing from your teaching and leadership experience, what strategies do you recommend to gradually introduce Kotlin in a Java-centric organization?
Ron Veen: Yeah, I think what you always find if you introduce something like Kotlin into an organization, you should be very aware that there will always be some gurus in the company who are very focused on Java, who know the inner details, and who might actually see bringing in a new language as a threat to their supremacy. So I think the most important thing is to get them on board, because in general I would expect that 60–70% of developers would be really interested and say, “Oh yeah, we’re going along with this.” So maybe it is not direct.
What we sometimes did is we had a team with some enthusiasts and some critical people, and we let them develop something new. It could either be—if we’re doing microservices—I mean, microservices are brilliant for this, right? Because you can choose whatever technology you want for your new service, so Kotlin would be a great choice there. So that would be a good thing: have this team of skeptics and enthusiasts and then see how they work together on the problem. Because if you just do the one or the other, we’re not really getting everyone on board.
That would be a really good approach, I think. But I sometimes also have done—you have this thing called Advent of Code, right? This is, right now at this time, the period leading up to Christmas, and there are new coding challenges. You could say with your team, “You know what? We’re going to do Advent of Code, and this year we’re going to do it in Kotlin,” and try to see how we would work it out there. So that could be a thing.
Of course, you can do things with hackathons in your own team and say, “We’re doing these coding sessions, and let’s try to explore how we could use Kotlin there.” And finally, I think if you would do code reviews with the whole team, you could also go through Kotlin and gradually explain: “OK, what are we doing here, and why are we doing it this way in Kotlin?” That makes people really see, “OK, I’ve done it the Java way,” and I think that really plays—for instance with collection classes—because Kotlin, that’s such a great collection of, well, collection letters, and then people in the code—with you, the skeptics—can see, “Oh wow, this is actually quite nice,” and very concise how we’re writing the code.
Enforcing it upon someone, I don’t think it’s ever going to work. At least they’ll probably do it, but they won’t do it by heart. So I think, in general, with these steps you can actually win their hearts.
11. How can engineering leads support their teams’ upskilling and address any resistance, ensuring a smooth transition without disrupting productivity?
José Dimas Luján Castillo: I think maybe the good news or the bad news—it depends—but it’s more about a leadership issue in this case. Because I think we have a beginning that’s very clear: we need people saying the next steps for that. Because if you don’t have this follow-up about leadership, probably you will see a mess in some cases.
That’s good news because if you have the person in your team, obviously it’s an easy way to do that. But if you don’t have it, you need to create it or you need to hire these people, because that’s the thing. Maybe you have people with good leadership, but without the knowledge for the adoption.
Because, for example, the most common errors when you are trying to do that: you need to start with small limits. If you’re trying to migrate everything, or the most complex in your legacy code, probably it’s not a good idea. So my recommendation, for example, in some companies when they ask for something similar is: start with the small models. Because you need to see—if you think it is good writing code, that’s correct because they are working with you—but they really understand the business. Because maybe you will see they know the new business, not the old business, for example, because you are using old code sometimes.
The other part is: it’s a new language, it’s a new paradigm, it’s new code. At the end you need to see if you have a problem with the adoption because sometimes people understand the features, and it is not the real benefit. They understand the modern things, or they understand the faster way to do the things, but it’s not the same as the best way to do that. So don’t be closed for these situations, because obviously the most important is: OK, we will do the migration. I am not saying this is the best way to do the things because probably the team can find a best way to do the things, because they really put the hands on the code. But if you are very closed with that and you say to the team, “Just follow what I am doing,” probably you will miss a good part of the code from the team.
So that’s the other part: just go talk. OK, it sounds weird, but when you are using the team for the migration, probably they are the best way to understand the situation. Because you can’t imagine how the thing is working, but when you are rewriting the code you will see the real things. Maybe you have good code and you don’t need to rewrite this part. Maybe you have to rewrite another model, not this one, because you will see the benefit—and maybe the benefit is not too good to change it. Maybe the benefit is in another model. Sometimes that happens.
Because the problem is: if you think the leadership—or just one person—knows everything about the project, probably you are not with the correct answer. Because people need to put their hands on the code for that.
And just to close that: you need to think in your team. In these cases, you need to trust in that team to take some decisions. Obviously they need to explain to you or explain to the company, but probably they are the best way to understand the problems in those cases.
And you need to give space to the teams to play with new toys because probably they have the answers, but they don’t know yet. So if you let them play with some new features or some new code, probably you will find good things in that.
And obviously don’t try to read productivity in guidelines—if you try to read it as: “If you have more lines of code or less lines of code,” probably you will miss something. So in this case my recommendation is: we need to avoid productivity as “more lines of code or less.” Just keep trusting in the team and decide together if it’s a good part for the business—if we need to change something or not. But if you don’t open the code and read it and try to play with that, you don’t know if the adoption is a good idea or not.
Mobile Development and Cross-Platform
12. The Android development landscape is in constant flux. As of 2025, we’ve seen the rise of Jetpack Compose for declarative UI, more sophisticated modularization of apps, and renewed emphasis on clean architecture principles for maintainability. Based on your experience building hundreds of mobile apps, what do you consider the three most important architectural practices or patterns for modern Android development?
José Dimas Luján Castillo: I think the last two years we really see why they think to start using Kotlin. That’s the thing, because for Jetpack Compose, I think that’s the main concern.
And if I need to say three keys for that: I think we need to separate the responsibilities. Even if you are not using it for Android, I think if you can separate your responsibilities in the code, it is always a benefit for everyone—for testers, for developers, for product owners, for everyone—because it’s very easy to understand each part for everyone.
Trying to use the definition of modules—not because it’s a new way to do that. Maybe that sounds like, “We need to separate everything,” but no. The thing is: if you modularize everything in your project, it’s very easy to add these features in this module as a feature, or delete, or change this module.
For emergencies, for example: maybe you have a critical bug in some part of the code, but if you have modules you can just put it in another part and you can continue with the regular functionality.
So I think that’s the second. And the third one: I think the architecture is changing. You need to prepare your architecture ready for change, because when we create code, we think the code will always be the same code—that’s the problem.
It is very complex. People try to create architectures ready for new changes, because we don’t have the time, we don’t have the money, we don’t have the team for that, but I think great developers and great leadership are always preparing the project for changes—not just for the new framework.
Because if you prepare your project just for the new framework, when we change the paradigm—in this case, for Jetpack Compose, because it’s a really different way to do mobile applications—probably all your code is not ready for these changes. That’s the deal, and that’s the problem. So now you will see a lot of mobile applications where the new features are working with Jetpack Compose, but the old ones probably will never migrate because they are not ready. They don’t need to keep waiting a miracle to change the modules just for the new Jetpack Compose implementation, for example.
So that’s my three keys. And in my context, in my current projects or last projects, I always ask, for example, when I will implement a new technology: what kind of problems will we resolve with that? The cost of the adoption, and the impact for the long term.
That’s my three main variables I have in mind, and I always try to put a number: how many problems I will solve, the cost of the adoption—how many people and how many resources we need—and the impact we will have: long term, mid term, or short term. I think with these three variables I create a table and share it with the team, and after that I have a very clear situation. We decide if we need to follow these new technologies. That’s what I did in the past.
13. José, with your background in Android, iOS, and cross-platform frameworks like Flutter, how do you see Kotlin Multiplatform fitting into real-world projects today?
José Dimas Luján Castillo: I think we are in a very interesting situation in mobile development right now because we have a lot of actors—maybe serious actors—because in the past we had a lot of actors. But the problem is, I am not saying I am not a fan of JavaScript, but the problem for development in the beginning for multiplatform is they had a lot of JavaScript frameworks, and at the end it’s not the same case because it’s not a real multiplatform situation.
But now we have a lot of multiplatform situations. We have Flutter, we have SwiftUI, we have Android with Kotlin Multiplatform. So you are really creating a codebase for using in the other option of mobile development without having to add some patches for the situations. So it’s a real competition for who is the best option.
Now, we don’t have a clear winner for that because that depends for each team. For example, if you have an iOS team and you have five developers using iOS and Swift, why do they need to learn Kotlin? Maybe it’s not the best case for that. Maybe you have the Swift situation. That’s the real thing because you will need to pay—you will need to use money—for this migration at the end.
But now we are in the most easy way to create multiplatform applications, even for mobile developers, even for Android developers or iOS developers. So we have a real situation where we can separate the logic from the UI without problems. With Kotlin Multiplatform, it’s very clear to do that. You don’t need to be expert on Android or Java or Kotlin. If you read the code, you will understand in a very easy way—even because, when we write the code now, you will see a lot of web programming paradigms.
For example, the reactive way to do websites with Vue or React—you will see, when you read the code in mobile development, it’s very, very, very easy to understand. You will see Flutter is OK, React Native is OK, OK, but at the end Kotlin is part of the body of mobile development—and safe in this case too.
So we need just to wait—maybe a couple of months, or maybe a couple of years—to see the real impact of Kotlin Multiplatform. The way to understand Kotlin Multiplatform is very easy if you understand Kotlin. You don’t need to understand too much. Probably you will need to take two or three features because maybe these features are not too famous in backend development, for example, or in the Java world. But it’s two or three, not too much, because at the end you are using your regular Kotlin in backend—you can just use it in mobile development. The problem is you need to understand how the operation system is working. That’s the only thing.
The tooling is very advanced. That’s the other part—you will see Kotlin Multiplatform is running too fast for these changes. They are creating and sharing tools each three months, four months for the people, the ecosystems—and Kotlin too. So it’s very, very good news for the developers because you will see two or three really good maturity tools each four months.
So I think that’s the advantage to use Kotlin Multiplatform for mobile development versus Flutter or React, even if they have more years, because now they are in other stage. They are trying to increase the developers in the ecosystem of Flutter or React, but Kotlin—they don’t need to do that because they passed this stage. Because if you are using Java, you can use Kotlin. If you are a Kotlin developer, you can use Kotlin Multiplatform. I don’t need to convince you to use it because I don’t have the problem with the knowledge. You have these tools—just why is not the problem?
The question is: Why are you not creating mobile applications with Kotlin Multiplatform? That’s the real thing because you have the knowledge, you have Kotlin, you have Java knowledge. Maybe you just need to take a look at the operation system. I think that’s the real situation for Kotlin Multiplatform. They are just waiting for more people in the ecosystem because if you know Kotlin, you can do that.
14. We’ve been talking about Jetpack Compose, we’ve been talking about Kotlin Multiplatform, which are, you could say, new technologies or new approaches, and we talked about them in the context of adapting them into large-scale apps. But when it comes to a large-scale enterprise setting, what challenges should teams be aware of when adopting a new technology or approach while they aim to access benefits such as maximizing code reuse without compromising native user experience, and so on? What are some best practices or difficulties that teams should be aware of when trying to bring something into the stack, so to say?
Ron Veen: Yeah, that is an interesting question because I guess one of the core reasons also for Kotlin Multiplatform to be there is code reuse—specifically, if you have business logic, that’s really the code you don’t want to have distributed over different platforms, but you would like to have centralized.
So I think everything goes down to that, and that you should really focus on which parts you really think you should share. Because if, again, you look at code reuse, and especially in enterprise environments—reusing parts—it depends on your architecture, doesn’t it?
Because if you have this classical architecture where you have one large single deployable unit, then code reuse could be quite easy. If you get to the microservices situation, well then code reuse becomes a little more tricky, I think. And then, you know, the whole DRY thing—“don’t repeat yourself”—suddenly becomes a bit more fluid, that you could say, well, sometimes we just don’t want to reuse in order to maintain the independence that microservices should have.
So, again, here I think it all depends upon what is the architecture you’re trying to support. So I think there’s no one-fits-all solution here—so, no.
About the Book: Kotlin for Java Developers
15. Your book, “Kotlin for Java Developers” is aimed at software developers proficient in Java who want to learn Kotlin for professional development – it’s especially relevant to Android engineers, JVM backend developers, and full-stack Java programmers maintaining legacy systems. What inspired you to write this book together?
Ron Veen: Well, the good thing is—Jose actually—the bulk of the work was already there, right? So I actually came later to the project, and the majority of this book—and the credits for the book—should really go to him, because he had already written a large part. I think I only added a few chapters.
But I think I came to the project for a simple reason: anyone who writes code—if you have, like, 10 developers and you say, “Write this piece of code for me,” then you’ll get 10 different solutions in the end. It could be typical small things or something, but everyone has their own style. You can always see it with code reviews: “Shouldn’t we do it like this? Why not like that?” And I think it was the same here with the book.
I think Jose had already written the majority of the book, and—just like with code—it’s always good to have a second opinion about it, and that’s basically where I came in. We started chatting with one another and talking about, “OK, should we rewrite it like this? Is this better?” Just fine-tuning a lot of things and having two perspectives on the book.
So that’s how I got to it—or actually what I did on the book. How I got to it was easy: I was approached by Packt. So I said, “We have this book about Kotlin.” I thought, “Yeah, Kotlin—that’s great.” That really touches me. I think it’s a great technology and should be used more often. So yeah—if there’s a way that we can spread the good news, I would really love to do that.
Then I got to see all the work that Jose had already done, and I thought, “Well, this is just brilliant,” and yes, I’d love to be a part of this. I just hope that Java developers really see it.
What I really liked about the approach to this book was it’s not like I’m telling you Kotlin from A–Z. I really love that we have this approach where we say, “Wait a minute—you’re already a Java developer. I don’t need to teach you what loops are, or iterations, or, in general, what functions are, or lambdas. You already know that. I’m just going to teach you how you can make the transition to Kotlin.” That’s why I think there’s a lot of information in there for Java developers in a very concise way, so it’ll save them time if they use the book to switch.
16. José, What was your inspiration? What specific gaps or common struggles did you observe among Java developers that made you think, “I need to write this book, and I need to help them”?
José Dimas Luján Castillo: Well, I need to say something at the beginning, because Ron said I started the book early—but yeah, that’s true. But actually, Ron’s part was very important for the project. I was stuck on a couple things, and he read it and he made the right suggestions. I think that was the point to try to move forward, because obviously we have a lot of complex situations to understand.
I wrote a lot of books in the past, but this is the second in English, because it’s not my main language. Obviously, that helps a lot, I think—maybe not for him because he’s very good with English, but for me, because I think that helped a lot for that.
And about the coding: when I start thinking about how I need to solve—or I want to explain—the things I know… I am a teacher too. I was a teacher for 18 years, maybe. And I note, for example, when I try to tell people—like at the beginning, 18 years ago—it’s very easy. It’s not the same case when you have developers with previous experience.
So I take that in my mind, because I know a lot of people want to use Kotlin because they are coming from Java—that’s the part. It’s a different way when you are starting from zero or scratch, but when you have developers with experience, it’s a very different way to do that. So I take that in mind while I was writing the book.
I was thinking too much that the other part is: I need to take time to explain the syntax. But at the end, the problem is the way we try to focus the situation. For example, am I trying to explain how we can write this line of code in Kotlin, or maybe we need to… I think we really need this line of code, because maybe in Kotlin we don’t need it.
That’s what I always try to put in the reader’s mind: if we need it, OK—this is the way to do that. But the question is: do we really need this line? Because maybe in Kotlin we have another way to do that, and maybe we don’t need to use it. That’s my second question always when I try to explain something, because that’s the real way to create the bridge for Java developers to Kotlin.
OK, you will need—maybe you will need that knowledge more; maybe it’s better if you don’t need it. But you know why you have the answer. Or maybe you need to find the answer when you are writing the code. That’s the other part.
The other question—or comment—I always have in my mind is: we need to be respectful with Java. Since the beginning with Kotlin, when we try to sell the idea to use Kotlin, I don’t like too much, actually. I have a very weird experience in the past when I was a Google Developer Expert and I was the third Kotlin Developer Expert, and the problem is: they removed me because I’m not always saying the best option is Kotlin for the developer.
And I really think that, in some cases, maybe you have situations when you don’t see a very specific answer or a good answer for that—but it is the real part. We need to be respectful with Java because, at the beginning, without the experience of Java, we can’t create Kotlin. Not me—the Kotlin team—because obviously they use a lot of experience in Java, all of them. They are very experienced people with Java, and they try to see good parts of Java and take it into Kotlin, and they are increasing good parts.
So if we sell Kotlin as a killer—I think that’s disrespectful for the technology, because it’s not. The way to do that sometimes is actually a compliment for the technologies, the architecture, the projects. But the other part is: more than sometimes it’s just your preference—how you prefer to write the code in this way or this one—because maybe you don’t have very clear architecture or this paradigm to use it.
So that’s the other part. I always, in my way to express it, when you need to compare Java with Kotlin, I always try to be very respectful with that because a lot of the good things in Kotlin—maybe 90% of them—they are coming from Java, because Java is the first part of your experience. So I always try to keep that in mind when I write the book and put the examples. Obviously, we have a lot of parts better in this case, or very fast implementation—I need to say it, obviously—but with the correct words and the correct approach for the people. For me, that’s my line to follow to write the book.
And obviously, I want a couple parts that are really practical. In these cases, I use very simple scenarios and add complexity in the code. I start, maybe, for example, with just one definition, but at the end of the chapter you will see it takes more functions, because that’s the way to follow that. I don’t prefer to do anything by default because when I read books in the past—
You sometimes see magic code just appear on the next page. So I don’t like too much to say, “Hey, we have new code—just read it and move forward,” because I don’t think that’s the way. Obviously, in other kinds of books, on other kinds of technologies, maybe you need to do that because it’s a framework and needs to be—and you can copy the template because it’s too… but even in the necessary parts, I try to do that for the book. That’s my—maybe five or three points to follow when I write the book.
17. What do you hope experienced Java professionals will do differently after reading Kotlin for Java Developers, and how do you think this will help them tackle real-world challenges more effectively?
Ron Veen: Well, I think, again, like we said, this is really trying to explain to Java developers that Kotlin isn’t that different, because, again, 80% of your logic and things will still be the same. Yes, you will use a bit different syntax, but it’s still a syntax that’s quite familiar to you. You might use different collection functions, because there are different ones.
But I think the really important part here is that you’re actually starting to see the value, but you’re also starting to recognize when it doesn’t really matter if we do Java or if we do Kotlin—they’re both running on this brilliant thing, which is the JVM, right? The Java Virtual Machine that, in the end, runs the code.
So it is not as big a step as you might think it is when you move from Java to Kotlin—as opposed to moving from Java to Go, or from Java to Rust. The steps are really small, and I think our book just helps you write idiomatic Kotlin, where you can actually see, “Oh, right—I’m actually seeing what I should do.” And like José said, it’s not like translating it one to one.
Actually, I think JetBrains, in the IDE, they have the function where you can select a Java class and say, “Convert to Kotlin.” Well, it would technically work, but it still wouldn’t be idiomatic Kotlin, right? So I really hope that, with the book in hand, you would actually write Kotlin as Kotlin is meant to be—so I really hope that’s where we’re getting.
If you want to dig deeper into the mechanics of moving from Java to Kotlin—writing idiomatic Kotlin, handling null safety, using coroutines for concurrency, and taking advantage of features like extension functions and DSLs—check out Kotlin for Java Developers by José Dimas Luján Castillo and Ron Veen (Packt, Oct 2025). Written for experienced Java developers, it teaches Kotlin by mapping concepts directly to familiar Java constructs and then goes further into interoperability, generics, data and sealed classes, coroutines and flows, and DSL design—across backend, Android, and cross-platform development.






