<?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: ottonova</title>
    <description>The latest articles on DEV Community by ottonova (@ottonova).</description>
    <link>https://dev.to/ottonova</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%2Forganization%2Fprofile_image%2F827%2F5b1c9085-ae9f-4a27-bddb-cec748244099.png</url>
      <title>DEV Community: ottonova</title>
      <link>https://dev.to/ottonova</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ottonova"/>
    <language>en</language>
    <item>
      <title>How We Transformed Our Daily Meetings for the Better</title>
      <dc:creator>Sergey Podgorny</dc:creator>
      <pubDate>Mon, 13 Nov 2023 10:00:17 +0000</pubDate>
      <link>https://dev.to/ottonova/how-we-transformed-our-daily-meetings-for-the-better-18ie</link>
      <guid>https://dev.to/ottonova/how-we-transformed-our-daily-meetings-for-the-better-18ie</guid>
      <description>&lt;p&gt;In the world of teamwork, our daily stand-ups play a crucial role in our collective success.  We wanted to make things more efficient, and that's when we found something awesome in the videos from "&lt;a href="https://www.developmentthatpays.com/" rel="noopener noreferrer"&gt;Development That Pays&lt;/a&gt;": Walking the Board.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Problem
&lt;/h3&gt;

&lt;p&gt;We've all been there: the endless cycle of daily stand-ups where the team updates on what they did yesterday, what they're working on today, and any blockers they're facing.&lt;/p&gt;

&lt;p&gt;While it seems like a straightforward approach, it has its drawbacks. The individual spotlight often overshadows the collaborative nature of the team event, with team members more focused on crafting their own stories than actively listening to others. This realization prompted us to seek a more effective alternative.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Discovery
&lt;/h3&gt;

&lt;p&gt;While browsing YouTube, I discovered "Development That Pays". It proved to be a goldmine of helpful videos. Two videos, in particular, caught my attention: &lt;em&gt;Daily Stand-up: You're Doing It Wrong!&lt;/em&gt; and &lt;em&gt;Agile Daily Standup - How To Walk the Board (aka Walk the Wall)&lt;/em&gt;. These videos challenged our traditional approach and introduced an alternative — Walking the Board.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/H02BlTXpcto"&gt;
&lt;/iframe&gt;
&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/316qdj10j9M"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  The "Walking the Board" Concept
&lt;/h3&gt;

&lt;p&gt;Walking the Board, also known as Walking the Wall, offered a refreshing perspective. Instead of individual updates, the team starts with the ticket on the top right of the board. The team member assigned to that ticket provides an update, and we move on to the next ticket. This method shifts the focus from individuals to the work itself and changes the stand-up from a chain of individual updates to a &lt;em&gt;&lt;strong&gt;team event&lt;/strong&gt;&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;This approach transforms the stand-up into a collaborative journey across the board, ensuring that the spotlight remains on the work itself, not on individual narratives. No more struggling to come up with a good story, the cards on the board provide the agenda. It's a game-changer that keeps everyone focused on the work. It's a shift from "&lt;em&gt;What did I do?&lt;/em&gt;" to "&lt;em&gt;What is the status of the work on the board?&lt;/em&gt;"&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7aiub4fjr67uc80r8o3u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7aiub4fjr67uc80r8o3u.png" alt="Board overview" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  How To Walk the Board
&lt;/h3&gt;

&lt;p&gt;Starting at the top right of the board makes &lt;em&gt;financial sense&lt;/em&gt; — the items closest to being live are discussed first. If you're familiar with the concept of net present value, you'll understand that income now is more valuable than income later, and income tomorrow is more valuable than income next week.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffmkgopn3c0b39mio3mam.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffmkgopn3c0b39mio3mam.png" alt="Concept of net present value chart" width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The second reason for starting at the right is purely practical: we are going to move the cards across the board from left to right. By starting at the right, we create space for cards to move into.&lt;/p&gt;

&lt;p&gt;Also, the "Development That Pays" video emphasized the importance of &lt;strong&gt;moments of glory&lt;/strong&gt; — allowing team members to move their own cards and take pride in their progress. It's not just about updating the board; it's about actively participating in the collective journey.&lt;/p&gt;

&lt;p&gt;At the end of the meeting, the board and the team's understanding of its current "shape are up to date. Team members can also share non-board related topics or updates, fo example tasks not listed on the board.&lt;/p&gt;

&lt;h3&gt;
  
  
  Success Story: Implementing Walking the Board
&lt;/h3&gt;

&lt;p&gt;Inspired by these videos, we decided to give "Walking the Board" a shot. The transformation was remarkable! Our daily stand-ups became more than just updates — they turned into collaborative sessions centered around the work on the board.&lt;/p&gt;

&lt;h4&gt;
  
  
  ELMO Rule
&lt;/h4&gt;

&lt;p&gt;To keep discussions concise, we &lt;a href="https://www.seriousscrum.com/page/elmo" rel="noopener noreferrer"&gt;introduced the "ELMO" rule&lt;/a&gt;. ELMO stands for &lt;em&gt;Enough, Let's Move On&lt;/em&gt;. "ELMO" is a word that the guide and travelers may use to indicate a conversation is either off-topic or takes too long. If a discussion is going off track, &lt;strong&gt;anyone&lt;/strong&gt; can simply say "ELMO". This signals that we'll discuss it later, outside our daily stand-up.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyw8betonyoasrvg65nxe.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyw8betonyoasrvg65nxe.jpg" alt="ELMO" width="800" height="401"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Secret Order
&lt;/h4&gt;

&lt;p&gt;We established a specific order for leading the board and other meetings. This system not only enhances a sense of responsibility but also encourages shared leadership among the team.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Result and Summary
&lt;/h3&gt;

&lt;p&gt;Since adopting Walking the Board in the summer of 2020, our meetings have changed a lot. We have shifted away from giving individual updates. Instead, our focus is entirely on the work on the board. This change has made our stand-ups more productive and collaborative, as we're now centered on the tasks at hand rather than individual narratives.&lt;/p&gt;

&lt;p&gt;We switched from traditional stand-ups to "Walking the Board" because we wanted our meetings to be more efficient. The videos from "Development That Pays" played a key role in inspiring this change, showing us what wasn't working with the old way and the benefits of a more team-focused approach. Now, Walking the Board is a regular part of our daily routine, making our meetings more focused, productive, and collaborative. If you're looking to improve your stand-ups, the insights from "Development That Pays" are definitely worth exploring.&lt;/p&gt;

</description>
      <category>agile</category>
      <category>meetings</category>
      <category>collaboration</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Migrating from Self-Managed RabbitMQ to Cloud-Native AWS Amazon MQ: A Technical Odyssey</title>
      <dc:creator>Sergey Podgorny</dc:creator>
      <pubDate>Sat, 14 Oct 2023 15:04:00 +0000</pubDate>
      <link>https://dev.to/ottonova/migrating-from-self-managed-rabbitmq-to-cloud-native-aws-amazon-mq-a-technical-odyssey-1376</link>
      <guid>https://dev.to/ottonova/migrating-from-self-managed-rabbitmq-to-cloud-native-aws-amazon-mq-a-technical-odyssey-1376</guid>
      <description>&lt;p&gt;In the ever-evolving world of cloud-native solutions, it can be a daunting task to maintain message brokers. For a while, our team was responsible for a self-managed RabbitMQ instance. While this worked well initially, we encountered challenges in terms of maintenance, version updates, and data recovery. This led us to explore Amazon MQ, a fully managed message broker service offered by AWS.&lt;/p&gt;

&lt;p&gt;In this article, we'll discuss the advantages of both self-managed RabbitMQ and Amazon MQ, the reasons behind our migration, and the hurdles we faced during the transition. Our journey offers insights for other developers, who consider a similar migration path.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Self-Managed RabbitMQ Era
&lt;/h3&gt;

&lt;p&gt;Our experience with self-managed RabbitMQ was characterized by control, high availability, and the responsibility to ensure data integrity. Here are some of the advantages of this approach:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Total Control&lt;/strong&gt;&lt;br&gt;
Running your own RabbitMQ server gives you complete control over configuration, security, and updates. You can fine-tune the setup to meet your specific requirements: ideal for organizations with complex or unique messaging needs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;High Availability&lt;/strong&gt;&lt;br&gt;
It's worth noting that our entity was running on AWS EC2, whose SLA guarantees only 99.99%, but de-facto we achieved a remarkable uptime rate of 99.999% with our self-managed RabbitMQ setup. The downtime was almost non-existent, which ensured a reliable message flow through our system. High availability is crucial for many mission-critical applications.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Data Recovery&lt;/strong&gt;&lt;br&gt;
Ironically, data recovery was a challenge with our self-managed RabbitMQ. In the event of a crash, we lacked confidence in our ability to restore data fully. This vulnerability urged us to consider Amazon MQ, a fully managed solution.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  The Shift to Amazon MQ
&lt;/h3&gt;

