<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mariusz Sołtysiak</title>
    <description>The latest articles on DEV Community by Mariusz Sołtysiak (@marrek13).</description>
    <link>https://dev.to/marrek13</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1147302%2Fd5819354-1ded-4433-875d-9029147fc7c6.jpeg</url>
      <title>DEV Community: Mariusz Sołtysiak</title>
      <link>https://dev.to/marrek13</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/marrek13"/>
    <language>en</language>
    <item>
      <title>Decoding the challenge of business urgency and engineering rigor</title>
      <dc:creator>Mariusz Sołtysiak</dc:creator>
      <pubDate>Sun, 03 Dec 2023 08:23:48 +0000</pubDate>
      <link>https://dev.to/marrek13/decoding-the-challenge-of-business-urgency-and-engineering-rigor-892</link>
      <guid>https://dev.to/marrek13/decoding-the-challenge-of-business-urgency-and-engineering-rigor-892</guid>
      <description>&lt;p&gt;Some people say it's impossible. Some people say it's hard. I say it's not easy but achievable. In this article, I'll try to explain my approach to managing the balance between business needs and engineering excellence.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pragmatism in Action&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I consider myself a very pragmatic person. If I don't need something, I discard it. If a task can be done tomorrow, I do it tomorrow to avoid overthinking. When I need to purchase something, I buy it because it's necessary. Similar concepts can be applied to software engineering and working in a team. Let's explore an example situation that has occurred to me multiple times. A product manager once asked me:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Hey Mariusz, I would like to ask you if we could somehow deliver this bug fix/feature faster. You know how important it is for our merchants. We receive a lot of support requests, and it's becoming quite burdensome for our agents to answer all of them."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In such situations, there are multiple possible answers. Let's review each of them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Answer 1: Technical Rigidity&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Sorry, it is not possible. We need more time to deliver good quality code."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In this situation, we don't balance business needs at all. We focus purely on the technical aspect, ignoring the impact on the product and the entire organization, such as the overload of support agents. Generally speaking, I consider this kind of answer to be the least appropriate, as it leads to multiple consequences: lack of trust, being considered not as a team player, and communication issues with the product in the future.&lt;/p&gt;

&lt;p&gt;The only reason to provide this kind of answer would be due to a lack of trust in the product manager, who may have lied to you in the past. In that case, it should be addressed with proper, direct feedback instead of building a toxic relationship.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Answer 2: Blind Acceptance&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Oh sure, no problem, we'll do a workaround quickly and deploy it today."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;While this answer may be better in some scenarios, in my opinion, it's not good enough. We allow the product manager to have full ownership of the technical aspect of the product, making it possible for them to come to us with any request and demand to satisfy it in a very short time. Firstly, we shouldn't accept the request without getting more context - it's dangerous and can lead to consequences such as untested errors in production, immense pressure on the team, and missing pieces of a solution. I also see a danger in the second part of the answer, which is "deploy it today." I would avoid promising anything like this unless the fix changes something straightforward, like changing a button color. What if the fix is not easy to apply to the code that is already in progress toward the proper, clean solution? What if QA finds a critical bug that takes more time? Always think about the consequences of your promises, as it can lead to a lack of trust.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Answer 3: Pragmatic Collaboration&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Can we please talk more about this issue? I'd like to understand more about the urgency and how much time we have to fix the issue. We've already started working on a proper solution without workarounds, and I'd like to avoid doing the workarounds if we can deliver the proper version soon. If we agree to the workaround, I expect you will give us more time to finish the proper solution and remove the workaround later this week/during the next sprint."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This would be my pragmatic answer and usually is. In this answer, we first try to understand the importance of the request because, in many situations, these requests are not estimated enough. Sometimes it is due to pressure from leadership, sometimes due to a lack of experience from the product manager, and sometimes just from not getting all the details from the support.&lt;/p&gt;

&lt;p&gt;After we get more details, we need to estimate the overall impact on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Product&lt;/li&gt;
&lt;li&gt;Team&lt;/li&gt;
&lt;li&gt;Organization&lt;/li&gt;
&lt;li&gt;Code/Infra&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the impact on product/organization is high (i.e., support agents experiencing significant delays in answering questions), we most likely should accept doing the workaround (if possible), especially when delivering the right approach could take a lot of time.&lt;/p&gt;

&lt;p&gt;If the impact on the team is high (i.e., a lot of team members are involved in resolving support requests), we should decide after discussing the possible options with the team members.&lt;/p&gt;

&lt;p&gt;If the impact on code/infra is too high (i.e., would require delivering a completely new component to K8s just to remove it a few days later), we can refuse the request and ask for more time to deliver the right solution.&lt;/p&gt;

&lt;p&gt;The last important part of the answer is agreeing on the fact that the workaround should not stay in the code forever. That's a compromise that should be (almost) always done to avoid the situation where we only do workarounds and quick fixes instead of focusing on the long-term maintainability of the codebase.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Real-life Example: Collaborative Decision-making&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Recently, in my company, we were exploring a new feature that was important for the team and the organization (we received many feature requests from support agents). The team made a discovery and estimated that it would take around a year to deliver the feature. This timeline wasn't acceptable, as the request was urgent. One of the engineers found a workaround and presented it to the team. Because of the increasing number of requests, the team decided to use the workaround, deliver the feature in 3 months, and then work on the proper solution afterward. I think that was an exemplary collaboration between product managers and engineers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion: Learning from Experience&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The entire topic of balancing business needs and engineering excellence is, of course, much bigger, and it's hard to provide an example for every situation that can happen in your team/company. I wrote this article to reflect a bit more on your day-to-day work and see if, perhaps, you're not making my mistakes. When I started my career, I usually answered with the 2nd answer. Later on, when I gained more technical experience, I started to answer with the 1st. Only after several years of changing my roles and teams I realized that the proper answer is the last one.&lt;/p&gt;




