<?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: Leonardo Teteo</title>
    <description>The latest articles on DEV Community by Leonardo Teteo (@leoat12).</description>
    <link>https://dev.to/leoat12</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F97835%2F6cef4276-9394-4906-ba9c-73e4ba8ba658.jpeg</url>
      <title>DEV Community: Leonardo Teteo</title>
      <link>https://dev.to/leoat12</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/leoat12"/>
    <language>en</language>
    <item>
      <title>What is a good documentation for you and what tools do you use?</title>
      <dc:creator>Leonardo Teteo</dc:creator>
      <pubDate>Wed, 15 Apr 2020 01:37:52 +0000</pubDate>
      <link>https://dev.to/leoat12/what-is-a-good-documentation-for-you-and-what-tools-do-you-use-2lf1</link>
      <guid>https://dev.to/leoat12/what-is-a-good-documentation-for-you-and-what-tools-do-you-use-2lf1</guid>
      <description>&lt;p&gt;It seems documentation never gets the love its deserve for our own good and there are many tools for that, although I'm still looking for the right one. &lt;/p&gt;

&lt;p&gt;What are the ones that make part of you guys pipelines? &lt;/p&gt;

</description>
      <category>discuss</category>
      <category>documentation</category>
    </item>
    <item>
      <title>Thoughts about quarantine and remote working after 15 days </title>
      <dc:creator>Leonardo Teteo</dc:creator>
      <pubDate>Tue, 07 Apr 2020 21:18:45 +0000</pubDate>
      <link>https://dev.to/leoat12/thoughts-about-quarantine-and-remote-working-after-15-days-ae6</link>
      <guid>https://dev.to/leoat12/thoughts-about-quarantine-and-remote-working-after-15-days-ae6</guid>
      <description>&lt;p&gt;With the crisis of the new coronavirus (COVID-19), it is never enough nowadays the recommendation to stay at home as much as possible to avoid infecting yourself and others. Here in Brazil the spread of the virus started at the beginning of March. Measures were taken immediately to prevent infection, soap and hand sanitizer flew from the shelves and it is hard to find them even now. A lock-down with only the extremely necessary opened was announced around March 18th, but the company I work advised us wisely to stay at home from Monday that week, March 16th, and I've been at home ever since. &lt;/p&gt;

&lt;p&gt;The situation is serious and we all need to take it seriously, but I'm trying to stay positive, principally when it comes to remote working. There are people who really need to go out, meet people, talk face to face, etc. However, it is not like that for the majority of introverts like me. It is not like we don't like to go out at all, but it is not surprising that we generally like to stay at home more than other people, it is inside of our comfort zone. But anyway, I will stop generalizing and talk about my experience exclusively. &lt;/p&gt;

&lt;p&gt;Before this crisis I worked from home once per week and since I started doing that I found myself much more productive at home than at the office. Besides staying in my comfort zone, noises and interruptions are less likely. Besides that, I can sleep more and decrease my 2 hours in public transportation to zero! Yes, public transportation around here are cramped and slow, it is not an exaggeration to say that I spend 50% of my energy or more going to and from work. Programming is what I like to do, even in my time off, so at work is more fun than stress (I'm not saying that there is no stressful moments, there is! But often I face them as a challenge), so yes, I spend more energy on my way to work than working. So, at home I'm always 100% after a peaceful breakfast before starting. &lt;/p&gt;

&lt;p&gt;There are some interesting things that I noticed during my work remotely and even reading about remote working these days that I find interesting on how it is different and how it is advantageous to me in many ways. Some days ago I read a blog post by Martin Fowler on &lt;a href="https://martinfowler.com/articles/effective-video-calls.html"&gt;how to do effective video calls&lt;/a&gt;. At my company we don't generally do video calls, we keep with just audio, although the meeting app has this feature, of course. However, some rules apply also to audio calls, principally two that go well together: &lt;strong&gt;Mute when you are not talking&lt;/strong&gt; and &lt;strong&gt;Don't talk over people&lt;/strong&gt;. This is &lt;strong&gt;HUGE&lt;/strong&gt; for an introvert like me. People may think it is an exaggeration, but there are differences in tone of voice and how people behave in meetings and all that. Extroverts are generally the center of attention, they talk a lot and loud, in live meetings people have more freedom to talk over one another and still being understood. People who are introverts, or who are not even introverts, but just have a low tone of voice, are generally overwhelmed.&lt;/p&gt;

&lt;p&gt;On video/audio calls the microfones are not that forgiving, people talking over one another is a complete mess, you don't understand anything, so people have to speak one at a time. The participants have to mute and unmute all the time, this also slows the reactions and things get more organized. Also, people tend to be more concise and avoid small talks. In the end, meetings get shorter, more productive and more people are heard. It is a win-win situation in my point of view. &lt;/p&gt;

&lt;p&gt;Overall it has been a great experience for me, but I'm aware that this is an extreme case and if things keep that way for long, it will start to get a little boring. Even when you work remotely, sometimes you go out of your house to work at a cafe your something, to change the scenario, this is impossible right now. Let's hope that we can win this battle against the virus soon and companies improve their remote working policies after this great, but unintended, experiment!&lt;/p&gt;

&lt;p&gt;Last, but not least, we have to remember the privilege that we have by being able to work from home, there are people who don't have this privilege and are suffering greatly and we need to put them on our thoughts and prayers. We have this privilege, but with it comes great responsibilities. Now than ever before the technology is connecting people, making them see they are not alone even in this crisis. We from IT are working to keep everything running: messaging apps, streaming apps, news sites, social media, etc. I'm proud and humbled to be able to be part of this great team that is keeping everything running so that people stay connected and entertained in the middle of this crisis. We are going to defeat this virus together! :)  &lt;/p&gt;

</description>
      <category>remoteworking</category>
      <category>career</category>
    </item>
    <item>
      <title>Building an URL Shortening API with Spring WebFlux (and a lot of supporting cast)</title>
      <dc:creator>Leonardo Teteo</dc:creator>
      <pubDate>Sat, 04 Apr 2020 15:12:20 +0000</pubDate>
      <link>https://dev.to/leoat12/building-an-url-shortening-api-with-spring-webflux-and-a-lot-of-supporting-cast-3ni8</link>
      <guid>https://dev.to/leoat12/building-an-url-shortening-api-with-spring-webflux-and-a-lot-of-supporting-cast-3ni8</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In the past few weeks and specially the last few days with the recommendation to stay at home due to the pandemic crisis we are fighting against (stay at home, guys! it is never an exaggeration this recommendation), I've been reading a lot of articles and experimenting with new technologies. On one of those occasions I came across this &lt;a href="https://dzone.com/articles/how-a-url-shortening-application-works" rel="noopener noreferrer"&gt;great article&lt;/a&gt; by &lt;a href="https://dzone.com/users/4169695/sunilkrpv.html" rel="noopener noreferrer"&gt;Sunil P V&lt;/a&gt; about how a URL shortening application works and after reading it and seeing the architecture I thought that developing it would be a great way to pass time. I wrote before about how I struggle at having ideas for practice projects &lt;a href="https://dev.to/leoat12/do-you-make-the-same-project-with-two-or-more-frameworks-languages-just-to-practice-13om"&gt;here&lt;/a&gt; and &lt;a href="https://dev.to/leoat12/what-do-you-do-to-practice-new-programming-languages-andor-frameworks-1122"&gt;here&lt;/a&gt;, so it sounded reasonable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Explaining the Architecture
&lt;/h2&gt;

&lt;p&gt;Borrowing the diagram that Sunil P V has in his article I will explain the technologies I used to develop the project and why. First, let's see the diagram:&lt;/p&gt;

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

&lt;p&gt;Every URL shortening application I've seen so far works similarly. When the user sends a long URL, the API generates a short hash that identifies the long URL and saves both information into a database, then when the user requests for &lt;code&gt;sho.rt/hash&lt;/code&gt; the API gets the hash and the long URL represented by it and redirects to that URL. Easy enough. &lt;/p&gt;