&lt;p&gt;As time passed, it became apparent that managing RabbitMQ was no longer sustainable for our team. Here are the primary reasons that drove us to explore Amazon MQ as an alternative:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Skills Gap&lt;/strong&gt;&lt;br&gt;
Our team lacked in-house experts dedicated to managing RabbitMQ, which posed a risk to our operations. As RabbitMQ versions evolved, staying up-to-date became increasingly challenging. This skill gap urged us to consider Amazon MQ, a fully managed solution.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;AWS Integration&lt;/strong&gt;&lt;br&gt;
As an AWS service, Amazon MQ seamlessly integrated with our existing AWS infrastructure, providing us with a more cohesive and consistent cloud environment. It allowed us to leverage existing AWS services and tools, which resulted in a smooth migration process.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Managed Service&lt;/strong&gt;&lt;br&gt;
The promise of offloading the operational burden to AWS was enticing. Amazon MQ handles tasks like patching, maintenance, and scaling. This allows our team to focus on more strategic initiatives.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Enhanced Security&lt;/strong&gt;&lt;br&gt;
One key advantage of switching to AmazonMQ is its strong foundation on AWS infrastructure. This not only ensures robust security practices but also regular updates are integrated into the system. So, it gives us confidence, as we know that any potential vulnerabilities are under active monitoring and management.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  The Amazon MQ Experience
&lt;/h3&gt;

&lt;p&gt;While the move to Amazon MQ presented numerous benefits, we also encountered some challenges that are worth noting:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnbpa07bdqinvjbdk5gqr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnbpa07bdqinvjbdk5gqr.png" alt="Downtime logs for RabbitMQ instance" width="800" height="199"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;SLA Guarantees&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://aws.amazon.com/amazon-mq/sla/" rel="noopener noreferrer"&gt;Amazon MQ's service level agreement (SLA)&lt;/a&gt; guarantees 99.9% availability. This is generally acceptable for many businesses but was a step down from our self-managed RabbitMQ's 99.999% uptime. While the difference might seem small, it translated into more downtime. A trade-off we had to accept.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Limited Configuration&lt;/strong&gt;&lt;br&gt;
Amazon MQ abstracts many configuration details. This simplifies management for the most users. However, this simplicity comes at the cost of fine-grained control. For organizations with highly specialized requirements, this might be a drawback.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cost Considerations&lt;/strong&gt;&lt;br&gt;
Amazon MQ is a managed service, which means there are associated costs. While the managed service helps reduce operational overhead, it's crucial to factor in the cost implications when migrating.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  What do three nines (99.9) really mean?
&lt;/h3&gt;

&lt;p&gt;Here are my calculations according to Amazon MQ SLA:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;if the monthly downtime is &lt;a href="https://uptime.is/99.9" rel="noopener noreferrer"&gt;lower than ~43 minutes&lt;/a&gt;, they will charge 100% of the costs&lt;/li&gt;
&lt;li&gt;if the monthly downtime is &lt;a href="https://uptime.is/99" rel="noopener noreferrer"&gt;between ~43 minutes to ~7 hours&lt;/a&gt;, they will charge 90% of the costs of this downtime&lt;/li&gt;
&lt;li&gt;if the monthly downtime is &lt;a href="https://uptime.is/95" rel="noopener noreferrer"&gt;between ~7 hours to ~1day&lt;/a&gt;, they will charge 75% of the costs of this downtime&lt;/li&gt;
&lt;li&gt;and if the monthly downtime is &lt;a href="https://uptime.is/95" rel="noopener noreferrer"&gt;higher than ~1 day&lt;/a&gt;, they won't charge any costs for this downtime&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Our migration from self-managed RabbitMQ to Amazon MQ represented a shift in the way we approach message brokers. While Amazon MQ offered many benefits, such as reduced operational burden and seamless AWS integration, it came with some trade-offs, including a lower SLA guarantee and less granular control.&lt;/p&gt;

&lt;p&gt;Ultimately, the decision to migrate should be based on your organization's specific needs, resources, and objectives. For us, the trade-offs were acceptable given the advantages of a managed service within our AWS ecosystem.&lt;/p&gt;

&lt;p&gt;The path to a cloud-native solution isn't always straightforward, but it can lead to more streamlined operations and a greater focus on innovation rather than infrastructure management. Understanding the pros and cons of both approaches is vital for an informed decision about your messaging infrastructure.&lt;/p&gt;

&lt;p&gt;As technology continues to evolve, it's essential to stay adaptable and leverage the right tools and services to meet your business needs. In our case, the migration to Amazon MQ allowed us to do just that.&lt;/p&gt;

</description>
      <category>rabbitmq</category>
      <category>aws</category>
      <category>amazonmq</category>
      <category>cloudnative</category>
    </item>
    <item>
      <title>How and why we updated RabbitMQ queues on production</title>
      <dc:creator>Sergey Podgorny</dc:creator>
      <pubDate>Sat, 05 Dec 2020 13:16:49 +0000</pubDate>
      <link>https://dev.to/ottonova/how-and-why-we-updated-rabbitmq-queues-on-production-2h76</link>
      <guid>https://dev.to/ottonova/how-and-why-we-updated-rabbitmq-queues-on-production-2h76</guid>
      <description>&lt;p&gt;In this article, I would like to share with you and the whole internet our experience of dealing with RabbitMQ Live updates. You will learn some details about our architecture and use cases. Let's start from the simplest... Why do we need RabbitMQ in our business?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5v187fajkej1sydbgon1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5v187fajkej1sydbgon1.png" alt="Backend with synchronous tasks processing" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Our Architecture
&lt;/h3&gt;

&lt;p&gt;As a health insurance company, our business depends on many different third-party services to analyze risks, process claimable documents, charge monthly payments etc. All these processes take some time to be processed, so to keep our services fast and autonomous from each other, we are using asynchronous processing of tasks that can be done in the background. This approach speeds up responses and allows to do more in the background, ie. email sending, policy creation, acceptance verification etc.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fsqqwauyd4ohrf5dmlrvi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fsqqwauyd4ohrf5dmlrvi.png" alt="Backend with synchronous tasks processing" width="800" height="575"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Whenever a client expresses some intent to the API by making a request to it, this intent can create follow-up tasks. These tasks do not need to be handled synchronously, i.e. they do not need to be handled while processing the initial request. Instead, we put a message about this intent onto the message queue where it can be picked up asynchronously by another process and handled independently from the original request.&lt;/p&gt;

&lt;h3&gt;
  
  
  Problem
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;But with great opportunities comes great responsibility&lt;/em&gt;. Message processing is very important and critical for our business. Some messages could &lt;a href="https://www.rabbitmq.com/dlx.html#:~:text=The%20reason%20is%20a%20name,allowed%20queue%20length%20was%20exceeded" rel="noopener noreferrer"&gt;expire without being consumed or inconsistent with queue restricted arguments&lt;/a&gt;. In theory, this should not happen or might happen in a very rare case. But as we are working with customers data, we do not want to lose important messages. To keep dead messages saved in the message broker and do not stuck them in the original queue, we are using &lt;code&gt;dead-letter&lt;/code&gt; feature.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F67kadgxlehzgiovfpjlz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F67kadgxlehzgiovfpjlz.png" alt="An old dead-letter implementation" width="800" height="329"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Messages are published to exchange and can be sent to multiple queues depending on the routing key. As you can see from the image above, we used the same dead-letter scheme as for the original queues, so dead messages may end up in the wrong dead-letter queues. It is not very critical if you pick up dead messages manually (considering that they are rare), but nevertheless, it is still strange to find these messages in the wrong place.&lt;/p&gt;

&lt;p&gt;To solve this problem, we need to add a new argument to the properties of the queues, it is &lt;code&gt;x-dead-letter-routing-key&lt;/code&gt; and it should be unique. As a unique value for the routing key, we can use the queue name itself. This idea brought our team one step closer to a good solution: &lt;em&gt;we don't need a dead-letter exchange anymore&lt;/em&gt; 🎉. To simplify it, we can use default nameless exchange &lt;code&gt;""&lt;/code&gt; with the dead-letter queue as the routing key and it will forward the message directly to the proper queue.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fv46cx1alae08819bk3ln.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fv46cx1alae08819bk3ln.png" alt="Dead-letter implementation with proper routing" width="800" height="268"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Unfortunately, doing everything is not as easy as writing or talking about it 😒. To maintain the consistency and stability of the message broker, the RabbitMQ does not allow changing the arguments of already existing queues.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deployment preparation
&lt;/h3&gt;