&lt;p&gt;Originally published at &lt;a href="https://mariuszsoltysiak.medium.com"&gt;https://mariuszsoltysiak.medium.com&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>softwaredevelopment</category>
      <category>softskills</category>
      <category>pragmatism</category>
    </item>
    <item>
      <title>How Observability Changed My (Developer) Life</title>
      <dc:creator>Mariusz Sołtysiak</dc:creator>
      <pubDate>Mon, 03 Jul 2023 10:00:00 +0000</pubDate>
      <link>https://dev.to/marrek13/how-observability-changed-my-developer-life-47fn</link>
      <guid>https://dev.to/marrek13/how-observability-changed-my-developer-life-47fn</guid>
      <description>&lt;p&gt;Recently I was thinking what was the single most important thing that changed my point of view on programming other than switching from PHP to Kotlin, and that thing is observability. Ill try to share my journey with the concept and provide some experiences and recommendations for anyone who wants to start doing it.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;What is observability?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;There are various definitions of observability found on the Internet, but I would like to provide an analogy to explain my understanding of it.&lt;/p&gt;

&lt;p&gt;Imagine a carrot field with numerous ready-to-be-harvested carrots. As a farmer, your goal is to make a profit by selling these carrots. Therefore, it would be detrimental if the carrots became sick or were stolen. A wise farmer would regularly inspect the condition of the carrots and apply appropriate remedies if any symptoms arise. However, is this approach truly effective? Not quite. It requires significant resources, and the larger the field, the more resources it consumes (in this case, the resource being time).&lt;/p&gt;

&lt;p&gt;Now, envision a scenario where instead of manually checking the condition of each carrot, they could be planted in special pots that automatically report their condition to a central software system. By having constant and ubiquitous information about the condition of the carrots, the farmer would save a considerable amount of time. This is what we mean by monitoring the field.&lt;/p&gt;

&lt;p&gt;As the farm expands, more fields are maintained, and its no longer solely about carrots. The farmer now desires to understand the overall, aggregated condition of all the fields on the farm. Achieving this would be challenging if we focused solely on individual fields, but it becomes effortless if we adopt a top-down approach and consider the entire IT system as a whole. That, to me, is the essence of observability - looking at the entire IT system from a higher-level perspective.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6HlXgTnK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/800/0%2ALjAnzu1sXzli1OlZ" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6HlXgTnK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/800/0%2ALjAnzu1sXzli1OlZ" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Why has it changed my life as a developer?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;A decade ago, I was a farmer with one field, and monitoring was more than enough to maintain a few modular monoliths that I created and worked with. Just having some logs in a text file was enough. Now the systems I work with are much more complex, and it would be extremely bad to have only one monolith. I wouldn't be learning about this without the tremendous help of my coworker, who pushed hard to adapt the concept within our company. My team was the first to play with the new toys, and the best part is that you never get bored playing with them. Every day you can learn and discover new things and ideas on how to play with the spans and traces you collect from your microservices.&lt;/p&gt;

&lt;p&gt;My favorite toy is the &lt;a href="https://opentelemetry.io"&gt;OpenTelemetry framework&lt;/a&gt;. I cant tell you how much I appreciate the work they're doing for the entire IT industry. The integrations are ready or almost ready for the major languages currently used for web/mobile development. Thanks to the traceability, we can capture spans from the user click in the mobile/front-end app to async event processing on a message broker. Doing the same story manually would probably take several hours to find and match the right logs (if they were all stored).&lt;/p&gt;

&lt;p&gt;Of course, collecting the traces wouldn't be enough, and we need a tool to help us understand the RAW data. We decided to use &lt;a href="http://HoneyComb.io"&gt;HoneyComb.io&lt;/a&gt; and its the last toy that changed my life as a developer. Having the ability to query any field in the range without having to prepare special indexes is awesome. It allows you to build very complex queries and execute them quickly. It saves many hours of debugging and usually helps to identify the broken microservice in just a few minutes.&lt;/p&gt;

&lt;p&gt;Having all the toys together has drastically reduced the resolution time for any production issue in my company. Ive gotten so used to having the right observability setup that it would be very hard to take it off my production readiness list.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Do I need to adapt the concept to my team/company?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;As usual - it depends. If your company is a small business built on a service architecture that rarely communicates with each other, the benefits are probably not that great. The tools can still help you build proper SLIs/SLOs and set up alerting on top of them, which in my opinion works much better than based on pure metrics.&lt;/p&gt;