&lt;p&gt;The most important part of the architecture is the API itself, represented by the green box in the diagram, this API is supposed to have many instances behind a load balancer, which means it needs to be distributed. We have the database where the URL information is persisted, Redis for caching purposes and Zookeeper for coordination. Let's go into more details:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;URL Shortening API&lt;/strong&gt;: The API needs to be distributed and resilient. Since it was a project made to practice new things, I mixed things I know (Spring) and a subject I wanted to experiment for some time (WebFlux), and so the application is made with Spring WebFlux as its base. A small load test done with Apache JMeter suggests that thanks to its non-blocking approach it is much more resilient than plain old Spring MVC in high load. In addition to that, the architecture suggests the use of the library &lt;strong&gt;Hashids&lt;/strong&gt; to generate the hashes for the URL, I followed this recommendation, more on that later. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Database&lt;/strong&gt;: The database described by Sunil P V in this article is DynamoDB, but it also mentions relational databases. I decided to use a relational database for the easy setup (no need for cloud configuration, etc.) and because it also offered me another opportunity to experiment. Since the application itself was reactive and non-blocking, the remaining of the components must be as well to take full advantage of its benefits. As such, I decided to use PostgreSQL with its reactive driver and powered by Spring R2DBC. Spring R2DBC makes the use of its repositories a smooth sailing for anybody who used Spring Data JPA before, so it was not that new, but it is great that both controller and data layers talk the same language with &lt;code&gt;Mono&lt;/code&gt; and &lt;code&gt;Flux&lt;/code&gt; all over. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Redis&lt;/strong&gt;: This is the easiest part to explain, not only because it is recommended in the architecture, but also because it is almost the standard for caching nowadays. It is used to cache the short url x long url relation so that it doesn't burden the database with numerous GETs for the same URL, basic caching. Spring also offers a reactive implementation for Redis, so it is a great idea to use it into the architecture.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Zookeeper&lt;/strong&gt;: Maybe this is an overhead, although the article mentions Zookeeper specifically, it also says that it could be replaced by Redis. Zookeeper is just used to store a counter that it is shared by all instances of the API, which is used to generate the range of ids a given instance will be responsible for. Let me know what you think about this, since it is something that's new for me. First time ever I used Zookeeper. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The code can be found &lt;a href="https://github.com/Leoat12/url-shortening-api" rel="noopener noreferrer"&gt;here&lt;/a&gt; and it also has some optional features that I was experimenting with such as tracing with Zipkin and metrics export to Elasticsearch. Since it does not make part of the core, I will not talk about it here, but feel free to enable them if you want.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code Details
&lt;/h2&gt;

&lt;p&gt;Lets start the code discussion by the specifics of the configuration. There are two very important beans and one for convenience that are configured. For convenience I declare a &lt;code&gt;Hashids&lt;/code&gt; bean with the salt already so that I don't need to recreate every time I use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Bean&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Hashids&lt;/span&gt; &lt;span class="nf"&gt;hashids&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Hashids&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hashIdsSalt&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then there is a pretty straightforward Redis configuration, but notice that it is Reactive. Spring Data Redis already have a connection factory ready to use, I just need to have a &lt;code&gt;ReactiveRedisTemplate&lt;/code&gt; to use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Bean&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ReactiveRedisOperations&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;redisOperations&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ReactiveRedisConnectionFactory&lt;/span&gt; &lt;span class="n"&gt;connectionFactory&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;GenericJackson2JsonRedisSerializer&lt;/span&gt; &lt;span class="n"&gt;serializer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;GenericJackson2JsonRedisSerializer&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="nc"&gt;RedisSerializationContext&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="nc"&gt;RedisSerializationContext&lt;/span&gt;&lt;span class="o"&gt;.&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;newSerializationContext&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;StringRedisSerializer&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serializer&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ReactiveRedisTemplate&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;connectionFactory&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then there is a bean called &lt;code&gt;UrlIdRange&lt;/code&gt; that is used to control the range of ids that the instance of the application is responsible. As I said before, the range is configured on Zookeeper, but every instance has its own range of ids to assign and only when it is exhausted it goes to the Zookeeper server again to get a new range. It already contacts Zookeeper to create the range on bean creation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Bean&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;UrlIdRange&lt;/span&gt; &lt;span class="nf"&gt;urlIdRange&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SharedConfigurationService&lt;/span&gt; &lt;span class="n"&gt;sharedConfigurationService&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sharedConfigurationService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getSharedCounter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;urlRangeKey&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;UrlIdRange&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With that it is a good time to explain the &lt;code&gt;SharedConfigurationService&lt;/code&gt; and the &lt;code&gt;UrlIdRange&lt;/code&gt; classes. &lt;/p&gt;

&lt;p&gt;The implementation of &lt;code&gt;SharedConfigurationService&lt;/code&gt; uses Apache Curator Framework to connect to the Zookeeper server and perform the actions on the shared counter. I will spend a little more time on this because it is something I did for the first time and suggestions on how to improve or even say that something is wrong is welcomed. The class only has one method &lt;code&gt;getSharedCounter&lt;/code&gt; and a property that gets the Zookeeper server base url from the application properties yml file. It receives a &lt;code&gt;key&lt;/code&gt; of type &lt;code&gt;String&lt;/code&gt; and then starts its processing:&lt;/p&gt;

&lt;p&gt;1 - Starts the client:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;CuratorFramework&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newClient&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;baseUrl&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RetryNTimes&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2 - Create the &lt;code&gt;SharedCount&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;SharedCount&lt;/span&gt; &lt;span class="n"&gt;sharedCounter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SharedCount&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;3 - On try-catch block, everything is done:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;sharedCounter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

  &lt;span class="nc"&gt;VersionedValue&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sharedCounter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getVersionedValue&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="o"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;sharedCounter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;trySetCount&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getValue&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sharedCounter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getVersionedValue&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;sharedCounter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;close&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;close&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getValue&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Error while starting shared counter, impossible to update counter."&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;NotAbleToUpdateCounterException&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;SharedCount&lt;/code&gt; is started and then the application get its versioned value and try to set the new value for the counter, it will only set if the values hasn't changed, otherwise it will keep trying. I did this way because I was thinking about the distributed characteristic of the application, in a high load environment collisions could happen and it would be a trouble for the management of the ids. I don't know if it is good practice or even if it is really necessary, so give me a heads up about what could go wrong or not. Then I close the counter and the client and return the value. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;UrlIdRange&lt;/code&gt; constructor is called on the bean creation with the current counter and then it does the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;UrlIdRange&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;calculateRange&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hasNext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;calculateRange&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;initialValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100_000&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;currentValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AtomicInteger&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;initialValue&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;finalValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;initialValue&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;99_999&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hasNext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The constructor calls &lt;code&gt;calculateRange&lt;/code&gt; where the calculation is done, the range is 100.000 ids, if the counter is 0, then it will be 0 to 99.999 and so on. Maybe I exaggerated a little bit on the number and it could be configurable through .yml file.&lt;/p&gt;

&lt;p&gt;With the initial configuration out of the way, it is time to dive into WebFlux. The API have two endpoints, as I've said before, one GET to find the URL and redirect and a POST to generate new short URLs. The router is very simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Bean&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;RouterFunction&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ServerResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;UrlInfoHandler&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ErrorHandler&lt;/span&gt; &lt;span class="n"&gt;errorHandler&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;RouterFunctions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;route&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;onError&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Exception&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;errorHandler:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;handleError&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;GET&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/{url}"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;handler:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;findLongUrlAndRedirect&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;POST&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;accept&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MediaType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;APPLICATION_JSON&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="nl"&gt;handler:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;generateAndSaveShortUrl&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;People may find the &lt;code&gt;@RequestMapping&lt;/code&gt; annotation from Spring MVC convenient, but I think a router function like this where all routes are defined in one place also has its advantages, it is much easier to see what routes are available and Spring gives some features to keep it organized in large applications. Since Spring Boot is made for microservices, which shouldn't have many routes per application anyway, it is not a problem.&lt;/p&gt;