&lt;p&gt;So, RabbitMQ does not allow you to change queue arguments in the runtime, so the only possible way to do it by removing queues and re-creating them again with updated arguments. But it is not possible in production, as we might lose some messages when they already removed, but new ones still do not exist. To solve this problem we need to introduce temporary queues to handle these messages, while old queues will be removed. For a simple system, this will be possible with 4 releases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create temporary queues, but do not handle messages from them for now.&lt;/li&gt;
&lt;li&gt;Switch to the new queues and remove old queues. At this step, we already have a properly configured queues, but names are different. To return to old names, we need to do the same steps again.&lt;/li&gt;
&lt;li&gt;Create new queues with old names, but with updated arguments. Do not consume messages from them for now.&lt;/li&gt;
&lt;li&gt;Switch to the new queues with updated arguments.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F4bc6nf9kzl2bhowi8smw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F4bc6nf9kzl2bhowi8smw.png" alt="4 steps to update queue arguments" width="780" height="1165"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;4 releases, not a few, right? This requires not only a lot of small work, but also attention to make sure everything went right every time. How can we reduce them? 🤔&lt;/p&gt;

&lt;p&gt;The simplest thing we can do is agree to rename the queues. This will reduce the number of releases by 2 times, since we will not need to rename them back. This was acceptable to us, and we even got more of it as we improved the message handling process. But that's a completely different story 😉.&lt;/p&gt;

&lt;p&gt;What else can you do? Enabling consumers and message handling in the new queues right away will reduce release count to only one, but we should accept the risk of duplicated messages when new queues already created but old ones are still processing.&lt;/p&gt;

&lt;p&gt;At this point, I was stopped by the teammate, because I did not take into account the process of our deployment. We have &lt;em&gt;blue-green deployment process&lt;/em&gt;, it's when you have multiple instances of the same thing. And when you deploy, you take one down, upgrade, then put it up, then take the other one down to upgrade. This guarantees there is something always up. In our case, this means there is always a consumer there.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fcy9jz6yqz8mxozymwzwp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fcy9jz6yqz8mxozymwzwp.png" alt="Blue-green deployment" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, messages can definitely be duplicated if deployed during business hours. Deployment takes several minutes, which means that both old and new queues will be active for several minutes.&lt;/p&gt;

&lt;p&gt;Time to analyze and decide whether it is safe to deploy the application at night (and do we really want to do it 🙂) when the message flow is low, or it is worth implementing a third-party service like a Redis to check if the message has already been processed by some consumer, old or new.&lt;/p&gt;

&lt;h3&gt;
  
  
  Release
&lt;/h3&gt;

&lt;p&gt;The easiest way to check the load on our message broker is to check the number of logs by day of the week and time. Since we are a highly focused company working only in Germany, we have a very low message load from late evening to early morning. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvr5s2t4u9w27zzuoiy3o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvr5s2t4u9w27zzuoiy3o.png" alt="amqp logs count per datetime" width="800" height="569"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It is not such a big highload as it could be, so we can accept the risk that some messages may be duplicated, but even if this happens, their number will be extremely small and we can manually solve them. This will save the resources and time that would be required for two releases.&lt;/p&gt;

&lt;p&gt;After trying to release after midnight we found out that we couldn't do it at night. Some of our third-party services are not available, so the container simply cannot be booted. Well, it was worth trying once, now we know it for sure. Nighttime for sleeping 😴.&lt;/p&gt;

&lt;p&gt;But we can still do it late in the evening or early in the morning. One has only to pay attention to the RabbitMQ load.&lt;/p&gt;

&lt;p&gt;Late in the evening:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fsxtcj3ckdjp02boeqve2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fsxtcj3ckdjp02boeqve2.png" alt="amqp logs count late in the evening" width="800" height="123"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Early in the morning:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fv0svv72a7t6t8fqfipuk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fv0svv72a7t6t8fqfipuk.png" alt="amqp logs count early in the morning" width="800" height="129"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We made the decision to press the release button early in the morning after a good night's sleep. This time everything went fine and there were no duplicates.&lt;/p&gt;

&lt;p&gt;It was not an easy way to solve this problem, but it was worth it. Solving this problem, our team and I learned a lot of interesting things about message consuming and deployment processes. Now it is even better than before, with correct queue settings and decoupled message handling 😎.&lt;/p&gt;




&lt;h3&gt;
  
  
  TL;DR
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;RabbitMQ does not allow to rename queues or change queue arguments;&lt;/li&gt;
&lt;li&gt;to change something in the queue, you have to remove it and re-create;&lt;/li&gt;
&lt;li&gt;to re-create it safe, you need to use temporary queues;&lt;/li&gt;
&lt;li&gt;stable system could be run under multiple instances, so be aware of duplicated messages between old queues and new queues;&lt;/li&gt;
&lt;li&gt;if your business is tied to one timezone and is not high loaded at night, it is acceptable to have duplicated messages instead of over-engineering your consumers.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>rabbitmq</category>
      <category>amqp</category>
      <category>production</category>
      <category>release</category>
    </item>
    <item>
      <title>Attending GopherCon online</title>
      <dc:creator>Sergey Podgorny</dc:creator>
      <pubDate>Mon, 10 Aug 2020 11:18:47 +0000</pubDate>
      <link>https://dev.to/ottonova/attending-gophercon-online-4n43</link>
      <guid>https://dev.to/ottonova/attending-gophercon-online-4n43</guid>
      <description>&lt;p&gt;2020 will be remembered for a very long time by the quarantine and the accompanying restrictions. All events where there is a crowd of people have been cancelled and we are trying to adhere to all recommendations. It would seem that this year's conference would be impossible. But tough times await new solutions, and now conferences are also moving online.&lt;/p&gt;

&lt;p&gt;This innovative solution has its pros and cons. What I liked was:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ability to communicate with the speaker;&lt;/li&gt;
&lt;li&gt;switch channels just in one click;&lt;/li&gt;
&lt;li&gt;talks were recorded in advance, so speakers could answer questions in runtime;&lt;/li&gt;
&lt;li&gt;talk to anyone you want in chat;&lt;/li&gt;
&lt;li&gt;sitting in my favourite chair with two monitors;&lt;/li&gt;
&lt;li&gt;slides or speaker monitor very clearly visible (people with poor eyesight will understand me 😉);&lt;/li&gt;
&lt;li&gt;if you get bored, you can go about your business (conferences in the post-Soviet area are held on weekends, so you need to spend your personal time);&lt;/li&gt;
&lt;li&gt;waking up late and no queues to get a pass.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nevertheless, in addition to the pros, there were also disadvantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;affiliate ads sound more intrusive and more like spam;&lt;/li&gt;
&lt;li&gt;the platform they used for sharing had a few technical issues, so I met a lot of freezes;&lt;/li&gt;
&lt;li&gt;only the winners of contests and quizzes can receive partner merchandise.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What about the conference
&lt;/h3&gt;

&lt;p&gt;The conference is divided into two days. The first day was devoted to workshops, and the second day there were 2 tracks for talks. The overall level of the talks was quite high and I personally really liked it.&lt;/p&gt;

&lt;p&gt;Workshops were held exclusively in Russian, so the audience was very limited (about 140 participants). But the talks were both in Russian and in English and were very reasonably distributed among the tracks (approximately the number of listeners on the stream was 150 and 80 per track).&lt;/p&gt;

&lt;h4&gt;
  
  
  Workshops
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Observability in practice&lt;/strong&gt; by Elena Grahovac
&lt;div class="ltag__user ltag__user__id__23443"&gt;
    &lt;a href="/elena" class="ltag__user__link profile-image-link"&gt;
      &lt;div class="ltag__user__pic"&gt;
        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F23443%2F229947a0-0c15-4b4d-8950-80bd9bf6bba0.jpg" alt="elena image"&gt;
      &lt;/div&gt;
    &lt;/a&gt;
  &lt;div class="ltag__user__content"&gt;
    &lt;h2&gt;