&lt;p&gt;If you are running multiple microservices that communicate with each other, even if they are written in different languages, observability is a way to go. The only downside is that you should work on adding the OpenTelemetry APIs/agents to all of them to not miss any spans in your traces. It is best to start with non-critical, preferably a standalone service, and then systematically add integration to more critical services. This approach can help you avoid unnecessary production disruptions while you learn how to work with the new tools.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Okay, so this all sounds great, but what are the downsides?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The tools like &lt;a href="http://HoneyComb.io"&gt;HoneyComb.io&lt;/a&gt; can get expensive if you have a lot of traffic. Putting all traces directly into the API is probably not the best idea. To reduce the volume, you'll need to introduce sampling. This can be done in several ways, such as using an &lt;a href="https://opentelemetry.io/docs/collector/"&gt;OpenTelemetry collector&lt;/a&gt; and/or &lt;a href="https://docs.honeycomb.io/manage-data-volume/refinery/"&gt;HoneyComb Refinery&lt;/a&gt;. You can define sampling rules and ratios to focus on the important traces and drop those that are irrelevant or redundant. For example, you can apply a 0% sample ratio to any HTTP response with status &amp;gt;=400, while applying an 80% sample ratio to everything else. With this setup, you can still identify the errors and track the problematic samples without losing much context from the successful traffic. For some small integrations, it may be sufficient to use &lt;a href="https://opentelemetry.io/docs/concepts/sampling/#language-sdks"&gt;sampling within SDKs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Another fairly obvious drawback is the increased complexity of the architecture. You have to use several external libraries that need to be maintained. You may need to integrate the collector/refinery into your infrastructure and maintain it like any other microservice. Especially at the beginning of the journey, you may face several issues that need your attention.&lt;/p&gt;

&lt;p&gt;You also need to be careful, as with logging, not to expose sensitive data within the traces. Writing proper rules within the services or collector is a must.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Observability may be a success indicator&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EAO7oPn9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/800/0%2AbqTOuYMYVymfm2UH" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EAO7oPn9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/800/0%2AbqTOuYMYVymfm2UH" width="800" height="464"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Observability is a critical concept in modern systems engineering and software development that focuses on gaining insight into complex, distributed systems. It goes beyond traditional monitoring approaches by emphasizing the ability to understand and reason about systems internal states and behaviors from the outside. By employing a combination of monitoring, logging, tracing, and metrics, observability enables engineers to gain a holistic understanding of system performance, identify and troubleshoot issues, and make informed decisions to improve system reliability, efficiency, and user experience. In todays increasingly interconnected and dynamic technological landscape, observability plays a vital role in enabling organizations to build and maintain robust, scalable, and resilient systems. If your company is struggling to resolve production issues quickly, or if its hard for your teams to find them in the first place, give it a try and improve customer satisfaction for good.&lt;/p&gt;

</description>
      <category>observability</category>
      <category>devops</category>
      <category>metrics</category>
      <category>devrel</category>
    </item>
    <item>
      <title>API Versioning with Kotlin and Spring Boot</title>
      <dc:creator>Mariusz Sołtysiak</dc:creator>
      <pubDate>Sat, 08 Oct 2022 10:00:00 +0000</pubDate>
      <link>https://dev.to/marrek13/api-versioning-with-kotlin-and-spring-boot-42hd</link>
      <guid>https://dev.to/marrek13/api-versioning-with-kotlin-and-spring-boot-42hd</guid>
      <description>&lt;p&gt;I wrote a short poem that explains the need for API versioning:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;There was an API&lt;br&gt;
And it was good&lt;br&gt;
Then PM came&lt;br&gt;
And said you should&lt;br&gt;
Change the field&lt;br&gt;
From array to string&lt;br&gt;
How can I do it?&lt;br&gt;
This is BC!&lt;br&gt;
And there it comes&lt;br&gt;
The magical V&lt;br&gt;
V like a version&lt;br&gt;
Of your API&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Lets get into the details!&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Why and when to version an API?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;I believe almost everyone once asked themselves the question Should I version the API I created?. Almost like always, theres no single answer. However, if you already thought about it, it might be a good idea to pay attention to the problem before it becomes a real production issue.&lt;/p&gt;

&lt;p&gt;From my experience, all the APIs that work directly with the client (mobile apps, web applications) should be versioned. Imagine that you want to perform a breaking change like in the poem: the API supports multiple categories per item, but customers don't like it for some reason. The business comes and asks you to change the API so it always accepts only a single category. If you change the API in place you'll break all the clients that already use the current solution. For the web application there could probably be a short time while it stops working (for the time of deployment), but how can you force the users to upgrade all the mobile apps at once?&lt;/p&gt;

&lt;p&gt;On the other hand, if your API is internal you might not need full API versioning. Sometimes it'll be easier to introduce a copy-paste endpoint, switch the usage on the clients side, and then remove the old one. This approach requires you to know exactly how many clients the API has and align with all the consumers beforehand.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;How to version the API?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;There are several approaches to API versioning that can be used. I believe the most common are described below.&lt;/p&gt;

&lt;h4&gt;
  
  
  Versioning via URL path param
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="http://api.example.com/v1/items"&gt;http://api.example.com/v1/items&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The idea is to introduce the API version as a part of the path for each request coming to your API. The main issue with this solution is that for each new version of the APIs you need to modify your API specification for all endpoints to change the URL. I believe it can be pretty messy in the long run.&lt;/p&gt;

&lt;h4&gt;
  
  
  Versioning via URL query param
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="http://api.example/com/items?version=1"&gt;http://api.example/com/items?version=1&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The approach is similar, but this time your application will need to parse and look for specific query path parameters for each request coming to the application. It might not be a big issue on the server side, but from the mobile/frontend side it might be a bit tricky to implement this solution, especially if there are endpoints that already use the query params to fetch data (like pagination). Usually, the clients use some kind of generator to not write all the code manually, and those will not support this kind of versioning without additional effort.&lt;/p&gt;

&lt;h4&gt;
  
  
  Versioning by extending the Accept header content
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;Accept: text/json; version=1&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This idea is about appending a version string to the existing Accepts header. I don't personally like this solution for similar reasons as with the URL query param. I believe that it might not be so straightforward on the client side to modify the Accept header for each request - they are usually automatically populated by the HTTP client based on the passed content type.&lt;/p&gt;