&lt;p&gt;Then we have the &lt;code&gt;UrlInfoHandler&lt;/code&gt; where the fun happens. It is very interesting and maybe a bit overwhelming to face declarative programming for the first time, but since I had some experience already with Javascript and its declarative, non-blocking style, it was not so bad, but certainly I need to show to some of colleagues later to see if they understand what is happening. Let's start with the &lt;code&gt;findLongUrlAndRedirect&lt;/code&gt; method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Mono&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ServerResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;findLongUrlAndRedirect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ServerRequest&lt;/span&gt; &lt;span class="n"&gt;serverRequest&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;shortUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;serverRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;pathVariable&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"url"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;cacheService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getFromCacheOrSupplier&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shortUrl&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;UrlInfo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;urlInfoService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findByShortUrl&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shortUrl&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
          &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;doOnNext&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;urlInfo&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"UrlInfo found: {}"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;urlInfo&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
          &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;flatMap&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;urlInfo&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;permanentRedirect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;URI&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;urlInfo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getLongUrl&lt;/span&gt;&lt;span class="o"&gt;())).&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
          &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;switchIfEmpty&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpStatus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;NOT_FOUND&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;bodyValue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ErrorResponse&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;notFound&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shortUrl&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ErrorCode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;URL_INFO_NOT_FOUND&lt;/span&gt;&lt;span class="o"&gt;)));&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I get the &lt;code&gt;shortUrl&lt;/code&gt; from the request and the magic begins. First I go to the &lt;code&gt;cacheService&lt;/code&gt; to see if the &lt;code&gt;UrlInfo&lt;/code&gt; is already there, if not, the &lt;code&gt;Supplier&lt;/code&gt; given is called. Since the reactive approach of Redis cache in Spring is not supported by @Cacheable and its ease, as far as I know, I decided to use this approach. Maybe I could use AOP, but I thought that this way matched well with the rest of the code, full of lambda functions, or &lt;strong&gt;Functional Interfaces&lt;/strong&gt;, as it is described in Java. Then I call a &lt;code&gt;doOnNext()&lt;/code&gt; just for logging purposes, and then a &lt;code&gt;flatMap&lt;/code&gt; redirecting. If empty, the application responds with a 404 status. The method that generates a short url works similarly in the reactive sense although different in logic, you can take a look in the code at the &lt;a href="https://github.com/Leoat12/url-shortening-api" rel="noopener noreferrer"&gt;repository&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;The implementation of &lt;code&gt;CacheService&lt;/code&gt; is interesting because it leverages Reactor's features exclusive for caching:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Mono&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getFromCacheOrSupplier&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Class&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;clazz&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Supplier&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Mono&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;orElseGet&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;CacheMono&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lookup&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;redisOps&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;opsForValue&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buildKey&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;clazz&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
                  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Signal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;next&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clazz&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;cast&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;))),&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
          &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;onCacheMissResume&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orElseGet&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
          &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;andWriteWith&lt;/span&gt;&lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Mono&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fromRunnable&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
                  &lt;span class="n"&gt;redisOps&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;opsForValue&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;setIfAbsent&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buildKey&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;clazz&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;()).&lt;/span&gt;&lt;span class="na"&gt;subscribe&lt;/span&gt;&lt;span class="o"&gt;()));&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using &lt;code&gt;CacheMono&lt;/code&gt; I can get reactive control flow exclusive for caching, it also made possible the usage of my supplier in such a smooth way using &lt;code&gt;onCacheMissResume&lt;/code&gt;. But first it uses the &lt;code&gt;lookup&lt;/code&gt; method to call Redis with the given key, very straightforward since Redis reactive interfaces have the same usage as the blocking ones, but delivering a &lt;code&gt;Mono&amp;lt;T&amp;gt;&lt;/code&gt; to us. Finally, in case of miss, the value is cached using &lt;code&gt;andWriteWith&lt;/code&gt;. In any way, the object is returned to us, continuing the flow. Very interesting logic and please tell me if there is anything to improve!&lt;/p&gt;

&lt;p&gt;Despite not getting into details about the POST route, it is interesting to see the implementation of &lt;code&gt;saveIfNotExists&lt;/code&gt; from the &lt;code&gt;UrlInfoService&lt;/code&gt;, which is called by the handler to generate the short url and save, but only if it does not exist, the chain of three methods is called:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Tries to find the long url, if empty, save the request&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Mono&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;UrlInfo&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;saveIfNotExist&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;UrlGenerateRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;findByLongUrl&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getLongUrl&lt;/span&gt;&lt;span class="o"&gt;()).&lt;/span&gt;&lt;span class="na"&gt;switchIfEmpty&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// This is where hashids comes into play, encoding the id given by url range&lt;/span&gt;
&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Mono&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;UrlInfo&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;UrlGenerateRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getUrlId&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
  &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hashids&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;encode&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;urlInfoRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
          &lt;span class="nc"&gt;UrlInfo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;longUrl&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getLongUrl&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
                  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;shortUrl&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hash&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;expiryAt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getExpiryAt&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
                  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
  &lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Get the current value of the range and deals with range shortage as well&lt;/span&gt;
&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="nf"&gt;getUrlId&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;urlIdRange&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hasNext&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sharedConfigurationService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getSharedCounter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;urlRangeKey&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;urlIdRange&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;calculateRange&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;urlIdRange&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getCurrentValue&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The last important part that is left to be mentioned is the data layer using R2DBC. This is also very straightforward since Spring Data R2DBC repositories doesn't differ much from the standard, differing only by returning &lt;code&gt;Mono&lt;/code&gt; or &lt;code&gt;Flux&lt;/code&gt;. One thing I noticed though is that I didn't find a way to map table relationships on R2DBC, there is no javax annotations or Hibernate annotations, of course, for that stuff and I didn't find any reference to that on the documentation. However, I may be mistaken. Let me know if you know anything about that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;It was a really enjoyable experience to get a diagram of an application architecture, add your own ideas and materialize it in code. I hope I can find more articles of this type in the future. There was other experiments I didn't mention here such as documentation and testing, take a look at the &lt;a href="https://github.com/Leoat12/url-shortening-api" rel="noopener noreferrer"&gt;repository&lt;/a&gt; to see what I did about that, I will probably write another post about it. Thank you for all who reached the end of the post (it was a long one) and let me hear what you think! &lt;/p&gt;

</description>
      <category>java</category>
      <category>spring</category>
      <category>webflux</category>
      <category>api</category>
    </item>
    <item>
      <title>A love letter to TypeScript</title>
      <dc:creator>Leonardo Teteo</dc:creator>
      <pubDate>Wed, 07 Aug 2019 02:08:43 +0000</pubDate>
      <link>https://dev.to/leoat12/a-love-letter-to-typescript-56o0</link>
      <guid>https://dev.to/leoat12/a-love-letter-to-typescript-56o0</guid>
      <description>&lt;p&gt;Dear TypeScript, I know that your brother JavaScript sometimes may not want to see us together, but I think your qualities are worth it, that's why I love you! &lt;/p&gt;

&lt;p&gt;Jokes apart, this is really a post that I have been desiring to write for a long time since I started to actually study the many features that TypeScript have and how wonderful it is. The code in the cover image is not just for show, in a simple example like that I can show many reasons why I'm in love with TypeScript and I want to use it as much as possible from now on. Therefore, without further ado, let's go write this love letter bit by bit. &lt;/p&gt;

&lt;p&gt;When we talk about JavaScript we always think about flexibility. It confers a lot of flexibility in the way you write code, JavaScript is very permissive, you can add fields in objects, remove fields, functions can be passed as parameters, arrays can hold elements of any "type" (JavaScript has a very loose concept of type). However, all this flexibility has a cost. When I see a application with more than 100 lines and 1 file written in JavaScript it always looks a mess to me, no offense. I don't know from where things comes from and where they go. It is like stepping into a minefield. My background is from Java, where you have control of almost everything you code, way too much control sometimes. &lt;/p&gt;