&lt;a class="ltag__user__link" href="/elena"&gt;Elena Grahovac&lt;/a&gt;Follow
&lt;/h2&gt;
    &lt;div class="ltag__user__summary"&gt;
      &lt;a class="ltag__user__link" href="/elena"&gt;&lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Quite an interesting and practical workshop, in which she showed by a practical example of how to log useful information using a &lt;code&gt;uber-go/zap&lt;/code&gt; logger, tracing of application flow execution and gathering metrics using &lt;code&gt;opentelemetry&lt;/code&gt;, visualization and analysis of the obtained data using &lt;code&gt;jaeger&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The codebase available on GitHub, just use tags in this order &lt;code&gt;clean&lt;/code&gt;, &lt;code&gt;logger&lt;/code&gt;, &lt;code&gt;tracer&lt;/code&gt;, &lt;code&gt;meter&lt;/code&gt; and &lt;code&gt;tools&lt;/code&gt; to follow the process:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/rumyantseva" rel="noopener noreferrer"&gt;
        rumyantseva
      &lt;/a&gt; / &lt;a href="https://github.com/rumyantseva/stayathome" rel="noopener noreferrer"&gt;
        stayathome
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      [workshop] GopherConRU 2020: Getting started with Observability in Go. Logs and OpenTelemetry.
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;TLA+/TLC: a practical tool for formal verification of algorithms that all gophers need to know for sure&lt;/strong&gt; by Alexey Naidyonov&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Despite the title, I personally think that this topic is important, but not so much that everyone should know it. It would be nice to know - yes, it can help you with your architecture planning, but for need - no, I don't think so.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/growler" rel="noopener noreferrer"&gt;
        growler
      &lt;/a&gt; / &lt;a href="https://github.com/growler/gophercon-russia-2020-talk" rel="noopener noreferrer"&gt;
        gophercon-russia-2020-talk
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      My talk for Russian GopherCon 2020
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;TLA+ is a tool to design systems and algorithms, then programmatically verify that those systems don't have critical bugs. It's the software equivalent of a blueprint.&lt;/p&gt;

&lt;p&gt;If you are interested to learn more, here are a few links for you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://lamport.azurewebsites.net/video/videos.html" rel="noopener noreferrer"&gt;The TLA+ Video Course&lt;/a&gt; by Leslie Lamport, author of TLA+ and PlusCal specification language&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learntla.com/introduction/" rel="noopener noreferrer"&gt;Learn TLA+&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/tlaplus/Examples" rel="noopener noreferrer"&gt;TLA+ Examples&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you are interested in a deeper study, then "&lt;em&gt;Specifying Systems&lt;/em&gt;" and "&lt;em&gt;Practical TLA+&lt;/em&gt;" books will serve as the best continuation for you.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ftbn68o9ptkp3869u09ju.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ftbn68o9ptkp3869u09ju.png" alt="TLA+ best books to learn" width="600" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Talks
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Continuous profiling for Go applications&lt;/strong&gt; by Mike Kabischev&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nice talk, started with an overview of profile types and basics profiling with &lt;code&gt;runtime/pprof&lt;/code&gt;. Then several continuous profiling packages were compared, such as &lt;code&gt;github.com/conprof/conprof&lt;/code&gt; and &lt;code&gt;github.com/profefe/profefe&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Profiling is a part of observability, that's why &lt;code&gt;pprof&lt;/code&gt; should be always available, but &lt;code&gt;net/http/pprof&lt;/code&gt; should be accessible in the different port.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2ie3jewa6mm82y0oa2oa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2ie3jewa6mm82y0oa2oa.png" alt="Running net/http/pprof on the different port" width="762" height="272"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As a follow-up you can also read &lt;/p&gt;
&lt;div class="ltag__link"&gt;
  &lt;a href="https://medium.com/google-cloud/continuous-profiling-of-go-programs-96d4416af77b" class="ltag__link__link" rel="noopener noreferrer"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fv2%2Fresize%3Afill%3A64%3A64%2F1%2A6frWC0zC0sYDn68Jfizc9w.jpeg" alt="Jaana Dogan"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://medium.com/google-cloud/continuous-profiling-of-go-programs-96d4416af77b" class="ltag__link__link" rel="noopener noreferrer"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Continuous Profiling of Go programs | by Jaana Dogan | Google Cloud - Community | Medium&lt;/h2&gt;
      &lt;h3&gt;Jaana Dogan ・ &lt;time&gt;May 12, 2020&lt;/time&gt; ・ 
      &lt;div class="ltag__link__servicename"&gt;
        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fmedium-f709f79cf29704f9f4c2a83f950b2964e95007a3e311b77f686915c71574fef2.svg" alt="Medium Logo"&gt;
        Medium
      &lt;/div&gt;
    &lt;/h3&gt;
&lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;eBPF: Modern Introspection Capabilities in Linux&lt;/strong&gt; by Marko Kevac&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;BPF is kernel-level profiling in Linux. It allows you to monitor what happens in the system, as Linux is an event-driven system and you can analyse these events with BPF program. The newer the version of your kernel, the more BPF features you can use. However, BPF is not fully adapted with Go, namely BPF program written in Go cannot work with the kernel part. The most commonly used package is &lt;code&gt;iovisor/gobpf&lt;/code&gt;, but there are other alternatives like &lt;code&gt;github.com/dropbox/goebpf&lt;/code&gt; and &lt;code&gt;github.com/cilium/ebpf&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you are interested and would like to know more, then it is best to read "&lt;em&gt;BPF Performance Tools&lt;/em&gt;" and "&lt;em&gt;Linux Observability with BPF&lt;/em&gt;" books:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fv4n8jz4yiv6aqb68er9e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fv4n8jz4yiv6aqb68er9e.png" alt="BPF best books to read" width="560" height="349"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Codegenerator in Go&lt;/strong&gt; by Dmitriy Smotrov &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Personally, I am too conservative for decisions such as code generation, as I prefer to do everything myself. Nevertheless, such solutions can speed up work on routine things, for example, describing a repository for a model, or writing tests for this model. In addition, it is important to note that Go has good functionality for such solutions.&lt;/p&gt;

&lt;p&gt;Source code is available on GitHub&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/dsxack" rel="noopener noreferrer"&gt;
        dsxack
      &lt;/a&gt; / &lt;a href="https://github.com/dsxack/gophercon2020" rel="noopener noreferrer"&gt;
        gophercon2020
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Materials used in the Gophercon 2020 conference
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GoLand Tips &amp;amp; Tricks&lt;/strong&gt; by Florin Patan&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you are using GoLand as an IDE for writing code, then the examples shown during the talk can be very useful for you.&lt;/p&gt;

&lt;p&gt;Code samples can be found in the GitHub&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/JetBrains" rel="noopener noreferrer"&gt;
        JetBrains
      &lt;/a&gt; / &lt;a href="https://github.com/JetBrains/golandtipsandtricks" rel="noopener noreferrer"&gt;
        golandtipsandtricks
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      This is an ever evolving repository for GoLand Tips&amp;amp;Tricks
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Debugging concurrent programs in Go&lt;/strong&gt; by Andrii Soldatenko&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag__user ltag__user__id__191020"&gt;
    &lt;a href="/andriisoldatenko" class="ltag__user__link profile-image-link"&gt;
      &lt;div class="ltag__user__pic"&gt;
        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F191020%2Fb873da2e-cfab-449b-8f64-16978af770c4.jpeg" alt="andriisoldatenko image"&gt;
      &lt;/div&gt;
    &lt;/a&gt;
  &lt;div class="ltag__user__content"&gt;
    &lt;h2&gt;
&lt;a class="ltag__user__link" href="/andriisoldatenko"&gt;Andrii Soldatenko&lt;/a&gt;Follow
&lt;/h2&gt;
    &lt;div class="ltag__user__summary"&gt;
      &lt;a class="ltag__user__link" href="/andriisoldatenko"&gt;Author of telegram channel t.me/golang_for_two&lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;The talk was built on the use of the console version of the delve (&lt;code&gt;dlv&lt;/code&gt;). Of course, GoLand will solve it for you as its debugger also uses devle, same as VSCode, but not everything from delve release will immediately appear in your IDE. So if you want to have a better and custom debugger, it is good to know how &lt;code&gt;dlv&lt;/code&gt; works.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/go-delve" rel="noopener noreferrer"&gt;
        go-delve
      &lt;/a&gt; / &lt;a href="https://github.com/go-delve/delve" rel="noopener noreferrer"&gt;
        delve
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Delve is a debugger for the Go programming language.
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Slides can be found in the &lt;a href="https://www.dropbox.com/s/00c9vtyooz5b58v/advanced_debugging_techniques_of_go_code.pdf" rel="noopener noreferrer"&gt;Dropbox&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Go, please: language server under the microscope&lt;/strong&gt; by Ilya Danilkin &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A Language Server is meant to provide the language-specific smarts and communicate with development tools over a protocol that enables inter-process communication. The idea behind the Language Server Protocol (LSP) is to standardize the protocol for how such servers and development tools communicate. This way, a single Language Server can be re-used in multiple development tools, which in turn can support multiple languages with minimal effort.&lt;/p&gt;

&lt;p&gt;In the past, there were many LSP implementations in Go, but over time, the Go core team developed the official LSP implementation &lt;code&gt;gopls&lt;/code&gt; that we know today.&lt;/p&gt;