&lt;h4&gt;
  
  
  Versioning through the custom header
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;Accept-Version: 1.0&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The idea is to add a custom header to every request. This is in my opinion the best and clearest approach that Ill show you how to implement in the Spring Boot application.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Versioning through the custom headerSpring Boot configuration&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;To achieve the goal we need to add several small classes to the project, that will allow us to easily define the same endpoints across different controllers (or even the same) being identified by the custom annotation were going to create.&lt;/p&gt;

&lt;p&gt;First of all, we need to define the custom annotation and enum with supported API versions:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gist.github.com/marrek13/23f5026f210e7dbdff8a318ce8f3beec"&gt;https://gist.github.com/marrek13/23f5026f210e7dbdff8a318ce8f3beec&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then we need to write ApiVersionCondition class that implements the Spring RequestCondition interface. It requires implementing 3 methods:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;combine&lt;/strong&gt; defines the rules of overriding the annotations between classes and methods. In this case method annotations takes precedence over class annotations.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;getMatchingCondition&lt;/strong&gt; is responsible for reading the API version from the request and comparing it with the API version set in the annotation. We also fall back to version 1.0.0 if the request doesn't contain the Accept-version header. Another possibility is to always require the header and return null when its not present.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;compareTo&lt;/strong&gt; is used to define version order. In our case, its an enum so its compareTo method is used.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://gist.github.com/marrek13/89fc75d0cb2323b7ca0c9b3d8a91bafd"&gt;https://gist.github.com/marrek13/89fc75d0cb2323b7ca0c9b3d8a91bafd&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The next step is to extend the Spring RequestMappingHandlerMapping class that will tell spring how to create the ApiVersionCondition for classes and methods. This time we need to override 2 methods:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;getCustomMethodCondition&lt;/strong&gt; defines how to create the ApiVersionCondition from a Method&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;getCustomTypeCondition&lt;/strong&gt; defines how to create the ApiVersionCondition from a Class&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://gist.github.com/marrek13/431ef4041730ddb985920baf154e3117"&gt;https://gist.github.com/marrek13/431ef4041730ddb985920baf154e3117&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And the last step before we can start using the annotation in the controllers is to add the new RequestMappingHandlerMapping class to the Spring Boot Configuration&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gist.github.com/marrek13/a446cc08a4f99d991079a57d47dd4162"&gt;https://gist.github.com/marrek13/a446cc08a4f99d991079a57d47dd4162&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Using the new annotation in controllers&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Lets create 3 classes for testing purposes. We have 1 API interface and 2 implementations for different API versions. We create the 1.0.0 version annotation on the V1 controller and the 2.0.0 annotation on the V2 controller with the 2.1.0 annotation of one of its methods.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Color API interface&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gist.github.com/marrek13/2722506542a473133ad10a4ba3d3f6c7"&gt;https://gist.github.com/marrek13/2722506542a473133ad10a4ba3d3f6c7&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;V1.0.0 controller&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gist.github.com/marrek13/1820bb97ac58fe4efaf8d5e880bb59bd"&gt;https://gist.github.com/marrek13/1820bb97ac58fe4efaf8d5e880bb59bd&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;V2.0.0 controller with one V2.1.0 method&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gist.github.com/marrek13/aac7dc877c83dd6840b969d4ab1a4788"&gt;https://gist.github.com/marrek13/aac7dc877c83dd6840b969d4ab1a4788&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Results for different curl calls
&lt;/h3&gt;

&lt;p&gt;Calling list endpoint without version header or with 1.0.0 version returns the V1.0.0 controller response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl --location --request GET 'http://localhost:8080/colors'
curl --location --request GET 'http://localhost:8080/colors' --header 'Accept-version: 1.0.0'


Response:
[
    {
        "tag": "V1.0.0 list color",
        "hex": "#FF0000"
    }
]

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Calling list endpoint with 2.0.0 or 2.1.0 version header returns V2.0.0 controller response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl --location --request GET 'http://localhost:8484/colors' --header 'Accept-version: 2.0.0'
curl --location --request GET 'http://localhost:8484/colors' --header 'Accept-version: 2.1.0'