&lt;p&gt;That's where TypeScript comes to play, it mixes the flexibility of JavaScript, but putting it at bay with the control that static typed languages offer. For me, it have the best of two worlds: JavaScript and Java (never confuse them). So, let's go to the example. First, the &lt;code&gt;Letter&lt;/code&gt; interface.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Letter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Okay, pretty normal, right? One thing that I like in interfaces in TypeScript is that you can have both properties and methods defined and the class that will implement them will need to have all these properties to satisfy it. It is different in Java, where "properties" are in the end constants inside an interface, they are not properties. Interfaces in TypeScript, however, show their power along with other classes. So, we present below the &lt;code&gt;LoveLetter&lt;/code&gt; class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;LoveLetter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`I love you, &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Just by looking at the class you may not realize it if you don't know TypeScript wonderfulness, but this class completely satisfies the &lt;code&gt;Letter&lt;/code&gt; interface, 100%! First, the constructor. In Java it is always annoying to have to add parameters and assign them to the class properties right after, it is unnecessary boilerplate! I love TypeScript approach where by inserting &lt;code&gt;public&lt;/code&gt;, &lt;code&gt;private&lt;/code&gt;, etc. to the constructor's parameters you are declaring a class property and assigning the parameters' value to it all in one go. Therefore, &lt;code&gt;LoveLetter&lt;/code&gt; class has the string properties &lt;code&gt;to&lt;/code&gt; and &lt;code&gt;from&lt;/code&gt; that &lt;code&gt;Letter&lt;/code&gt; requires.&lt;/p&gt;

&lt;p&gt;"But how about &lt;code&gt;message&lt;/code&gt;? In &lt;code&gt;LoveLetter&lt;/code&gt; it is a method, not a string property!", you might say. That's another very interesting feature of TypeScript: "getter methods". It can be used much like getters in Java, for example, but I think in TypeScript it has a gotcha that Java doesn't have. When you add the &lt;code&gt;get&lt;/code&gt; word before the function, TypeScript will  treat it as if it were a property! So, we can do this: &lt;code&gt;letter.message&lt;/code&gt; instead of this: &lt;code&gt;letter.message()&lt;/code&gt;. Since it is considered a property to TypeScript it is a okay to satisfy the &lt;code&gt;Letter&lt;/code&gt; interface. It is very useful when you want to shape the data in another way, for example, for visual purposes, like I did with "I love you, #name#", using string interpolation to insert the name of recipient. It may not look a big difference in a simple example, but when you are trying to satisfy some big interfaces or having more complex use cases, it comes in handy. &lt;/p&gt;

&lt;p&gt;For some who may be used to Java it may sound strange that the class implements the interface like that without any formal declaration like &lt;code&gt;class Foo implements Bar&lt;/code&gt; in Java, but it is one of the reasons why interfaces are so powerful in TypeScript, the class satisfies the interface merely by its shape, a formal declaration is not necessary. You can declare formally, however:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;LoveLetter&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;Letter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`I love you, &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The declaration is exactly like Java and that way you will have error messages at the class level if the class is not satisfying the interface, but generally you will not have to be that explicit. So, if one class satisfies an interface only by shape, then you can go to the last part of our example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sendLetter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;letter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Letter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s2"&gt;`From: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;letter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;
    To: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;letter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;

    &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;letter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;
    `&lt;/span&gt;
  &lt;span class="p"&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;loveLetter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;LoveLetter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Developer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;TypeScript&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;sendLetter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;loveLetter&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Here we have a function that is assigned to a constant and is declared as an arrow function. In this case it doesn't have any special meaning, but arrow functions can make the code more elegant, principally when TypeScript/JavaScript are the home of callbacks. Also, it can solve some concerns around scopes, principally when it comes to &lt;code&gt;this&lt;/code&gt;, but we can talk about that in the future. Then we create a new &lt;code&gt;LoveLetter&lt;/code&gt; and assign it to a constant, nothing special, but the next line show some of the power of interfaces. Although the function receives a &lt;code&gt;Letter&lt;/code&gt; as parameter, since &lt;code&gt;LoveLetter&lt;/code&gt; satisfies the interface 100% then you are good to call the function with an instance of &lt;code&gt;LoveLetter&lt;/code&gt; as well! And what it is better is that you don't need to tell TypeScript anywhere that, it  knows it automatically. Again, the interface is evaluated by its shape, if the shape is right, you are good to go! &lt;/p&gt;

&lt;p&gt;It has been very interesting to learn more about TypeScript everyday and how it fuses the things that I like the most in the languages I already know in one beautiful language. There are many other features that are worth mentioning, but I think with this simple example you can get a sense of TypeScript greatness. I believe that TypeScript has a bright future in the market and I recommend it to everybody. Don't worry, I will not get jealous by the popularity of my dear TypeScript.  &lt;/p&gt;

</description>
      <category>typescript</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Is it a good idea to use CLIs to generate projects in JavaScript?</title>
      <dc:creator>Leonardo Teteo</dc:creator>
      <pubDate>Wed, 19 Jun 2019 12:21:01 +0000</pubDate>
      <link>https://dev.to/leoat12/is-it-a-good-idea-to-use-clis-to-generate-projects-in-javascript-4en9</link>
      <guid>https://dev.to/leoat12/is-it-a-good-idea-to-use-clis-to-generate-projects-in-javascript-4en9</guid>
      <description>&lt;p&gt;When I generate a project using Angular CLI, React Native CLI or even once with VueJs it is always somewhat troublesome because sometimes they ask questions before generating the project that as a beginner, you don't understand half of what they are asking and when it is generated, there are many files you don't know what they do. &lt;/p&gt;

&lt;p&gt;I am not a total beginner in Javascript, used jQuery for years and even Angular 2+ in some personal projects. I certainly know more about Angular fundamentals like components, modules, services, dependency injection, two-way binding and so on than what all that configuration files even mean. &lt;/p&gt;

&lt;p&gt;Is it everything thing there necessary at the beginning of a project? For a true beginner who want to start quickly, it is not one more wall they need to overcome? &lt;/p&gt;

</description>
      <category>beginners</category>
      <category>help</category>
      <category>javascript</category>
    </item>
    <item>
      <title>The magic known as MySQL FULLTEXT index.</title>
      <dc:creator>Leonardo Teteo</dc:creator>
      <pubDate>Tue, 11 Jun 2019 21:03:19 +0000</pubDate>
      <link>https://dev.to/leoat12/the-magic-known-as-mysql-fulltext-index-3npj</link>
      <guid>https://dev.to/leoat12/the-magic-known-as-mysql-fulltext-index-3npj</guid>
      <description>&lt;p&gt;We developers, most of the time, are having a battle with databases about performance. It is not rare that the root of a performance problem is ingrained deep inside your query. It is a fate we must fight against everyday. This week I had to fight against it and I had some interesting results and new experiences to talk about. That was when I discovered the magic called MySQL FULLTEXT index.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;When you work in a small company we end up venturing yourself in fields that it is not necessarily your specialty, that's me as a developer dealing with databases. I'm not a DBA and for that reason I don't know all the intricacies of a database like MySQL. When a problem comes up everybody helps giving their suggestions, researching and etc. This time the problem was about performance in a search feature of an application. &lt;/p&gt;

&lt;p&gt;Giving a similar example of the use case, we have a search feature that looks for products. As expected, there are many fields in a product where you need to search to make it as accurate as possible, some of them are the name of the product, its description, info fields, some keywords, the name of the manufacturer, etc. Only with this description we can have three tables:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Products, self-explanatory&lt;/li&gt;
&lt;li&gt;Keywords, it has a separate table because we can reuse for multiple products.&lt;/li&gt;
&lt;li&gt;Manufacturer, also self-explanatory.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, the problem here was not the number of joins (there are many, more than the ones I describe in the simpler example above), but the way the fields were searched for a given search input. Initially we were using a function on the database that made use of REGEXP to look for rows that contained the search input entirely, i.e, if the input was "discount" the column must have the entire word "discount" somewhere to be brought by the database. Okay, looks inoffensive, until the moment it is not. &lt;/p&gt;

&lt;p&gt;I still don't know why, I think it would be a good reason to research about and make another post another time (if you have any idea why let me know!), but after divide every part of the query and test all of them we reached the conclusion that the use of this search method was slowing down the query enormously, like, they query was taking many seconds in a production environment, very bad news. &lt;/p&gt;

&lt;p&gt;To give some more context so that it doesn't look like it was a big mistake from our part, the system is being rebuilt, it has been running for many years and now we are reshaping the layout and practically rewriting the backend with new technologies and solutions, but we are still using the same database and many queries were not touched yet. Besides, the problem appeared recently, maybe because of the increased traffic. During tests and early months of production it was not detected, the search was performing reasonably well although we had plans to speed it up even more.      &lt;/p&gt;

&lt;h2&gt;
  
  
  The solution
&lt;/h2&gt;

&lt;p&gt;Solve the problem was not that easy due to our time and budget limitations, it would be impossible to do something outside of what we already had of infrastructure, for example, add another database just for that: we thought about Elasticsearch or even any other NoSQL database like MongoDB, some tests indicated that it would give a good performance. However, add another database to the mix added complexity, not to mention cost. Since we are rebuilding we are willing to try new technologies, but we have added Redis for caching purposes and add another database would raise the costs too much. &lt;/p&gt;

&lt;p&gt;With this limitation in mind the only thing we could was trying to make the query better in some way. The first thing we tried was to replace the REGEXP for LIKE and although the performance improved it didn't bring the search results we were expecting. At the time I didn't know FULLTEXT index existed and didn't think that MySQL had such feature, I always relate full-text search with Elasticsearch and other NoSQL databases which has this as main feature. It was when I looked for "mysql fulltext" on friend Google and it came with interesting results. &lt;/p&gt;

&lt;p&gt;Like any other index you start by creating it, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;FULLTEXT&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;product_search_index&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And then the magic begins. To use the capabilities of the FULL TEXT INDEX you can use the &lt;code&gt;MATCH ... AGAINST ...&lt;/code&gt; function, there are some modes and you choose the one best suited for your needs. I'm still studying myself about all the modes and their advantages and disadvantages, but you can find all the explanation in the &lt;a href="https://dev.mysql.com/doc/refman/8.0/en/fulltext-search.html"&gt;documentation&lt;/a&gt;, for now I will stick with &lt;code&gt;IN NATURAL LANGUAGE MODE&lt;/code&gt;, the default one and the one that best suited for my use case, coincidentally. Quoting the documentation this mode works like this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A natural language search interprets the search string as a phrase in natural  human language (a phrase in free text). There are no special operators, with the exception of double quote (") characters. The stopword list applies.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It looks for the words we are looking for as a phrase in free text. MySQL has a stopwords list that can be configured for your needs to improve the results. Then you can make a simple query to bring the results:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="k"&gt;MATCH&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;AGAINST&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'notebook off discount'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The query, then, will bring the results of the search in order of relevance. Furthermore, it is fast, really fast comparing to what we have before. We brought down the query response time from many seconds to less than 1 second most of the time. Everybody was surprised, including me, about the results. It was like magic and this makes me think I need to study this more to understand how they do this. &lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;It is impressive like everyday you can learn something new and sometimes it can turn out to be surprisingly the solution you were looking for. With that I was able to solve the problem with only the resources I already had and ultimately not overengineering the solution. &lt;/p&gt;

</description>
      <category>mysql</category>
      <category>java</category>
      <category>search</category>
      <category>dev</category>
    </item>
    <item>
      <title>Do you make the same project with two or more frameworks/languages just to practice? </title>
      <dc:creator>Leonardo Teteo</dc:creator>
      <pubDate>Mon, 10 Jun 2019 13:59:43 +0000</pubDate>
      <link>https://dev.to/leoat12/do-you-make-the-same-project-with-two-or-more-frameworks-languages-just-to-practice-13om</link>
      <guid>https://dev.to/leoat12/do-you-make-the-same-project-with-two-or-more-frameworks-languages-just-to-practice-13om</guid>
      <description>&lt;p&gt;When I come up with a project idea I always have this same dilemma. I want to use new technologies, but also to continue improving in what I know. Should I make the same project many times with different languages just to practice? &lt;/p&gt;

</description>
      <category>discuss</category>
      <category>webdev</category>
    </item>
    <item>
      <title>The Tools and Skills Needed to Tackle Microservices </title>
      <dc:creator>Leonardo Teteo</dc:creator>
      <pubDate>Wed, 05 Jun 2019 03:18:01 +0000</pubDate>
      <link>https://dev.to/leoat12/the-tools-and-skills-needed-to-tackle-microservices-46m6</link>
      <guid>https://dev.to/leoat12/the-tools-and-skills-needed-to-tackle-microservices-46m6</guid>
      <description>&lt;p&gt;It is almost 2 years since I started to develop professionally and really understand the challenges that it comes with building and maintaining services up and running 24/7 without breaks. Since then, I became fascinated to the concept of microservices. It looks so simple, the old divide and conquer, but brilliant. However, it comes with a lot of challenges as well and many tools to tackle these challenges. That's where my question is born. &lt;strong&gt;What are the tools you use to build your microservices architecture?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It seems a question that I could easily Google it and get some answers. I did it sometimes, even listening to other companies infrastructure. A lot of them talk about Kubernetes as a mean to deploy microservices. Others deal with communication, which seems a real challenge in microservices, like Kafka and other messaging or data streaming tools. Service discovery and circuit breaker are some names I read as well. On the Java world, where I live most of my time, there are Netflix OSS with Eureka, Feign, and others. It is a myriad of tools and begs the question about what do you use and your stories with those tools. &lt;/p&gt;

&lt;p&gt;Furthermore, all stories we hear about microservices deployments is from big companies where the infrastructure is massive and it sounds impossible to practice with those tools unless you are already in a company with such a massive infrastructure. Am I wrong? &lt;strong&gt;How do you practice with those tools to understand them well?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I understand that most of the tools used depends on the user case, but that's why I asking here! I hope we can gather a lot of different stories of all shapes and sizes! So, let the talks begin! :D    &lt;/p&gt;

</description>
      <category>discuss</category>
      <category>microservices</category>
      <category>dev</category>
      <category>devops</category>
    </item>
    <item>
      <title>What do you do to practice new programming languages and/or frameworks?</title>
      <dc:creator>Leonardo Teteo</dc:creator>
      <pubDate>Sun, 20 Jan 2019 13:34:13 +0000</pubDate>
      <link>https://dev.to/leoat12/what-do-you-do-to-practice-new-programming-languages-andor-frameworks-1122</link>
      <guid>https://dev.to/leoat12/what-do-you-do-to-practice-new-programming-languages-andor-frameworks-1122</guid>
      <description>&lt;p&gt;I've been struggling with this problem for a while now. I'm curious, I like to experiment new things, be it languages or frameworks, but for that it is important to have some idea to code with. Just do the tutorials is not enough for me, it is generally too easy, so I need something more real to practice. However, I don't have much creativity to projects. I try to think about some problem that I may have and would like to automate or something linked with my hobbies that would be nice to create. I do have some projects slowly evolving, but since they are a little more complex, I tend to use things I'm already fairly familiar with, so it doesn't count. I also try to find open source projects on GitHub that I could contribute, but the well kept ones are generally too hard for someone who wants to practice the basics, it is intimidating.  &lt;/p&gt;

&lt;p&gt;So, the question is, what to do when you want to practice something, but doesn't have an idea of project to try it on? There are sites that can help with that? Front-end, back-end or both. What do you do when you are in this kind of situation? &lt;/p&gt;

</description>
      <category>discuss</category>
      <category>programming</category>
    </item>
    <item>
      <title>Building Twitter layout with Flutter</title>
      <dc:creator>Leonardo Teteo</dc:creator>
      <pubDate>Sun, 13 Jan 2019 18:30:34 +0000</pubDate>
      <link>https://dev.to/leoat12/building-twitter-layout-with-flutter-363g</link>
      <guid>https://dev.to/leoat12/building-twitter-layout-with-flutter-363g</guid>
      <description>&lt;p&gt;Flutter is the new shiny framework for mobile development by Google, it was first released last year and this month it reached the 1.0 version. I've known Flutter for some months now, but since it reached 1.0 I decided to take a deeper look at it. I've developed mobile applications before using native Android with Java and cross-platform with Xamarim and NativeScript, it was not anything serious, but it is an area I find interesting and some people can argue, it is the near future. &lt;/p&gt;

&lt;p&gt;Presentations done, now let's go to the juicy details. In my opinion, the most remarkable feature of Flutter is how easy it is to understand its layouts mechanics. Basically, everything is a widget and you can put a widget anywhere you want. The widgets are very descriptive, have attributes that cover almost all common usages, it is effortless and simple to build a layout. Since everything is a widget, the framework is very permissive, dynamic and logical, you have no fear of doing something wrong, just do it, and with hot reload as fast a blink you can test everything easily. &lt;/p&gt;

&lt;p&gt;My experience with Flutter is amateur level, I did the most basic tutorial on &lt;a href="https://flutter.io" rel="noopener noreferrer"&gt;Flutter website&lt;/a&gt;, read some things about how Flutter handles layouts, principally &lt;a href="https://flutter.io/docs/development/ui/layout" rel="noopener noreferrer"&gt;this great article&lt;/a&gt; that summarizes everything you need to know about Flutter layout structure. I would never dare to try replicate Twitter layout in none of the aforementioned frameworks, but with Flutter I had enough confidence to do it because I had no fear of failure. &lt;/p&gt;

&lt;p&gt;So we have something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F4vshv53futqwcx8ss2w4.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F4vshv53futqwcx8ss2w4.jpg" alt="Twitter layout"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To make it simpler, I made the layout taking in consideration only simple tweets, meaning only with text, no images, quotes, etc. Just to start. However, the rest will be present, the app bar at the top, the floating button to tweet and the bottom bar with tabs. Does it look too complex? Divide and conquer is the best approach for that! &lt;/p&gt;

&lt;p&gt;First, let's see the app bar at the top. We can see that we have a circle avatar and a text written "Home". An app bar is a very common design pattern in Android apps and Flutter knows that,because of that Flutter has widgets to make it easy to build one. To do that we use the &lt;code&gt;Scaffold&lt;/code&gt; widget that has a parameter called &lt;code&gt;appBar&lt;/code&gt; that accepts an &lt;code&gt;AppBar&lt;/code&gt; widget as follows:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;MaterialApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;title:&lt;/span&gt; &lt;span class="s"&gt;"Twitter Layout"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;theme:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;ThemeData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;primaryColor:&lt;/span&gt; &lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fromRGBO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;43&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="nl"&gt;accentColor:&lt;/span&gt; &lt;span class="n"&gt;Colors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;blueAccent&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nl"&gt;home:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Scaffold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nl"&gt;appBar:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;AppBar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nl"&gt;title:&lt;/span&gt; &lt;span class="n"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="nl"&gt;children:&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Widget&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;[&lt;/span&gt;
                &lt;span class="n"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                  &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;CircleAvatar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"L"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                    &lt;span class="nl"&gt;radius:&lt;/span&gt; &lt;span class="mf"&gt;15.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                  &lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="nl"&gt;margin:&lt;/span&gt; &lt;span class="n"&gt;EdgeInsets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;right:&lt;/span&gt; &lt;span class="mf"&gt;30.0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Home"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
              &lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="nl"&gt;elevation:&lt;/span&gt; &lt;span class="mf"&gt;4.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="nl"&gt;body:&lt;/span&gt; &lt;span class="n"&gt;_buildBody&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;As you can see, the &lt;code&gt;Scaffold&lt;/code&gt; widget is wrapped by a &lt;code&gt;MaterialApp&lt;/code&gt; widget that makes is it easy to build apps using &lt;a href="https://material.io" rel="noopener noreferrer"&gt;Material Design&lt;/a&gt;, design directives for Android apps by Google, which the Twitter app clearly uses. The &lt;code&gt;AppBar&lt;/code&gt; widgets has a &lt;code&gt;title&lt;/code&gt; parameter that accepts any widget, although generally it is just a &lt;code&gt;Text&lt;/code&gt; widget. Therefore, I created a &lt;code&gt;Row&lt;/code&gt; widget that is responsible to place its children aligned horizontally, the way we want in this case. We add the children of the &lt;code&gt;Row&lt;/code&gt; widget in a &lt;code&gt;children&lt;/code&gt; parameter. In this case the widget has a &lt;code&gt;Container&lt;/code&gt; and &lt;code&gt;Text&lt;/code&gt; as children. The &lt;code&gt;Container&lt;/code&gt; widget is a very convenient widget because it enables you to custom spacing, positioning and painting configurations to its child. In this case, I added a &lt;code&gt;CircleAvatar&lt;/code&gt; widget as its child and added a margin of 30 pixels to the right of the circle to give separation from the "Home" text. The child of a &lt;code&gt;CircleAvatar&lt;/code&gt; widget can be any widget, but we generally use text or an image, to make it simple I used a &lt;code&gt;Text&lt;/code&gt; with the letter "L". The radius indicates the size of the circle. If you notice, the circle on the app bar is a little smaller than the ones on the tweets, so I had to configure that. The &lt;code&gt;parameter&lt;/code&gt; on the &lt;code&gt;AppBar&lt;/code&gt; widget indicates the elevation of the app bar, it is what gives that shadow below it. In the end it was not necessary to make an app bar, a circular avatar and all the spacing configuration from the ground up, Flutter makes it easy to achieve the result you want with the use of common patterns. The &lt;code&gt;Scaffold&lt;/code&gt; widget also has a &lt;code&gt;body&lt;/code&gt; parameter, where, in this case, all the app content resides. Let's get into it. &lt;/p&gt;

&lt;p&gt;To organize the layout I made the body building logic on a &lt;code&gt;_buildBody()&lt;/code&gt; method which is as follows: &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;

&lt;span class="n"&gt;Widget&lt;/span&gt; &lt;span class="nf"&gt;_buildBody&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;children:&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Widget&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;[&lt;/span&gt;
          &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Flexible&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Scaffold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="nl"&gt;body:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;ListView&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                  &lt;span class="nl"&gt;itemBuilder:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_tweets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                  &lt;span class="nl"&gt;itemCount:&lt;/span&gt; &lt;span class="n"&gt;_tweets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                  &lt;span class="nl"&gt;reverse:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="nl"&gt;floatingActionButton:&lt;/span&gt; &lt;span class="n"&gt;FloatingActionButton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="nl"&gt;onPressed:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Icon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Icons&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;edit&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
              &lt;span class="p"&gt;)),&lt;/span&gt;
          &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nl"&gt;decoration:&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;BoxDecoration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;color:&lt;/span&gt; &lt;span class="n"&gt;Theme&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;cardColor&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;_buildTabsBar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;_buildBody()&lt;/code&gt; return a &lt;code&gt;Widget&lt;/code&gt;, which is, in this case, a &lt;code&gt;Container&lt;/code&gt;. The container has a &lt;code&gt;Column&lt;/code&gt; widget as child, which all the magic happens. In the image used as base above we can see that we have the list of tweets and right below it the tabs bar, besides the floating button. The children of the &lt;code&gt;Column&lt;/code&gt; widget are placed the way they appear on the screen. First, we have a &lt;code&gt;Flexible&lt;/code&gt; widget and, as the names suggests, it is flexible, meaning in this case that it will occupy the remaining of the space of the parent, this is where our list and floating button are. The &lt;code&gt;Flexible&lt;/code&gt; widget child is a &lt;code&gt;Scaffold&lt;/code&gt; widget. Nobody said that it can be used only was the main widget of a an app like we used before although it is very common that way. It is used here to facilitate the creation of the floating button since it has a &lt;code&gt;floatingActionButton&lt;/code&gt; attribute, which takes a &lt;code&gt;FloatingActionButton&lt;/code&gt; widget with an edit icon as child. It also has an &lt;code&gt;onPressed&lt;/code&gt; attribute to configure the event, but since the goal here is just to make the layout, it is &lt;code&gt;null&lt;/code&gt; for now. Only this will make the floating button appear exactly where we want it. As before, on the &lt;code&gt;body&lt;/code&gt; parameter of he &lt;code&gt;Scaffold&lt;/code&gt; widget, we have the main content, the list of tweets, that is implemented using &lt;code&gt;ListView&lt;/code&gt;, which is kind of a specialized column that enables scrolling when the content does not fit entirely in the widget. It simply builds the list from a list tweets, which we will see later. &lt;/p&gt;

&lt;p&gt;For now, let's focus on the other child of the &lt;code&gt;Column&lt;/code&gt;, the container which has the method &lt;code&gt;_buildTabsBar()&lt;/code&gt; as child. Let's see how the tabs are structured. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;

&lt;span class="n"&gt;Widget&lt;/span&gt; &lt;span class="nf"&gt;_buildTabsBar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;height:&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;color:&lt;/span&gt; &lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fromRGBO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;43&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;mainAxisAlignment:&lt;/span&gt; &lt;span class="n"&gt;MainAxisAlignment&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;spaceEvenly&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;children:&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Widget&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;[&lt;/span&gt;
          &lt;span class="n"&gt;Icon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Icons&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;home&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;color:&lt;/span&gt; &lt;span class="n"&gt;Theme&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;accentColor&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="n"&gt;Icon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Icons&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;search&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;color:&lt;/span&gt; &lt;span class="n"&gt;Colors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;grey&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
          &lt;span class="n"&gt;Icon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Icons&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;notifications_none&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;color:&lt;/span&gt; &lt;span class="n"&gt;Colors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;grey&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
          &lt;span class="n"&gt;Icon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Icons&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;mail_outline&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;color:&lt;/span&gt; &lt;span class="n"&gt;Colors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;grey&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Making the bar is very simple and that's what makes it fantastic. It is just a &lt;code&gt;Container&lt;/code&gt; with a &lt;code&gt;Row&lt;/code&gt; as child that has the icons as children, that's it. I configure the height of the container and its color. Then, in the &lt;code&gt;Row&lt;/code&gt; I used the &lt;code&gt;mainAxisAlignment&lt;/code&gt; attribute to make the space be evenly distributed between the icons making look like the original layout. I still remember how it is a pain to center things using HTML and CSS, not to mention make the space even.&lt;/p&gt;

&lt;p&gt;So, let's see the last part, the tweet. It looks like the part where there are more elements to take care of and it is right, but it is not that much more complex than the rest of the layout if you visualize it as a collection of rows and columns. To make the tweet reusable and easy to use in a &lt;code&gt;ListView&lt;/code&gt; I created a &lt;code&gt;Tweet&lt;/code&gt; class containing all the layout for the tweet:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Tweet&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;StatelessWidget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="n"&gt;Tweet&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;userHandle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;userHandle&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;Widget&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BuildContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;padding:&lt;/span&gt; &lt;span class="n"&gt;EdgeInsets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;10.0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nl"&gt;decoration:&lt;/span&gt; &lt;span class="n"&gt;BoxDecoration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nl"&gt;color:&lt;/span&gt; &lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fromRGBO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;43&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="nl"&gt;border:&lt;/span&gt; &lt;span class="n"&gt;Border&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;bottom:&lt;/span&gt; &lt;span class="n"&gt;BorderSide&lt;/span&gt;&lt;span class="p"&gt;())),&lt;/span&gt;
      &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;mainAxisAlignment:&lt;/span&gt; &lt;span class="n"&gt;MainAxisAlignment&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;crossAxisAlignment:&lt;/span&gt; &lt;span class="n"&gt;CrossAxisAlignment&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;children:&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Widget&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;[&lt;/span&gt;
          &lt;span class="n"&gt;CircleAvatar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;substring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
          &lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="n"&gt;_tweetContent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;...&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;To make it simple, it is stateless and only gets the user, user handle and the tweet text to build the tweet. A full-fledged tweet would probably be statetul because of the counts for likes, retweets and answers and have much more parameters. The &lt;code&gt;build()&lt;/code&gt; method returns a Container with the basic layout configuration, padding and a border at the bottom acting as a divider for the tweets, then it has a &lt;code&gt;Row&lt;/code&gt; as child. The row contains the circle avatar of the user who tweeted and the tweet content, which is built through a method for organization sake. &lt;code&gt;mainAxisAlignment&lt;/code&gt; and &lt;code&gt;crossAxisAlignment&lt;/code&gt; set as &lt;code&gt;start&lt;/code&gt; is very important because it makes the circle avatar to be placed at top-left corner as needed. &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;_tweetContent()&lt;/code&gt; method returns the content of the tweet, of course. Below is the entire method since it is easier to connect the dots by seeing all elements, after that I will explain the code. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;

&lt;span class="n"&gt;Widget&lt;/span&gt; &lt;span class="nf"&gt;_tweetContent&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Flexible&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;margin:&lt;/span&gt; &lt;span class="n"&gt;EdgeInsets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;left:&lt;/span&gt; &lt;span class="mf"&gt;10.0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nl"&gt;crossAxisAlignment:&lt;/span&gt; &lt;span class="n"&gt;CrossAxisAlignment&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nl"&gt;mainAxisAlignment:&lt;/span&gt; &lt;span class="n"&gt;MainAxisAlignment&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nl"&gt;children:&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Widget&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;[&lt;/span&gt;
            &lt;span class="n"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="nl"&gt;children:&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Widget&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;[&lt;/span&gt;
                &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="nl"&gt;style:&lt;/span&gt; &lt;span class="n"&gt;TextStyle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="nl"&gt;color:&lt;/span&gt; &lt;span class="n"&gt;Colors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;white&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="nl"&gt;fontWeight:&lt;/span&gt; &lt;span class="n"&gt;FontWeight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;bold&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
                &lt;span class="n"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                  &lt;span class="nl"&gt;margin:&lt;/span&gt; &lt;span class="n"&gt;EdgeInsets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;left:&lt;/span&gt; &lt;span class="mf"&gt;5.0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userHandle&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" · 30m"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                      &lt;span class="nl"&gt;style:&lt;/span&gt; &lt;span class="n"&gt;TextStyle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;color:&lt;/span&gt; &lt;span class="n"&gt;Colors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;grey&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;])),&lt;/span&gt;
                &lt;span class="p"&gt;)&lt;/span&gt;
              &lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="nl"&gt;margin:&lt;/span&gt; &lt;span class="n"&gt;EdgeInsets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;top:&lt;/span&gt; &lt;span class="mf"&gt;5.0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;style:&lt;/span&gt; &lt;span class="n"&gt;TextStyle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;color:&lt;/span&gt; &lt;span class="n"&gt;Colors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;white&lt;/span&gt;&lt;span class="p"&gt;))),&lt;/span&gt;
            &lt;span class="n"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="nl"&gt;margin:&lt;/span&gt; &lt;span class="n"&gt;EdgeInsets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;top:&lt;/span&gt; &lt;span class="mf"&gt;10.0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
              &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="nl"&gt;mainAxisAlignment:&lt;/span&gt; &lt;span class="n"&gt;MainAxisAlignment&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;spaceBetween&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nl"&gt;children:&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Widget&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;[&lt;/span&gt;
                  &lt;span class="n"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="nl"&gt;children:&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Widget&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;[&lt;/span&gt;
                      &lt;span class="n"&gt;Icon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Icons&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;color:&lt;/span&gt; &lt;span class="n"&gt;Colors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;white&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                      &lt;span class="n"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="nl"&gt;margin:&lt;/span&gt; &lt;span class="n"&gt;EdgeInsets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;left:&lt;/span&gt; &lt;span class="mf"&gt;3.0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                        &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"15"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                            &lt;span class="nl"&gt;style:&lt;/span&gt; &lt;span class="n"&gt;TextStyle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;color:&lt;/span&gt; &lt;span class="n"&gt;Colors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;white&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
                      &lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;],&lt;/span&gt;
                  &lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="nl"&gt;children:&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Widget&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;[&lt;/span&gt;
                      &lt;span class="n"&gt;Icon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Icons&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;color:&lt;/span&gt; &lt;span class="n"&gt;Colors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;white&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                      &lt;span class="n"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="nl"&gt;margin:&lt;/span&gt; &lt;span class="n"&gt;EdgeInsets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;left:&lt;/span&gt; &lt;span class="mf"&gt;3.0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                        &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"15"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                            &lt;span class="nl"&gt;style:&lt;/span&gt; &lt;span class="n"&gt;TextStyle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;color:&lt;/span&gt; &lt;span class="n"&gt;Colors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;white&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
                      &lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;],&lt;/span&gt;
                  &lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="nl"&gt;children:&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Widget&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;[&lt;/span&gt;
                      &lt;span class="n"&gt;Icon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Icons&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;favorite_border&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;color:&lt;/span&gt; &lt;span class="n"&gt;Colors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;white&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                      &lt;span class="n"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="nl"&gt;margin:&lt;/span&gt; &lt;span class="n"&gt;EdgeInsets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;left:&lt;/span&gt; &lt;span class="mf"&gt;3.0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                        &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"15"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                            &lt;span class="nl"&gt;style:&lt;/span&gt; &lt;span class="n"&gt;TextStyle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;color:&lt;/span&gt; &lt;span class="n"&gt;Colors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;white&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
                      &lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;],&lt;/span&gt;
                  &lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;Icon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Icons&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;share&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;color:&lt;/span&gt; &lt;span class="n"&gt;Colors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;white&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;],&lt;/span&gt;
              &lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;The parent element is a &lt;code&gt;Flexible&lt;/code&gt; widget which allows the element to occupy the rest of the space available, the space on the row created on the &lt;code&gt;build&lt;/code&gt; method above. Then we have a &lt;code&gt;Container&lt;/code&gt; which allow to configure the margin necessary on the left of the content to separate it from the circle avatar. Finally, we have a &lt;code&gt;Column&lt;/code&gt;, where the fun starts. &lt;/p&gt;

&lt;p&gt;Again we have &lt;code&gt;crossAxisAlignment&lt;/code&gt; and &lt;code&gt;mainAxisAlignment&lt;/code&gt; as &lt;code&gt;start&lt;/code&gt; to make the content to be positioned a the top-left corner. The first child of the column is a &lt;code&gt;Row&lt;/code&gt; that contains the user name, its handle and the time of the tweet. To make the user handle be slightly separated from the user name we wrap the &lt;code&gt;Text&lt;/code&gt; into a &lt;code&gt;Container&lt;/code&gt; as we've done before. The second child of the column is a &lt;code&gt;Container&lt;/code&gt; that wraps the actual text of the tweet with a margin at the top. Finally, we have another container with a &lt;code&gt;Row&lt;/code&gt; as child to build the reply, retweet, like and share buttons. &lt;code&gt;mainAxisAlignment&lt;/code&gt; is set as &lt;code&gt;spaceBetween&lt;/code&gt; so to that all icons will have an equal space between them and will be evenly distributed through the width of the row. Very convenient configuration, positioning and spacing was always something very troublesome for me in other frameworks. Each icon is a &lt;code&gt;Row&lt;/code&gt; itself containing the icon and the number of replies, RTs, etc beside it. Simple, isn't it?  &lt;/p&gt;

&lt;p&gt;So let's see the final result below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fr4xg52fojn87p9pc2jyg.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fr4xg52fojn87p9pc2jyg.jpg" alt="Twitter layout made with Flutter"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It is close enough except for the icons which are probably Twitter exclusive. The tweets are just a sample. &lt;/p&gt;

&lt;p&gt;I hope this post will be of any use for people who are thinking about taking a look at Flutter and how to get started. For me it was love at the first sight when it comes to layout creation and unless it is limited about interactivity, where I still have to experiment, I believe that it will be popular very soon! &lt;/p&gt;

</description>
      <category>flutter</category>
      <category>dev</category>
      <category>mobile</category>
    </item>
    <item>
      <title>Is it good or bad to be all over the place with dev technologies? </title>
      <dc:creator>Leonardo Teteo</dc:creator>
      <pubDate>Mon, 24 Dec 2018 00:15:36 +0000</pubDate>
      <link>https://dev.to/leoat12/is-it-good-or-bad-to-be-all-over-the-place-with-dev-technologies--1k47</link>
      <guid>https://dev.to/leoat12/is-it-good-or-bad-to-be-all-over-the-place-with-dev-technologies--1k47</guid>
      <description>&lt;p&gt;2018 has been a wild year for me, it was the first year of my professional career as developer, before that I dealt more with networking infrastructure and administration. How I went from a career towards SysAdmin to Developer is another story for another day. Before starting really working with development I've never dived deep into the development world, I was still at college studying to get graduated, there wasn't much space, specially because it was not my first choice at first. But I was caught by the development world and here I am, one year ago, writing a retrospective and somewhat asking for advice about my eagerness to learn a lot of things at the same time. &lt;/p&gt;

&lt;p&gt;Let's start from the beginning, I was hired for a Java Web Developer position, and, I have to confess that days before the interview I had no knowledge of Spring Framework at all, I mean it, I'm not ashamed for saying the truth. I knew Java from college and has developed simple web applications in the past, but it was in C# despite the MVC concepts are the same. That was what helped me in understanding Spring, JAX-RS and other frameworks from Java quickly. Fortunately, I was hired and I started to study Spring deeply while at work and outside of the company. Spring Boot, Spring Security, Spring Data, Spring Session, etc. I still have a lot to learn though. &lt;/p&gt;

&lt;p&gt;In the meantime, the company is also a AWS partner, we usually deploy our applications on AWS and the knowledge of its services is paramount. So, I also started to study AWS with the goal of getting certified. After some months of study, I was able to pass the certification exam and I'm now a certified developer. It helped me a lot in having confidence to propose improvements to what we already had on AWS and it has been great to see this come to fruition.  &lt;/p&gt;

&lt;p&gt;Only that is already a really good amount of knowledge to swallow, Spring and AWS have some things in common: they are huge, with a lot of modules, services, complexities and details, they range from simple web applications to security, data handling, etc. I also put some effort on understanding DevOps on AWS, which was not really part of the exam that much. I also took a liking for serverless and for that reason spent a long time making experiments with AWS Lambda and DynamoDB.&lt;/p&gt;

&lt;p&gt;Since I was doing experiments with DynamoDB, I also took a look at MongoDB to see what differences they had, I saw that DynamoDB had some limitations during my experiments and I had to take a look at other solutions to see if they were more compatible with my user case. Right now I'm experimenting with Elasticsearch and Logstash and enjoying a lot as well, it can have a very good impact in future projects in my opinion. &lt;/p&gt;

&lt;p&gt;However, before I enter into the current Elasticsearch vibe I also had the front-end vibe, I was worried about my knowledge of HTML, CSS and frameworks such as Angular, VueJs and React, I also made a post about &lt;a href="https://dev.to/leoat12/be-or-not-to-be-a-full-stack-developer-2ko"&gt;Full-stack development&lt;/a&gt;, I was and I am still worried about how to become a full-stack developer. My first adventures with Angular was not that pleasant, but recently, after so much time making web applications, many of the experiences I had with Spring and template engines such as JSP and Thymeleaf, proved to be very useful in understanding Angular better, right now I going back to Angular and developing an UI for a personal project, maybe soon I will talk about that here. &lt;/p&gt;

&lt;p&gt;Besides all that, I'm also right now experimenting with Flutter, the newest and shiny framework for mobile development by Google. This year I also played around with native Android development with Java, NativeScript and Xamarim! Flutter has been a pleasant surprise and I think this vibe will last through next year. &lt;/p&gt;

&lt;p&gt;So, after all that I think it is possible to understand what my worries are: I'm all over the place! I experiment with a lot of things from databases, mobile and web frameworks, cloud providers and so on, without going deeper into any of them, excluding Spring and AWS, which actually makes part of my daily professional life.&lt;/p&gt;

&lt;p&gt;What are your takes about this? Should I focus more? Is it all right to experiment so much without going deeper? What are your experiences on dealing with the huge amount of technologies we have at our disposal nowadays and the curiosity IT guys like us naturally have?&lt;/p&gt;

&lt;p&gt;Happy holidays! :)   &lt;/p&gt;

</description>
      <category>discuss</category>
      <category>help</category>
      <category>career</category>
      <category>dev</category>
    </item>
    <item>
      <title>The node_modules problem</title>
      <dc:creator>Leonardo Teteo</dc:creator>
      <pubDate>Mon, 19 Nov 2018 22:45:21 +0000</pubDate>
      <link>https://dev.to/leoat12/the-nodemodules-problem-29dc</link>
      <guid>https://dev.to/leoat12/the-nodemodules-problem-29dc</guid>
      <description>&lt;p&gt;I think I'm not the first one to talk about this problem even here in dev.to. I quick research trying to found any solution concluded with the image that is the head of this text. The &lt;strong&gt;node_modules&lt;/strong&gt; folder is where your project dependencies are stored, common knowledge. Its weight is also common knowledge.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I decided to vent my frustration now
&lt;/h2&gt;

&lt;p&gt;Black Friday is here! It means discounts and the opportunity to update your computer. Therefore I decided to buy a SSD to boost the performance of my laptop, from 1 TB HDD to 500 GB SSD. All my files right now sums 299 GB, so I will not lose much space, but I decided to do the housekeeping work even so, this includes making backups of my projects. Not all projects I make I put on GitHub, sometimes I'm just experimenting and it is not worth the trouble, but I keep them anyway. &lt;/p&gt;

&lt;p&gt;When I started the copy &amp;amp; paste process I remembered how heavy &lt;strong&gt;node_modules&lt;/strong&gt; are...&lt;/p&gt;

&lt;h2&gt;
  
  
  Some comparisons
&lt;/h2&gt;

&lt;p&gt;One example that shows clearly the problem is the &lt;strong&gt;node_modules&lt;/strong&gt; folder of my &lt;a href="https://dev.to/leoat12/my-first-serious-project-in-nodejs-toread-cli-3e4b"&gt;ToRead CLI project&lt;/a&gt; as you can see in the imagem below.&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%2Ff7jeyvijq3pn8ur9vaqr.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%2Ff7jeyvijq3pn8ur9vaqr.PNG" alt="node_modules property window" width="428" height="92"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The size of the folder is not really the problem although I will get to that later, but 15.000 files and more than 1800 folders!? Are you kidding me?! It is a simple CLI project with 5 files! Just for a comparison, let's see how many files and folders there is in the &lt;strong&gt;Windows&lt;/strong&gt; folder:&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%2Fo9lkc594x5v18ed4wa0q.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%2Fo9lkc594x5v18ed4wa0q.PNG" alt="Windows folder property window" width="360" height="102"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While the system was counting I really thought &lt;strong&gt;node_modules&lt;/strong&gt; would win this, but no. In any case, the folder has almost half of the amount of files an entire operating system has! &lt;/p&gt;

&lt;p&gt;As I've said, the problem when copying &lt;strong&gt;node_modules&lt;/strong&gt; folder from one place to another is not the size, it is the amount of files and folders, the complexity of the tree. It is a nightmare for a HDD. It takes many minutes to discover all files let alone copy them. In the end, it also impacts &lt;strong&gt;npm&lt;/strong&gt; performance and there are memes for that also.&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%2Fxfa2qqs4zc030gzpncmk.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%2Fxfa2qqs4zc030gzpncmk.jpg" alt="Waiting for npm install" width="298" height="402"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Other comparisons come from my passion for serverless. It is not rare for me to implement the same function in both Java and Javascript and since you have to bundle the function along with its dependencies it is a good way to compare which one is more efficient in dependency management. In one of my projects I wtote the function in both languages with virtually the same features and Java bundle size is 11.1 MB and NodeJS bundle size was 29.0 MB. Therefore, NodeJS can do a better job at the size of dependencies as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  What other languages do
&lt;/h2&gt;

&lt;p&gt;Besides NodeJS I have experience dealing with dependencies in two more languages: Java and C#. They have, in my opinion, a very similar way of handling dependencies and a much more efficient way than NodeJS. &lt;/p&gt;

&lt;p&gt;Java has Maven, Gradle and other dependency management applications that works basically the same. There is a remote repository of the dependencies, generally Maven Central and a local repository. Maven always looks for the dependency in the local repository first and if not found it downloads from the remote repository. The dependencies are not within the project, like &lt;strong&gt;node_modules&lt;/strong&gt; folder, it is more global, it is downloaded once and can be used by many projects, just add to your pom.xml. &lt;/p&gt;

&lt;p&gt;C# follows the same idea, you list your dependencies in a .csproj file and Nuget takes care of the dependencies having also a remote and a local repository. It is much more efficient to handle dependencies this way, download once use in any project locally. &lt;/p&gt;

&lt;p&gt;I think there is also a difference in culture and the way the languages were structured and what people see as libraries. Java has a very mature core of libraries that can deal with almost anything, common scenarios or not. Therefore, libraries in Java generally are meant to be an abstraction of what Java already has, making it easier to use. Therefore, the libraries have a more shallow dependency tree, reaching the Java core libraries much quicker. &lt;/p&gt;

&lt;p&gt;What I see in NodeJS on the other hand is the opposite, everything can become a library, even a library that sums two numbers (hypothetical example, I hope) and libraries are heavily dependent of one another generating deep dependency trees, many files and folders.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion &amp;amp; Discussion
&lt;/h2&gt;

&lt;p&gt;I am certainly not qualified to criticize NodeJs structure and engineering, but as a user I clearly see a problem and some lessons from other languages that can be used to improve the dependency management, which is paramount nowadays for almost every application. What do you think this problem came to be and what has been done to solve it? It would be very interesting to hear from more experienced developers what you do to remedy this.  &lt;/p&gt;

</description>
      <category>node</category>
      <category>javascript</category>
      <category>discuss</category>
      <category>npm</category>
    </item>
  </channel>
</rss>