&lt;p&gt;Slides can be found in &lt;a href="https://slides.com/nezorflame/20200809_gophercon/" rel="noopener noreferrer"&gt;slides.com&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;How to stop thinking about required fields and start writing contracts&lt;/strong&gt; by Vladimir Serdyukov&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The talk tells about the Buffer Protocol mechanism, invented by Google for serializing data structures. The speaker talked about the differences between &lt;code&gt;proto2&lt;/code&gt; and &lt;code&gt;proto3&lt;/code&gt;, as well as how to use required fields in &lt;code&gt;proto3&lt;/code&gt;. For validation, you can use either &lt;code&gt;buf.build&lt;/code&gt; or &lt;code&gt;github.com/uber/prototool&lt;/code&gt;.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/golang" rel="noopener noreferrer"&gt;
        golang
      &lt;/a&gt; / &lt;a href="https://github.com/golang/protobuf" rel="noopener noreferrer"&gt;
        protobuf
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Go support for Google's protocol buffers
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;In new projects and for better compatibility it is recommended to use &lt;code&gt;proto3&lt;/code&gt;. &lt;code&gt;apiv2&lt;/code&gt; can and should be used, but &lt;code&gt;prototool&lt;/code&gt; does not support it. &lt;code&gt;buf.build&lt;/code&gt; looks promising, but plugins such as &lt;em&gt;&lt;code&gt;gogoproto&lt;/code&gt;&lt;/em&gt; lose their relevance.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Intro to AI for software engineers using go-learn&lt;/strong&gt; by Miriah Peterson&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;GoLearn is an accessible ML library written primarily in Go with some C and C++. It uses with simple classification problems.&lt;/p&gt;

&lt;p&gt;Checkout the examples &lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/sjwhitworth" rel="noopener noreferrer"&gt;
        sjwhitworth
      &lt;/a&gt; / &lt;a href="https://github.com/sjwhitworth/golearn" rel="noopener noreferrer"&gt;
        golearn
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Machine Learning for Go
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;To learn more, go through the tutorials at&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/ardanlabs" rel="noopener noreferrer"&gt;
        ardanlabs
      &lt;/a&gt; / &lt;a href="https://github.com/ardanlabs/training-ai" rel="noopener noreferrer"&gt;
        training-ai
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;and &lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/dwhitena" rel="noopener noreferrer"&gt;
        dwhitena
      &lt;/a&gt; / &lt;a href="https://github.com/dwhitena/gc-ml" rel="noopener noreferrer"&gt;
        gc-ml
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Go ML/AI Training Materials for GopherCon 2019
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Growth of the open-source community: problems and solutions&lt;/strong&gt; by Georgy Rylov&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The speaker told how he organized a special course at the university and involved students in writing their project.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/wal-g" rel="noopener noreferrer"&gt;
        wal-g
      &lt;/a&gt; / &lt;a href="https://github.com/wal-g/wal-g" rel="noopener noreferrer"&gt;
        wal-g
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Archival and Restoration for databases in the Cloud
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;As a result, he summed up that students can write productive code in Go and it takes comparable time to review it as for regular developer. It is not necessary to have a curriculum in order to come to the university with your projects.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Generic Programming in Go&lt;/strong&gt; by Vladimir Vivien, "&lt;em&gt;Learning Go Programming&lt;/em&gt;" book author&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag__user ltag__user__id__2734"&gt;
    &lt;a href="/vladimirvivien" class="ltag__user__link profile-image-link"&gt;
      &lt;div class="ltag__user__pic"&gt;
        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2734%2F309126.jpeg" alt="vladimirvivien image"&gt;
      &lt;/div&gt;
    &lt;/a&gt;
  &lt;div class="ltag__user__content"&gt;
    &lt;h2&gt;
&lt;a class="ltag__user__link" href="/vladimirvivien"&gt;Vladimir Vivien&lt;/a&gt;Follow
&lt;/h2&gt;
    &lt;div class="ltag__user__summary"&gt;
      &lt;a class="ltag__user__link" href="/vladimirvivien"&gt;&lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;The possibility of adding generics to Go is currently being developed. Preliminary, they should be expected no earlier than 2 years later.&lt;/p&gt;

&lt;p&gt;Go core team assumes a level of performance in runtime, as generics should come with faster execution time. Nevertheless, compiler time may increase, but the Go core team are doing everything to keep compilation fast. Use of generics can be also complicated and the code with them may look unusual. Here is an example of using type parameters in functions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;param&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The proposal can be found here:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/vladimirvivien" rel="noopener noreferrer"&gt;
        vladimirvivien
      &lt;/a&gt; / &lt;a href="https://github.com/vladimirvivien/go-generics-proposal" rel="noopener noreferrer"&gt;
        go-generics-proposal
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Examples using Go2 generics 
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;&lt;a href="https://blog.golang.org/generics-next-step" rel="noopener noreferrer"&gt;The Next Step for Generics | go blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://go.googlesource.com/proposal/+/refs/heads/master/design/go2draft-contracts.md" rel="noopener noreferrer"&gt;Contracts — Draft Design | Google source&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ardanlabs/gotraining/tree/master/topics/go/generics" rel="noopener noreferrer"&gt;Go training for Generics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://go.googlesource.com/go/+/refs/heads/dev.go2go/" rel="noopener noreferrer"&gt;&lt;code&gt;dev.go2go&lt;/code&gt; branch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://go.googlesource.com/go/+/refs/heads/dev.go2go/README.go2go.md" rel="noopener noreferrer"&gt;&lt;code&gt;dev.go2go&lt;/code&gt; branch README&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://go.googlesource.com/go/+/refs/heads/dev.go2go/src/cmd/go2go/testdata/go2path/src" rel="noopener noreferrer"&gt;&lt;code&gt;dev.go2go&lt;/code&gt; testdata&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;I was pleased with the time spent listening to talks and workshops. In addition to the information from the official part, in the communication channels, I have gathered for myself several technologies that are worth paying attention to.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;uber-go/zap&lt;/code&gt; logger might be a good alternative to the &lt;code&gt;sirupsen/logrus&lt;/code&gt; which we are currently using at ottonova. Although it is simpler to implement and use, nevertheless its execution speed is several times lower than that of &lt;code&gt;zap&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;FluentD is an interesting alternative for LogStash. From a preliminary analysis of FluentD, it appears to be less resource-intensive and more flexible.&lt;/li&gt;
&lt;li&gt;Observability is popular and demanded thing, and most of the conference was dedicated to it.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>gopher</category>
      <category>gophercon</category>
      <category>conference</category>
      <category>go</category>
    </item>
    <item>
      <title>Bulgaria PHP Conference 2019</title>
      <dc:creator>Sergey Podgorny</dc:creator>
      <pubDate>Mon, 16 Dec 2019 10:23:07 +0000</pubDate>
      <link>https://dev.to/ottonova/bulgaria-php-conference-2019-2097</link>
      <guid>https://dev.to/ottonova/bulgaria-php-conference-2019-2097</guid>
      <description>&lt;p&gt;Let's talk about organization, preparation and venue first. From my point of view, the organizers did a lot to make this conference great, at least they tried to do their best. The conference, same as the workshop took place in the very center of the city, in the biggest public hall. It was quite easy to find it and to get there, either with public transport or by foot if you were staying in the city center. One day in advance I got an email with quite descriptive instruction about everything I should know: how to get there, recommended places to stay, what they prepared for attendees etc.&lt;/p&gt;

&lt;p&gt;Unfortunately, I was a bit confused, because I did not figure out how to buy a ticket for the Workshop day if you already bought a conference ticket, when the workshop stream was not announced. Directly at the entrance to the workshop, there was a possibility to buy it, but I decided that it is not worth it and it is a bit expensive. Anyway, I am not sad about this fact, as conference organizers prepared a free of charge tour in the city and it was a good alternative.&lt;/p&gt;

&lt;p&gt;On the conference day, everything started with registration, grabbing my personal badge, general community talk and breakfast. I felt pretty comfortable there as organizers always tried to take care of us: there was a lot of drinks and snacks there, lunch was served by a special catering company and in the afternoon they made homemade cakes for us.&lt;/p&gt;

&lt;p&gt;And now more about the conference: it had 3 streams in parallel and in the afternoon one of these streams became unConf, where anyone could share something with everyone. The biggest stream had a lot of seats for all attendees, but not every talk assembled so many participants.&lt;/p&gt;