Response:
{
    "colors": [
        {
            "tag": "V2.0.0 list color",
            "hex": "#f0f0f0"
        }
    ]
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Calling single item endpoint without version header or with 1.0.0/2.0.0 returns V1.0.0 controller value:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl --location --request GET 'http://localhost:8484/color'
curl --location --request GET 'http://localhost:8484/color' --header 'Accept-version: 1.0.0'
curl --location --request GET 'http://localhost:8484/color' --header 'Accept-version: 2.0.0'


Response:
{
    "tag": "V1.0.0 single color",
    "hex": "#FF0000"
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally calling single item endpoint with 2.1.0 version header returns V2.1.0 controller method value&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl --location --request GET 'http://localhost:8484/color' --header 'Accept-version: 2.1.0'


Response:
{
    "tag": "V2.1.0 single color",
    "hex": "#f0f0f0"
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Performance impact
&lt;/h3&gt;

&lt;p&gt;Last thing to check is the impact on application performance. For that purpose I used Apache Benchmark. I ran a test that calls the endpoint 10000 times with no concurrent users:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ab -n 100000 -c 1 -H "Accept-version: 2.0.0" http://localhost:8484/colors

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first test I ran with the &lt;strong&gt;@ApiVersion&lt;/strong&gt; annotation processor &lt;strong&gt;enabled&lt;/strong&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Concurrency Level: 1
Time taken for tests: 95.117 seconds
Complete requests: 100000
Failed requests: 0
Total transferred: 16800000 bytes
HTML transferred: 4000000 bytes
Requests per second: 1051.33 [#/sec] (mean)
Time per request: 0.951 [ms] (mean)
Time per request: 0.951 [ms] (mean, across all concurrent requests)
Transfer rate: 172.48 [Kbytes/sec] received

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then I removed all the configs and annotations we created and I left only one controller which I tested with the same command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Concurrency Level: 1
Time taken for tests: 82.624 seconds
Complete requests: 100000
Failed requests: 0
Total transferred: 16800000 bytes
HTML transferred: 4000000 bytes
Requests per second: 1210.30 [#/sec] (mean)
Time per request: 0.826 [ms] (mean)
Time per request: 0.826 [ms] (mean, across all concurrent requests)
Transfer rate: 198.57 [Kbytes/sec] received

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result is that the annotation processor has some impact on the requests but the mean impact per request is only 1/8 ms. I think this is acceptable value and will matter only in performance-critical environments.&lt;/p&gt;




&lt;p&gt;I hope this will help you to manage the API versions in your code easier and will make your code architecture cleaner. Happy to hear any feedback from you!&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>springboot</category>
      <category>api</category>
      <category>apiversioning</category>
    </item>
    <item>
      <title>Should you try Kotlin as a PHP developer?</title>
      <dc:creator>Mariusz Sołtysiak</dc:creator>
      <pubDate>Mon, 25 Apr 2022 10:00:00 +0000</pubDate>
      <link>https://dev.to/marrek13/should-you-try-kotlin-as-a-php-developer-543l</link>
      <guid>https://dev.to/marrek13/should-you-try-kotlin-as-a-php-developer-543l</guid>
      <description>&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is PHP a bad language?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;The main issues for me with PHP were not the code style and code structures, these things are pretty much similar now:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://php.watch/versions/8.1/never-return-type"&gt;never return type in PHP&lt;/a&gt; -&amp;gt; &lt;a href="https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-nothing.html"&gt;Nothing in Kotlin&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.php.net/manual/en/language.types.enumerations.php"&gt;enums&lt;/a&gt; = &lt;a href="https://kotlinlang.org/docs/enum-classes.html"&gt;enums&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/brendt/constructor-property-promotion-in-php-8-5003-temp-slug-2059342"&gt;promoted constructor properties&lt;/a&gt; -&amp;gt; &lt;a href="https://kotlinlang.org/docs/classes.html#constructors"&gt;primary constructor properties&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/brendt/php-8-the-nullsafe-operator-1hak-temp-slug-6139993"&gt;null safe operator&lt;/a&gt; = &lt;a href="https://kotlinlang.org/docs/null-safety.html#safe-calls"&gt;null safe operator&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://php.watch/versions/8.0/match-expression"&gt;match expression&lt;/a&gt; -&amp;gt; &lt;a href="https://kotlinlang.org/docs/control-flow.html#when-expression"&gt;when expression&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;&lt;strong&gt;Concise syntax&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gist.github.com/marrek13/2b48d9efc966bdd03324901e895abbc3"&gt;https://gist.github.com/marrek13/2b48d9efc966bdd03324901e895abbc3&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, lets compare it with the code in Kotlin and make your judgment on which is more readable.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gist.github.com/marrek13/58b213a1542a356e3a177f4a70fc49f4"&gt;https://gist.github.com/marrek13/58b213a1542a356e3a177f4a70fc49f4&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Kotlin/JVM also supports things unavailable in PHP, like &lt;a href="https://kotlinlang.org/docs/generics.html"&gt;generics&lt;/a&gt; and &lt;a href="https://kotlinlang.org/docs/extensions.html"&gt;extensions&lt;/a&gt;. Both are very useful and can make the code very clean and reusable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Differences in functional composition&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Lets first take a look at the fold function written in PHP and Kotlin&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gist.github.com/marrek13/3780b947153526aa0c5a63bbb6981293"&gt;https://gist.github.com/marrek13/3780b947153526aa0c5a63bbb6981293&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gist.github.com/marrek13/f57b1b526efe886a911d7e68b327a59a"&gt;https://gist.github.com/marrek13/f57b1b526efe886a911d7e68b327a59a&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Multi-module projects&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Performance&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Kotlin offers easy achievable async request handling by using &lt;a href="https://kotlinlang.org/docs/coroutines-overview.html"&gt;coroutines&lt;/a&gt;. 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.&lt;/p&gt;

&lt;p&gt;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 &lt;a href="https://blogs.oracle.com/javamagazine/post/pedal-to-the-metal-high-performance-java-with-graalvm-native-image"&gt;brings huge benefits&lt;/a&gt;. Also, Spring is working on official support for GraalVM &lt;a href="https://docs.spring.io/spring-native/docs/current/reference/htmlsingle/"&gt;Spring Native&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Official libraries availability&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Communication protocols support&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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 &lt;a href="https://www.redhat.com/en/blog/comparing-openapi-grpc"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Message brokers support&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;What I miss from PHP is the &lt;a href="https://symfony.com/doc/current/messenger.html"&gt;Symfony Messenger&lt;/a&gt; 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.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Creating separated modules/libraries&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;PHP has Composer, JVM has Maven/Gradle. Creating and managing a library in composer &lt;a href="https://medium.com/@mazraara/create-a-composer-package-and-publish-3683596dec45"&gt;is not so straightforward&lt;/a&gt;. I consider it much easier in the JVM world, especially when using &lt;a href="https://github.com/features/actions"&gt;GitHub Actions&lt;/a&gt; with &lt;a href="https://github.com/features/packages"&gt;GitHub Packages&lt;/a&gt;. All you need to do is to use one step in the workflow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gist.github.com/marrek13/4d5f01f769083c251626620295b66f8a"&gt;https://gist.github.com/marrek13/4d5f01f769083c251626620295b66f8a&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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 &lt;code&gt;composer update&lt;/code&gt; action every time you change something.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Observability&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In my job, we put a lot of effort into &lt;a href="https://www.honeycomb.io/blog/observability-a-manifesto/"&gt;observability&lt;/a&gt;. 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.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;IDE/debugging support&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;For the PHP XDebug extension, there is a &lt;a href="https://www.jetbrains.com/help/phpstorm/configuring-xdebug.html"&gt;full article with all the steps&lt;/a&gt; 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.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Multiplatform code&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A great strength of Kotlin is Kotlin Multiplatform.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;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. (&lt;a href="https://kotlinlang.org/docs/multiplatform.html"&gt;https://kotlinlang.org/docs/multiplatform.html&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In my company, several libraries are used on both mobile platforms. There is no substitute in the PHP world.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Frameworks/libraries support&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;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?&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Should you try Kotlin as a PHP developer?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;So whats my general answer to the question? I think it depends.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;If things above are not scaring you, you're good to go. I highly recommend starting from &lt;a href="https://hyperskill.org/tracks/18"&gt;JetBrains Academy Kotlin Basics Course&lt;/a&gt;. 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.&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>php</category>
      <category>programminglanguages</category>
      <category>career</category>
    </item>
    <item>
      <title>Things I learned as a software engineer — career development</title>
      <dc:creator>Mariusz Sołtysiak</dc:creator>
      <pubDate>Fri, 25 Mar 2022 11:00:00 +0000</pubDate>
      <link>https://dev.to/marrek13/things-i-learned-as-a-software-engineer-career-development-5ak0</link>
      <guid>https://dev.to/marrek13/things-i-learned-as-a-software-engineer-career-development-5ak0</guid>
      <description>&lt;p&gt;In my &lt;a href="https://dev.to/marrek13/things-i-learned-as-a-software-engineer-2348-temp-slug-7452182"&gt;previous story&lt;/a&gt;, I was focused more on my experience from the early stages of my career. Now Id like to continue sharing the things I learned as a software engineer(and partially as a team leader) around setting career goals and managing self-development.&lt;/p&gt;

&lt;p&gt;After acquiring our company, our team started to grow, and after almost three years, I got an offer to become a team leader of four backend engineers. I had no experience managing a team, and here it was even harder, as only a part of the team was working directly with me. Others were working as part of other project teams. But I wanted to become a good leader.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prepare for changes&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I started reading books and listening to podcasts. I watched many videos and attended a few conferences to obtain more knowledge about leadership in general. The only problem is that everything happened just too late. I mentioned during my interview that I want to become a leader, but I never expected it really could happen. I didn't do enough on time to prepare myself and have a good starting point. Now I know how important is to prepare for changes. Thats why I decided to write this story.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Create a good development plan&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WFIt14nG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/800/0%2A142nqyDNKlPAlhSt" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WFIt14nG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/800/0%2A142nqyDNKlPAlhSt" width="800" height="532"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You need a clear development plan to follow to achieve the goals and satisfy the expectations. Its not an easy task to do, and usually, you should ask your leader for help. A good development plan should follow three basic rules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;have short and long-term goals&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;focus on 23 specific areas&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;have clear actions for every area they should be measurable and checked periodically&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If those points are satisfied, its probably enough to have something to continue the work. I strongly believe that the first version of the plan should be created individually.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to find areas to develop/improve?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Fortunately, there are some possible solutions. First of all, &lt;strong&gt;you should ask your colleagues and your leader(s) for feedback&lt;/strong&gt;. Because you want to focus on identifying development areas you should ask a few questions that will help them to provide you with ideas. Here are some examples of questions that could be used(all of them I asked and I received meaningful responses):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;What do you think are my areas to grow?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What things do you appreciate most when working with me?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What should I start doing?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What do you think should be my next step in my career progression, and what gaps do I have before I can make it?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Which hard skills should I work on the most?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In your opinion what responsibilities [in the company/team context] should I have that I don't have at the moment?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What strengths have you noticed that you think I should develop?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After you write down your questions, very important is to &lt;strong&gt;pick the correct people to send the feedback request&lt;/strong&gt;. You most likely wont receive a meaningful answer about hard skills from the product manager. Although, if you see that you are missing some skills around communication with business, the product manager might be the best choice.&lt;/p&gt;

&lt;p&gt;The last step is to analyze the results. The answers might not be so specific, but anyway you should try to identify something to develop. You should also &lt;strong&gt;keep in mind your personal career goals&lt;/strong&gt; and try to pick these points that could move you in the right direction. I personally always tried to pick up something that I could work on during my everyday work and current project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ask your leader for a review&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When you have created your development plan you should ask your leader for a 1:1 meeting to discuss it. Your leader also should have the possibility to read feedback answers. Altogether you should agree and set a time range for each of the actions inside all areas. You should also agree on how often you will update and review the progress.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kK8TdJg9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/800/0%2AhfRgA1U6vhBGJAbM" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kK8TdJg9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/800/0%2AhfRgA1U6vhBGJAbM" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Having everything written down and agreed you just need to do. Isn't it simple?&lt;/p&gt;

&lt;p&gt;Unfortunately, its never easy. Being systematic is very important here. You don't need to do everything at once. If you have agreed to a quarter, don't try to finish everything in a week - especially the last week of the quarter.&lt;/p&gt;

&lt;p&gt;If one of your actions is to read a book about microservices architecture, try to divide it into chapters and read one chapter every day. If your goal is to create a presentation and make a public speech, create a few slides every day, then spend 30 minutes daily to say it aloud until you be ready.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check progress&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Periodically you should update the progress about your actions and talk to your leader about challenges and learnings. Sometimes it might happen, that because of changes in the company/team some of the actions will not be possible to realize. You should be flexible about it and replace them with something else. When necessary, you can replace also an area.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Don't give up&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mBNjXj88--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/800/0%2AhFMx09SEH-2Zfrxv" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mBNjXj88--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/800/0%2AhFMx09SEH-2Zfrxv" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Remember that if you want to progress your goals should be ambitious. There is always a risk of failure, but you should never give up. If you fail to do something or wont meet the deadline, always try to make a retrospective with yourself and your leader. Try to write down why and what could you do to avoid it. Learning from failures can bring more benefits than you can imagine.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;More things are important during career development, but you should identify them on your own and adapt to your needs. I wanted to share the most important factors that I try to follow. I consider them very effective and helpful to progress.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>career</category>
      <category>development</category>
      <category>learning</category>
      <category>growth</category>
    </item>
    <item>
      <title>Error handling in Retrofit using NetworkResponseAdapter library</title>
      <dc:creator>Mariusz Sołtysiak</dc:creator>
      <pubDate>Sun, 16 Jan 2022 11:00:00 +0000</pubDate>
      <link>https://dev.to/marrek13/error-handling-in-retrofit-using-networkresponseadapter-library-412a</link>
      <guid>https://dev.to/marrek13/error-handling-in-retrofit-using-networkresponseadapter-library-412a</guid>
      <description>&lt;p&gt;Im currently working with my team on a new project. One part of it is a gateway service that distributes calls between microservices and/or merges results. We've been looking for a good solution to properly make requests using coroutines. Another requirement was to handle properly responses from the API and that we wont need to handle manually all common error results or IO exceptions.&lt;/p&gt;

&lt;p&gt;After looking for some options we found out Retrofit to be the perfect fit for our purpose. But it wasn't easy to find a proper solution to handle successful and failed responses. Id like to give you a simple example of how to configure Retrofit using the &lt;a href="https://github.com/haroldadmin/NetworkResponseAdapter"&gt;NetworkResponseAdapter&lt;/a&gt; library to properly and gracefully handle responses in your code with a simple extension function.&lt;/p&gt;

&lt;p&gt;Lets define a simple Retrofit client interface with one method to get a list of categories:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gist.github.com/marrek13/f35fdd24eb18ecee90826f92b76c53da"&gt;https://gist.github.com/marrek13/f35fdd24eb18ecee90826f92b76c53da&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The problem with this definition is that when there is an exception we will expose the network exception directly to our application layer. It is not a great solution and its better to throw instead some contextual exception connected with what the client is doing. To achieve this goal we defined our own exception:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gist.github.com/marrek13/e1405c25fe6ee70aa1afa380cbd70004"&gt;https://gist.github.com/marrek13/e1405c25fe6ee70aa1afa380cbd70004&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We added one line to the Retrofit builder&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.addCallAdapterFactory(NetworkResponseAdapterFactory())

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then the client was modified to use NetworkResponseAdapter:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gist.github.com/marrek13/fc3cc307bb8441c7e575c789e0b744c7"&gt;https://gist.github.com/marrek13/fc3cc307bb8441c7e575c789e0b744c7&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;NetworkResponse is a sealed class whose result can be one of the classes below:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;NetworkResponse.Success&lt;/strong&gt; : an object containing the successful result with response data for any 2XX response&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;NetworkResponse.ServerError&lt;/strong&gt; : an object which contains the response from the call that resulted in a non-2XX status&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;NetworkResponse.NetworkError&lt;/strong&gt; : the result of a request that didn't result in a response&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;NetworkResponse.UnknownError&lt;/strong&gt; : the result of a request that resulted in an error different from an IO or Server error&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;NetworkResponse.Error&lt;/strong&gt; : object for any other possible response not covered by any of previous cases&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As you noticed we need to provide the type arguments for deserialization: first for the Success response and the second for the ServerError response.&lt;/p&gt;

&lt;p&gt;To achieve the goal which is easy handling of all exceptions/errors in the same manner we introduced an extension function to the NetworkResponse class:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gist.github.com/marrek13/467be212bd60c38b8883f65cca58b0b9"&gt;https://gist.github.com/marrek13/467be212bd60c38b8883f65cca58b0b9&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Having all of this together, we can easily call our API in the service without being worried about leaking the IOExceptions from the Retrofit client:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gist.github.com/marrek13/506fd4ed9d881a9ce9aab15db7a6f83f"&gt;https://gist.github.com/marrek13/506fd4ed9d881a9ce9aab15db7a6f83f&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And thats it. Adding the call() to all places where the client is used is the only downside of this solution. But in general, we consider it as the most elegant and easy-to-read and test solution.&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>retrofit</category>
      <category>errors</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Things I learned as a software engineer</title>
      <dc:creator>Mariusz Sołtysiak</dc:creator>
      <pubDate>Thu, 06 Jan 2022 11:00:00 +0000</pubDate>
      <link>https://dev.to/marrek13/things-i-learned-as-a-software-engineer-k09</link>
      <guid>https://dev.to/marrek13/things-i-learned-as-a-software-engineer-k09</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--n_g5Cc8l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://miro.medium.com/v2/format:webp/1%2AbeKWBs2D-DaNWPhNifffcg.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--n_g5Cc8l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://miro.medium.com/v2/format:webp/1%2AbeKWBs2D-DaNWPhNifffcg.jpeg" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I started working as a full-stack software engineer when I was 15 years old. The first few projects I found by contacting people in internet radio forums. That brought me some really good money. Sometimes as I child, I was earning more than my parents. When I started my studies I officially joined a small 3-person company and worked mostly as a PHP developer, but also when necessary I was doing the front-end part. That was pretty challenging, especially at the beginning of my professional journey.&lt;/p&gt;

&lt;p&gt;Some people ask me if its too early or too late to become a software engineer. My answer for both is a strong NO. It is never too early or too late to develop software. The only thing that you need is strong motivation and striving to achieve the goal.&lt;/p&gt;

&lt;h3&gt;
  
  
  Being close to software users
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--14jnCZQR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/800/1%2An81yaA3rd3jnj3kh7OQB3w.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--14jnCZQR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/800/1%2An81yaA3rd3jnj3kh7OQB3w.jpeg" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The coolest thing I experienced in my first job was on-site work along with orthodontic technicians, trying to improve the system used by them for tracking the work. I recommend to everyone to do it at least once in their life, to work directly with people who are using the product. It taught me that being close to software users is a critical aspect of making the software successful and well fit to the market needs. Would you think why the buttons in this software needed to be big and the colors dark? Because technicians hands were ofter dirty after doing the appliances and covered with white powder. Without seeing it I probably would never consider this requirement.&lt;/p&gt;

&lt;h3&gt;
  
  
  Traveling back in time
&lt;/h3&gt;

&lt;p&gt;After 7 years I realized that I needed something new and I started looking for another job. At the same moment, I decided to focus fully on the back-end and forget about the front-end stuff. That was my first decision which led me to be happier about what Im doing and made me who am I now. Do I regret being in one company for 7 years? No. It allowed me to have experience in a way that is usually not possible for bigger companies and to be independent in almost every situation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--n_hoB_J_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/800/1%2AudUqDCUoJdRsGG79QQ-9fw.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--n_hoB_J_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/800/1%2AudUqDCUoJdRsGG79QQ-9fw.jpeg" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I was scared to death when I switched companies. Completely different, with a bigger team, working in Agile, more work around the product, designs, and maintenance. It was a challenging time for me. But I promised myself that I would do everything to satisfy the expectations. I was spending long after-hours reading books, watching tutorials, and just doing projects to understand and get up-to-date with the modern world. I felt like this 15-year-old child again.&lt;/p&gt;

&lt;h3&gt;
  
  
  Importance of changes
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7bDw19FC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/800/1%2AeM78jTYXzFDz8KrRBUe86Q.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7bDw19FC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/800/1%2AeM78jTYXzFDz8KrRBUe86Q.jpeg" width="800" height="532"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This experience taught me that changes are important and necessary and its me who is responsible for looking for them. Some may think that Im suggesting changing companies often is a good idea, but Im actually against it. If you find a good company you don't need to change it. A good company supports you with finding new opportunities and challenges whenever you feel that you need to try something else. Fortunately, I managed to find the company which was Shoplo, and now it is SumUp. Sometimes I say that I changed the company without really changing the company, and not only twice but multiple times already.&lt;/p&gt;

&lt;p&gt;From my experience, I can only tell that you should never be afraid to say, that you need a change. If you'll be waiting for someone to notice that something is not all right usually its too late. You are the driver of your career, nobody will tell you that you should change the team, tech stack, or company. Here I can recommend doing the &lt;a href="https://www.gallup.com/cliftonstrengths/en/home.aspx"&gt;CliftonStrengths&lt;/a&gt; test for yourself to see what are your strengths. It helped me a lot with making decisions about my career.&lt;/p&gt;

&lt;h3&gt;
  
  
  Find and praise a good boss
&lt;/h3&gt;

&lt;p&gt;Before my company was acquired we were quite a small developers team (on average around 10 people). It was a time when all of us were discovering new things and new technologies. Thankfully we had full support for that by our CTO, so we could learn together as a team. Back then I made really good progress in being a better back-end engineer. It would not have happened without the support of my boss and the team, where people all were hungry to learn new things together. Our motivation was at the highest possible levels so the progress was too.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AIhPjh7l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/800/1%2AqktTtOP3WQfbNbZFMs9JBA.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AIhPjh7l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/800/1%2AqktTtOP3WQfbNbZFMs9JBA.jpeg" width="800" height="539"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here I would like to underline how important is to have a boss that supports the team with development. Making a product is something important, but if it is not followed by good technical decisions the team is never going to be happy and performant. If you feel like your boss is not challenging you or instead even is forcing you to use specific technologies, its time for a change. Software engineers are good only when they constantly develop. Having no field to develop means you are not staying at the current level of knowledge. The world is going on, but you're not. In a few months, you'll start to be weaker.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Id like at first to thank you for reading my first article. For a purpose, Im finishing here, because Id like to hear your feedback about the article and about the things I mentioned before continuing my story. Looking forward to hearing from you!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>softwaredevelopment</category>
      <category>softwareengineering</category>
      <category>backend</category>
      <category>experience</category>
    </item>
  </channel>
</rss>