&lt;p&gt;You have to know about me, that I do not believe I can learn something from any talk, because most of the things are already known from programming paradigms, web development and PHP in general. Usually, talks at conferences are just a shared experience, exploring new unknown stuff or repeating something like SOLID, caching and other. Everything you want to learn could be easily and faster found on the web, and if you missed some talks you could watch them later on YouTube, moreover, for free. Personally, all these conferences are just community spirit, free baubles and lunch. &lt;strong&gt;But this conference managed to absolutely surprise me!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The biggest discovery for me was a talk about modern SQL from Markus Winnand. How much I did not know about SQL in general. Knowing modern relational databases, such as MySQL, PostgreSQL, Oracle DB or SQLite, does not mean you know modern SQL. The most SQL standards and features were introduced since SQL-1999 (recursion), SQL-2003 (schemaless and analytical, like median), SQL-2011 (system versioning, aka time-travelling), SQL-2016 (&lt;code&gt;JSON_TABLE&lt;/code&gt;), etc. &lt;em&gt;A lot&lt;/em&gt; has happened since SQL-92, SQL has evolved &lt;em&gt;beyond&lt;/em&gt; the relational idea. If you use SQL for &lt;em&gt;CRUD&lt;/em&gt; operations only, you are doing it wrong.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Do not use self-joins in SQL anymore!&lt;/strong&gt; Also, avoid &lt;code&gt;OFFSET&lt;/code&gt;s from your statements, they are a performance leak!&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdis1e95rfvgpastmj88f.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdis1e95rfvgpastmj88f.jpg" alt="All employees must wash hands after using self-joins" width="800" height="435"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The saddest conclusion I made: the most popular RDBMSes made themselves compliant with modern SQL only recently, but still, there are some features not ready in all RDBMSes. But what about modern ORMs? When will they be compliant with all the features we have in modern SQL? Or is it the best solution, for now, to avoid ORMs and write custom queries?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fraxqh1njq3wuldus49oe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fraxqh1njq3wuldus49oe.png" alt="SQL recursion and analitical" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9zfuqpj567oq6cj64qrc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9zfuqpj567oq6cj64qrc.png" alt="SQL system versioning and JSON_TABLE" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;By the way, he has a book about SQL performance explained, it is highly recommended to read it.&lt;/em&gt; You can find more info on his &lt;a href="https://modern-sql.com/" rel="noopener noreferrer"&gt;website&lt;/a&gt; or buy his book with stickers and mug.&lt;/p&gt;

&lt;p&gt;The conference was worth visiting at least for the sake of this talk, and I was very pleased with the fact that I learned so many new things I can use in my applications to boost performance. Anyway, there were also a few talks worth attending:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Encoding and charset&lt;/strong&gt;, presented by Andreas Heigl. Worth to know that encoding is not a character set and what is what. How to properly work with UTF-8 in PHP and MySQL. Be aware that &lt;code&gt;utf8&lt;/code&gt; in MySQL is not a real UTF-8 encoding, you have to use &lt;code&gt;utf8mb4&lt;/code&gt; instead for proper UTF-8.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Automated PHP Refactoring&lt;/strong&gt;, presented by Haralan Dobrev at unConf. He shared a &lt;a href="https://github.com/exakat/php-static-analysis-tools" rel="noopener noreferrer"&gt;collection of all known tools&lt;/a&gt; and showed how they could be implemented together.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Hexagonal Architecture&lt;/strong&gt; by Nicolas Carlo. It was not that much for me personally as DDD is based on this architecture, but anyway it was a very good structured talk with good examples and real-life cases.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;PHP-FIG Panel&lt;/strong&gt; to describe a stack of standards they have. Be aware that PSR-2 is deprecated right now and PSR-12 should be used instead.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Here is a list of some useful slides for you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://modern-sql.com/slides/SQLinThe21stCentury-2019-11-09.pdf" rel="noopener noreferrer"&gt;More Than a Query Language: SQL in the 21st Century&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://heiglandreas.github.io/slidedeck/HowToHandlePILE_OF_POO/20190314-confoo/index.html#/" rel="noopener noreferrer"&gt;How to tame a 🦄: encoding stuff&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://speakerdeck.com/trajchevska/solid-design-principles-for-better-team-performance" rel="noopener noreferrer"&gt;SOLID design principles for better team performance&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>php</category>
      <category>conference</category>
      <category>bgphp</category>
      <category>community</category>
    </item>
    <item>
      <title>php.barcelona
</title>
      <dc:creator>Alin Purcaru</dc:creator>
      <pubDate>Mon, 16 Dec 2019 08:59:29 +0000</pubDate>
      <link>https://dev.to/ottonova/php-barcelona-1k3k</link>
      <guid>https://dev.to/ottonova/php-barcelona-1k3k</guid>
      <description>&lt;p&gt;I and the rest of the PHP engineers at ottonova, had the pleasure of attending the PHP.Barcelona Conference in November this year. It was a great experience, spanning over two full days.&lt;/p&gt;

&lt;p&gt;I’ve put together some quick, and biased, notes about the presentations.  Here it goes…&lt;/p&gt;

&lt;h1&gt;
  
  
  Day 1
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Opening Keynote – Rasmus Lerdorf
&lt;/h2&gt;

&lt;p&gt;Really uplifting beginning of the conference with Rasmus going down memory lane. We got to know some of the motivation and the process of creating PHP. All this further strengthening my opinion that it didn’t really start as serious programming language. (Ok. I admit. It did progress since then, so don’t start throwing stones.)&lt;/p&gt;

&lt;p&gt;A funny highlight was the explanation that “PHP is vertically consistent” – the PHP functions match the vendor functions they create an API to. Of course, this leaves it inconsistent with itself.&lt;/p&gt;

&lt;p&gt;Also, really enlightening, was clarifying why adding things like further type checking, generics, or class modifiers, like “immutable” would be a serious performance hit to the language – so we should really stop hoping that any of that would come soon. &lt;/p&gt;

&lt;h2&gt;
  
  
  From Helpers to Middleware – Marco Pivetta
&lt;/h2&gt;

&lt;p&gt;Nice practical presentation, showing how design can incrementally evolve, from what would basically be spaghetti code, into a proper modular and scalable middleware-style architecture. While a good start, I would have hoped to see a deeper dive into this style, because where it stopped it felt like it just scratched the surface.&lt;/p&gt;

&lt;h2&gt;
  
  
  Microservices gone wrong – Anthony Ferrara
&lt;/h2&gt;

&lt;p&gt;Although this was just a public retrospective of a specific project, which maybe will not resonate with everyone, for me and the work we do at ottonova, there were still a couple of valuable lessons to take home:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Messages that microservices use to synchronize can be differentiated into proper Events and RPCs, and these categories can and maybe should be treated differently. The latter require a response back, while the former don’t really need it. We don’t have this clear separation ourselves yet, but the need for it is definitely starting to show.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Each entity in your domain does not need to have its own service. Larger services are also fine, if they make sense for your use case. Our own setup is using domain-defined microservices, of various sizes, so seeing that splitting everything aggressively may backfire will make us think twice when extracting a new microservice.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;He has a cute dog.&lt;/p&gt;

&lt;h2&gt;
  
  
  Serverless PHP applications with Bref – Matthieu Napoli
&lt;/h2&gt;

&lt;p&gt;I guess it’s nice to see that there is a way to hook up PHP to Lambda, but then again, why take the effort to force it and not just use a language supported directly? Apart from that aspect, interesting to see an intro into AWS Lambda, since I didn’t try it out myself yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  JSON Web Tokens – Sam Bellen
&lt;/h2&gt;

&lt;p&gt;Not that much to say here: JWTs. We already use them, you should use them too. They’re easy to work with and really useful. At their core they are just signed information in a nice and standard JSON format. Nevertheless still a very powerful concept as it enables you to transfer claims securely from one party to another.&lt;/p&gt;

&lt;h2&gt;
  
  
  Developing cacheable PHP applications – Thijs Feryn
&lt;/h2&gt;

&lt;p&gt;Well, this one was awkward. Especially since I had the pleasure of sitting through this exact presentations some months before. Thijs is a dedicated evangelist, you have to give it to him. He manages to squeeze everything out of what Varnish can do and serve it to his audience on a silver platter. &lt;/p&gt;

&lt;p&gt;Now come the buts. The use-cases considered in the presentation are outdated. Really focusing too much on server side rendering and templating. And I particularly did not enjoy instructing an auditorium full of developers (maybe some more impressionable than other) to use their caching layer for keeping application logic.&lt;/p&gt;

&lt;p&gt;Nothing wrong with Varnish itself, though. And since we need to keep all our data inside Germany, for legal reasons, maybe we’ll need to consider ourselves an on-premise caching solution in the future.&lt;/p&gt;

&lt;h2&gt;
  
  
  PHP Performance Trivia – Nikita Popov
&lt;/h2&gt;

&lt;p&gt;Really confident presentation from one of the core PHP contributors, containing a deeper dive into how the OPcache works, and what its limitations are. Not that serious limitations, if you ask me. With a bit of care for how you handle deployments, you should be fine.&lt;/p&gt;

&lt;p&gt;Also interesting to see some benchmarks that show that using objects instead of arrays is much more memory-efficient in PHP. Not that the opposite would have made us drop using Value Objects, but still good to see that we’re already using the memory friendly option.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get GOing with a new language – Kat Zień
&lt;/h2&gt;

&lt;p&gt;While there was nothing spectacular about this presentation, just an intro into Go, I still enjoyed seeing that there is a clear interest from the PHP community to explore other languages. Go is particularly relevant for us at ottonova, since we’re already using it for our messaging setup and we plan to try some more areas where we think it would do a better job than good old PHP.&lt;/p&gt;

&lt;h1&gt;
  
  
  Day 2
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Advanced Web Application Architecture – Matthias Noback
&lt;/h2&gt;

&lt;p&gt;Nice structured first dive into DDD and the rationale of it. We’re already doing most of what this presentation talks about, and much more, at ottonova, but it helps to see another’s take on it and double-check our approach.&lt;/p&gt;

&lt;p&gt;It was reassuring to see that one of the first requirements of DDD is to separate your Domain from your Infrastructure, a thing that we carefully follow, along with some more advanced techniques.&lt;/p&gt;

&lt;p&gt;Also really appreciated the general advice that not every project is the same and if something applies somewhere it does not automatically mean that it will apply to your situation. This is, of course, common sense, but it doesn’t hurt to hear some basic common sense from time to time, in a world overflooded with strong opinions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Working with Webhooks – Lorna Mitchell
&lt;/h2&gt;

&lt;p&gt;Decent structured presentation about Webhooks – an architectural style for async communication. Nothing groundbreaking here, but since this style is not standardly used (or at least not by me), it’s nice to be reminded it exists. Good tip with using ngrok for exposing local stuff.&lt;/p&gt;

&lt;h2&gt;
  
  
  Supercharge your apps with ReactPHP &amp;amp; PHP-PM – Albert Casademont
&lt;/h2&gt;

&lt;p&gt;Since FPM is already showing its scaling limitations for us, it was particularly interesting to see what other options would be available.&lt;/p&gt;

&lt;p&gt;For many of our processed requests, we have the common pattern that we get some input, we process it, and then pass it to another service (maybe external) and wait for a response. Then we do some more work on it and respond to our client. This implies considerable processing power wasted on our side – we wait a lot for HTTP responses ourselves. This is where some concurrent PHP would come in handy. While one request is waiting, other requests can be handled. So we will definitely be looking into either PHP-PM, or Swoole in the future.&lt;/p&gt;

&lt;h2&gt;
  
  
  It’s all about the goto – Derick Rethans
&lt;/h2&gt;

&lt;p&gt;This was a nice, theoretical, dive into how PHP parses and executes code. For someone with a minimal Computer Science background, I think it was still fairly basic, and I don’t think there was much to take away.&lt;/p&gt;

&lt;h2&gt;
  
  
  Develop microservices in PHP – Enrico Zimuel
&lt;/h2&gt;

&lt;p&gt;This was an interesting walk-through what are some of the benefits, and specific concerns, of using microservices. Nothing too new to us, since we already heavily rely on microservices both in the PHP group and in our other teams.&lt;/p&gt;

&lt;p&gt;One thing we noted down to improve was the standardisation of error responses. Good hint. We’ll definitely look into that one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mutation Testing – Better code by making bugs – Théo Fidry
&lt;/h2&gt;

&lt;p&gt;Mutation Testing seems really cool as a theoretical concept, and it’s nice to see that someone is trying it out. Not sure how it would work out in practice. So far, I can see two major downsides. First, it simply takes a lot of time to run such a test. Even with optimisations, this will be something that could take hours. Second, the testing itself seems only as good as your mutators, and I think writing relevant mutators is not a trivial task. Having some that just replace operators could be straight-forward, but how much does that help?&lt;/p&gt;

&lt;h1&gt;
  
  
  Back to Munich
&lt;/h1&gt;

&lt;p&gt;And the rest we sadly had to skip, to not miss our plane back home.&lt;/p&gt;

&lt;p&gt;Overall, as we hoped when booking the tickets, the lineup was a solid one. And they delivered. Kudos to them, as well as to the organizers. We came back with lots of new ideas, some that we will try in the near future, and confirmation that we are on the right track with many of our architectural decisions.&lt;/p&gt;

&lt;p&gt;We will definitely have Barcelona on our list for next year as well. Lovely city too.&lt;/p&gt;

</description>
      <category>php</category>
    </item>
    <item>
      <title>Recruiting Backend Engineers at ottonova</title>
      <dc:creator>Alin Purcaru</dc:creator>
      <pubDate>Tue, 22 Oct 2019 13:20:44 +0000</pubDate>
      <link>https://dev.to/ottonova/recruiting-backend-engineers-at-ottonova-1mld</link>
      <guid>https://dev.to/ottonova/recruiting-backend-engineers-at-ottonova-1mld</guid>
      <description>&lt;p&gt;To do our part and share with the Community, as well as provide a bit more transparency into ottonova and how we are building state-of-the-art software that powers Germany’s first digital health insurance, here are some words about how the Backend Team goes about finding new team members. &lt;/p&gt;

&lt;p&gt;We’re going to cover what we are doing in the Backend Team, what we value, and how we ensure we hire people that share our values.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Backend Team
&lt;/h2&gt;

&lt;p&gt;Our team is responsible for many of the services that power our health insurance solutions at ottonova. This includes our own unique functionality, like documents management, appointments timeline, guided signup, as well as interconnecting industry-specific specialized applications.&lt;/p&gt;

&lt;p&gt;Under the hood, we manage a collection of independent microservices. Most of them written in PHP and delivering REST APIs through Symfony, but a couple leveraging Node.js or Go. Of course, everything we use is cutting-edge technology, and we periodically upgrade.&lt;/p&gt;

&lt;p&gt;As a fairly young company, we spend most of our time adding new functionality to our software, all in cooperation with product owners, but at the same time we invest fair effort into continuously improving the technical quality of our services.&lt;/p&gt;

&lt;h2&gt;
  
  
  Values
&lt;/h2&gt;

&lt;p&gt;Technical excellence  is one of our team’s core values. To this end, we are practitioners of Domain-driven design (DDD). Our services are built around clearly defined domains and follow strict separation boundaries. &lt;/p&gt;

&lt;p&gt;Because we created an architecture that allows it, and we have the internal support to focus on quality, we invest a lot into keeping the bar high and whenever needed we refactor and make sure the Domain Layer stays up to date with the business needs, or that the Infrastructure Layer is performant enough and can scale.&lt;/p&gt;

&lt;p&gt;Although most of our work is done using PHP, we strongly believe in using the right tool for the job. Modern PHP 7+ happens to be a pretty good tool for describing a rich Domain, but we like to be pragmatic and where it is not good enough, maybe in terms of performance, we are free to choose something more appropriate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Expectations from a new team member
&lt;/h2&gt;

&lt;p&gt;From someone joining our team we, first of all, expect the right mindset for working in a company that values quality. We are looking for colleagues that are capable and eager to learn as well as happy to share their existing knowledge with the team. &lt;/p&gt;

&lt;p&gt;A certain set of skills is needed as well, or the right foundation for developing those skills. We are particularly interested in a good mastery of  programming and PHP fundamentals, Web Development, REST, OOP, and Clean Code.&lt;/p&gt;

&lt;p&gt;As actual coding is central to our work, we require and test the ability to both write code on the spot, and to come up with clean design.&lt;/p&gt;

&lt;p&gt;These expectations can be grouped into four main pillars that a candidate will be evaluated on:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Mindset&lt;/strong&gt; – able and willing to both acquire and transfer knowledge inside a team&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Knowledge&lt;/strong&gt; – possesses the core knowledge needed for using the languages and tools we use&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clean Design&lt;/strong&gt; – able to employ industry standards to come up with simple solutions that can be understood by others&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Coding Fluency&lt;/strong&gt; – can easily transfer requirements into code and coding is a natural process&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--s62NWAgz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/3vvvhcne4qahnsuchrse.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--s62NWAgz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/3vvvhcne4qahnsuchrse.png" alt="Pillars"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Recruiting Process
&lt;/h2&gt;

&lt;p&gt;To get to work with us, a candidate goes through a process designed to validate our main pillars. All this while giving them plenty of time to get to know us and have all their questions answered.&lt;/p&gt;

&lt;p&gt;It starts with a short call with HR, followed by a simple home coding assignment. Next there is a quick technical screening call. If all is successful so far, we finish it up with an in-person meeting where we take 1-2 hours to get to know each other better.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Coding Assignment
&lt;/h3&gt;

&lt;p&gt;Counting mostly for the Clean Design pillar, we start our process with a coding assignment that we send to applicants. This is meant to allow them to show how they would solve normally a problem in their day-to-day work. It can be done at home with little time pressure, as it is estimated to take a couple of hours, and it can be delivered within the next 10 days.&lt;/p&gt;

&lt;p&gt;The solution to this would potentially fit into a few lines of code. But since the requirement is to treat it as a realistic assignment, we are expecting something a bit more elaborate. We are particularly interested in how well the design reflects the requirements and the usage of clean OOP and language features, the correctness of the result (including edge cases), and tests.&lt;/p&gt;

&lt;p&gt;We value everyone’s time and we don’t want unnecessary effort invested into this. We definitely do not care about features that were not asked for, overly engineered user interfaces or formatting, or usage of design patterns just for the sake of showcasing their knowledge.&lt;/p&gt;

&lt;p&gt;It will ideally be complex enough to reflect the requirements in code, but simple enough that anyone can understand the implementation without explanations.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Tech Screening
&lt;/h3&gt;

&lt;p&gt;To test the Knowledge pillar we continue with a Skype or a regular phone call. This step was designed for efficiency. By timeboxing to 30 minutes we make sure everyone has time for it, even on short notice. We don’t want to lose the interest of good candidates getting lost in a scheduling maze.&lt;/p&gt;

&lt;p&gt;Even if it’s short, this call ensures for us a considerably higher match rate for the in-person interview. In time we found that there really are just a handful of fundamental concepts that we expect a new colleague to already know. Many of the other can quickly be learned by any competent programmer.&lt;/p&gt;

&lt;p&gt;All topics covered in this screening are objectively answerable. So at the end of a successful round we can make the invitation for the next step.&lt;/p&gt;

&lt;h3&gt;
  
  
  In-Person Interview
&lt;/h3&gt;

&lt;p&gt;This is when we really get to know each other. This is ideally done at our office in central Munich – easier for people already close by, but equally doable for those coming from afar.&lt;/p&gt;

&lt;p&gt;In this meeting we start by introducing ourselves to each other and sharing some information about the team and the company in general.&lt;/p&gt;

&lt;p&gt;Next we ask about the candidate’s previous work experience. With this and the overall way our dialog progresses we want to check the Mindset pillar and ensure that the potential new colleague fits well into our team.&lt;/p&gt;

&lt;p&gt;After that we will go into a new round of “questioning” to deeper test the Knowledge pillar. Similar to the Tech Screening, but this time open-ended. Informed opinions are expected and valued. We definitely want to talk about REST, microservices, web security, design patterns and OOP in general, or even agile processes.&lt;/p&gt;

&lt;p&gt;Then comes the fun part. We get to write some code. Well… mostly the candidate writes it, but we can also help. We go through a few mostly straight forward coding problems that can be solved on the spot. We are not looking for obscure PHP function knowledge, bullet-proof code, or anything ready to be released. We just want to see how a new problem is tackled and make sure that writing code comes as something natural to the candidate. With this we cover the Coding Fluency pillar.&lt;/p&gt;

&lt;p&gt;Afterwards it’s the interviewee’s turn. We take our time to answer any questions they may have. They get a chance to meet someone from another team and get a tour of the office.&lt;/p&gt;

&lt;h3&gt;
  
  
  What’s next?
&lt;/h3&gt;

&lt;p&gt;The interviewers consult and if there is a unanimous “hire” decision, we send an offer. In any case, as soon as possible (usually a few days) we inform the candidate of the outcome.&lt;/p&gt;

</description>
      <category>php</category>
      <category>ddd</category>
      <category>culture</category>
      <category>career</category>
    </item>
    <item>
      <title>Why we switched from Moment.js to Day.js?</title>
      <dc:creator>Tome Pejoski</dc:creator>
      <pubDate>Wed, 12 Jun 2019 14:35:15 +0000</pubDate>
      <link>https://dev.to/ottonova/why-we-switched-from-moment-js-to-day-js-4nn8</link>
      <guid>https://dev.to/ottonova/why-we-switched-from-moment-js-to-day-js-4nn8</guid>
      <description>&lt;p&gt;&lt;a href="https://momentjs.com"&gt;Moment.js&lt;/a&gt; is an awesome library when it comes to performing complex date-time manipulations. It provides a rich and clean API that covers many use cases. That aside, Moment.js shouldn’t always be the go-to library when it comes to date-time problematics. Alternatives should be considered as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are the alternatives?
&lt;/h2&gt;

&lt;p&gt;Actually, there are plenty of alternatives out there:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/iamkun/dayjs"&gt;Day.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://moment.github.io/luxon/"&gt;Luxon&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://date-fns.org/"&gt;Date-Fns&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://js-joda.github.io/js-joda/"&gt;JS-Joda&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date"&gt;Native Date&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why we picked Day.js?
&lt;/h2&gt;

&lt;p&gt;This decision bases on two reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;em&gt;Lightweight&lt;/em&gt; - only &lt;strong&gt;2.6KB&lt;/strong&gt; gzip&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Similar API to Moment.js&lt;/em&gt; - which means easier migration&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  How the migration went?
&lt;/h2&gt;

&lt;p&gt;All date-time functions, used in our apps, are located in one service, called &lt;code&gt;date.service.ts&lt;/code&gt;. So, the migration of this service, made the switch possible for us.&lt;br&gt;
In general, having the date-time manipulation centralised in one place is a good practice. Additionally makes changes like this one possible without much effort.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a&gt;&lt;/a&gt;The migration process
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Make sure that the service is 100% covered with unit tests&lt;/li&gt;
&lt;li&gt;Check if all Moment.js API usages are available in Day.js&lt;/li&gt;
&lt;li&gt;Replace Moment.js with Day.js in the &lt;code&gt;package.json&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Adjust the service to use Day.js&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Step 1. was an easy one. We just wrote the missing unit tests for our service.&lt;br&gt;
In general, test coverage of utility functions should always be high.&lt;/p&gt;

&lt;p&gt;In Step 2. we found out that the following changes were necessary:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Object instantiation
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Moment.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;moment&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;day&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;moment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2019-07-12&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Day.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dayjs&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;day&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dayjs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2019-07-12&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Second parameter in &lt;code&gt;diff&lt;/code&gt; is &lt;em&gt;plural&lt;/em&gt; in Moment.js, but &lt;em&gt;singular&lt;/em&gt; in Day.js
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Moment.js&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;date1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;moment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2019-07-11&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;date2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;moment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2019-07-10&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;date1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;diff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;years&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 0&lt;/span&gt;
&lt;span class="nx"&gt;date1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;diff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;days&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Day.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;date1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dayjs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2019-07-11&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;date2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dayjs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2019-07-10&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;date1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;diff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;year&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 0&lt;/span&gt;
&lt;span class="nx"&gt;date1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;diff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;day&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;UTC support doesn’t come out of the box with Day.js

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.npmjs.com/package/dayjs-plugin-utc"&gt;dayjs-plugin-utc&lt;/a&gt; should be installed
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Moment.js&lt;/span&gt;
&lt;span class="nx"&gt;moment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2019-07-12T15:37:01+02:00&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;utc&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;format&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;//2019-07-12T13:37:01Z&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Day.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;dayjsPluginUTC&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dayjs-plugin-utc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;dayjs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dayjsPluginUTC&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;dayjs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2019-07-12T15:37:01+02:00&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;utc&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;format&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;//2019-07-12T13:37:01Z&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;months()&lt;/code&gt; doesn't exists in Day.js
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Moment.js&lt;/span&gt;
&lt;span class="nx"&gt;moment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;months&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// ['January', 'February', ... , 'December' ]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Day.js&lt;/span&gt;
&lt;span class="nx"&gt;dayjs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;months&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// dayjs.months is not a function&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The APIs are mostly compatible. Finding these key differences between the libraries helped us tackling all the issues in Step 3. and Step 4.&lt;/p&gt;

&lt;p&gt;All other changes were specifically related to our business logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  How our bundle changed?
&lt;/h2&gt;

&lt;p&gt;The migration confirmed our intentions. Our bundle is &lt;strong&gt;60KB&lt;/strong&gt; (~10%) lighter.&lt;br&gt;
Gzipped size of Moment.js was 72.47KB and now of Day.js is 3.14KB (including locale and UTC plugin)&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;So far, switching to Day.js seems like a great decision. We haven't run into any issues since our migration, one month ago.&lt;/p&gt;

&lt;p&gt;The goal of this blog post is not to convince you that Day.js is &lt;em&gt;awesome&lt;/em&gt; and Moment.js is &lt;em&gt;terrible&lt;/em&gt;. But to remind you that choosing a date-time library is not an easy task.&lt;br&gt;
There are many options available, so take your time and find out which one might be the best for your apps and needs.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>momentjs</category>
      <category>dayjs</category>
      <category>datetime</category>
    </item>
  </channel>
</rss>
