<?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: Mikhail Palei</title>
    <description>The latest articles on DEV Community by Mikhail Palei (@undeadlol1).</description>
    <link>https://dev.to/undeadlol1</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%2F166322%2Fa5ed26c2-2aea-4d02-92db-3ab30df82aaa.jpeg</url>
      <title>DEV Community: Mikhail Palei</title>
      <link>https://dev.to/undeadlol1</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/undeadlol1"/>
    <language>en</language>
    <item>
      <title>The Ultimate Goal of Programming</title>
      <dc:creator>Mikhail Palei</dc:creator>
      <pubDate>Sun, 03 Dec 2023 18:56:33 +0000</pubDate>
      <link>https://dev.to/undeadlol1/the-ultimate-goal-of-programming-17e</link>
      <guid>https://dev.to/undeadlol1/the-ultimate-goal-of-programming-17e</guid>
      <description>&lt;p&gt;Is to have code that is easy to change.&lt;br&gt;
This is a simple statement, and perhaps it will not even provoke a large number of disputes. Because it is obvious that it is useful to have code that is easy to change. Even if you do not agree that this is the ultimate goal of programming, you probably still agree with the usefulness of the concept as a whole.&lt;/p&gt;

&lt;p&gt;Let's break it down. What problem are we trying to solve?&lt;br&gt;
I think this is a fundamental problem for programmers. The thing is, we do not understand, or have false ideas about, why we are programming at all.&lt;/p&gt;

&lt;p&gt;For example, when welders weld a structure at a construction site, they know that this structure is needed in order to build a house. They use welding because it is very important for the house to be strong. To prevent the house from collapsing. To prevent people from dying in a collapse. This is vital.&lt;/p&gt;

&lt;p&gt;Perhaps this seems too obvious. Perhaps it sounds as if I am describing the fact that water is wet and the sky is blue. But ask yourself: what do programmers think about when writing code? What is the ultimate goal of their activity?&lt;br&gt;
“To make a product” is the answer I received in the vast majority of cases.&lt;/p&gt;

&lt;p&gt;The problem is that the very concept of a "product" is constantly changing. Have you ever heard the saying: "In programming, there is only one constant: everything always changes." Just as no business plan survived first contact with the consumer, all projects always change in the course of development. New requirements emerge. Bugs and errors force us to refine and revise.&lt;/p&gt;

&lt;p&gt;This is why "making a product" is an extremely wrong way to look at programming. This approach implies that there is a clear plan. That everything is written down and planned so that the plans do not fail or change. That there are requirements that will not change. That there will be no mistakes or bugs.&lt;/p&gt;

&lt;p&gt;This vision also does not imply that the concept of a "product" is not only vague and constantly changing, but also constantly expanding. New features and use cases appear for the application, new services emerge. The business will always try to retain current users by expanding functionality and improving the service. Or simply change and adapt to new markets.&lt;/p&gt;

&lt;p&gt;I do not want to confuse you with these arguments. The idea here is very simple: there is no such thing as a "finished product" in programming. Our work is never finished. We can support the current product for a long time, we may be reassigned to another or we may simply be fired. For example, because the money ran out. But the situation where the product is built and finished happens extremely rarely. There are probably exceptions to this rule, but I ask you to note that these are precisely exceptions that confirm the rule.&lt;/p&gt;

&lt;p&gt;What do I want to say and where am I leading with this?&lt;/p&gt;

&lt;p&gt;I’ll draw an example from practice. Because it will help you put this knowledge into practice.&lt;/p&gt;

&lt;p&gt;Recently, I was involved in training a new employee. He was given a task:&lt;br&gt;
• the mobile application has a list. The list displays only one item. The remaining list items are hidden.&lt;br&gt;
• If you press "show full list", then the entire list will be displayed instead of just one item. For example, 10 items.&lt;br&gt;
• A change is required. It is necessary for three items to be displayed at the very beginning, rather than just one. Meaning, when you enter the page, you see three items in the list, you press the "show full list" button, and then 10 items are displayed.&lt;/p&gt;

&lt;p&gt;The developer approached this issue the same way as many might: he wrote the code so that the list could take an argument. Meaning, you can tell the list how many items should be in the list before the button is pressed. His reasoning was simple: "I want to ensure that I won't have any problems with this list in the future. If I ever need to use this list somewhere else, or use several lists with different initial numbers of elements, I just need to specify the right argument. There will never be any more issues with this element." In this way, he was making it "future proof."&lt;/p&gt;

&lt;p&gt;This is absolutely logical. It makes sense. And it is obviously useful.&lt;/p&gt;

&lt;p&gt;However, when the developer asked me about my opinion on this solution, it surprisingly made me think. In programming, there are many different principles. There is one that is rarely applied and often even provokes disputes: KISS (Keep It Simple Stupid).&lt;/p&gt;

&lt;p&gt;In order to display just one item, we previously had the following line:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;list.sublist(0, 1)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To display any number of items, we planned to use this line:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;list.sublist(0, amountOfInitialItemsToDisplay)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;At first glance, the change seems not critical. But upon closer examination, it turned out that the complexity of our code sharply increased. If previously we had only one test that had a very simple description "if the button is not pressed, make sure that only one item is displayed," now we need several tests:&lt;br&gt;
• "if the button is not pressed and if it is indicated to display only one initial item, make sure that only one item is displayed"&lt;br&gt;
• "if the button is not pressed and if it is indicated to display 3 items, then make sure that three items are displayed"&lt;br&gt;
• "if the button is not pressed and if nothing is indicated to display (the argument is missing), then display the default value—three items"&lt;br&gt;
• "if the button is not pressed and if it is indicated to display 0 items, make sure that 0 items are displayed"&lt;br&gt;
• "if the button is not pressed and if a negative number is given, throw an error"&lt;br&gt;
• "if the button is not pressed and if a number is given that exceeds the number of list items, throw an error"&lt;/p&gt;

&lt;p&gt;Perhaps the last few tests may seem excessive to you, and these situations are made up. Indeed, I agree with you, this is so. But the key idea is that previously we did not have such potential situations, such problems, and so many tests. And now, due to a small change in logic, our code has become more complex. We have more code and tests that need to be maintained, and it has become more difficult to understand all of this.&lt;/p&gt;

&lt;p&gt;On the other hand, we have considerations that we really can change the list in the future (if we change it now, who said we won't change it in the future?), the list may have a different appearance on different pages, and indeed, it doesn't feel future proof.&lt;/p&gt;

&lt;p&gt;So what should we choose?&lt;/p&gt;

&lt;p&gt;At that moment, I asked myself: what is the ultimate goal of programming? The ultimate goal of programming is to have code that is easy to change. If we look at the problem from this point of view, the answer becomes obvious.&lt;/p&gt;

&lt;p&gt;We need to change this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;list.sublist(0, 1)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;list.sublist(0, 3)&lt;br&gt;
Then update one test, and the work is done.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is a way to add the least amount of complexity.&lt;/p&gt;

&lt;p&gt;This is a way through which, if we were asked to change this list in any way, we would have the fewest problems.&lt;/p&gt;

&lt;p&gt;Judge for yourself: if we had a dynamic number of elements, there would be more logic, more checks, more tests, and more code in general.&lt;br&gt;
So when it is necessary to change this list (and this moment will definitely come, because it is an axiom), this greater complexity would hinder us. We would have to take it into account, write new tests and checks. It turns out that complexity leads to even greater complexity, and it can even multiply in geometric progression.&lt;/p&gt;

&lt;p&gt;Ultimately, despite the fact that these considerations are very logical, they still seemed to me to be somehow wrong. As if unlawful. Did I spend all my time learning different principles and gaining experience just to change one number to another in the end? What about SOLID? What about DRY? Maybe use some programming pattern? Maybe extract the logic of creating the list? Maybe create two classes instead of one? Maybe through inheritance somehow? Maybe something else?&lt;/p&gt;

&lt;p&gt;In my specific example, everything is very simple, and it may seem like these considerations are far-fetched. But if we abstract from the specifics of my example, it becomes clear that this is often how we think. We have our own knowledge, experience, ideas, and concerns. And very soon, if you dig deeper, it becomes clear that we make decisions based on a multitude of factors. Someone writes code so as not to worry about the future. Someone likes to use proven techniques. Someone just wants to close the task as quickly as possible. Someone just doesn't know what they're doing.&lt;/p&gt;

&lt;p&gt;And none of these decisions are made from a position of common sense. Because the most sensible thing we can do every day is to write code so that it is easy to change. Because as programmers, we spend the lion's share of our time somehow changing our code.&lt;/p&gt;

&lt;p&gt;In conclusion, I would like to say that in my opinion, all the principles and best practices that we apply actually come down to the idea written at the beginning of the article.&lt;/p&gt;

&lt;p&gt;DRY == do not duplicate code, write so that changes do not have to be made in many places instead of one.&lt;/p&gt;

&lt;p&gt;Architecture == correctly divide the project into layers, so that changes in one layer do not affect others == write code so that it is easy to change.&lt;/p&gt;

&lt;p&gt;SOLID == write code so that when adding functionality, we add classes, not change existing ones == write classes so that it is easy to make changes to the project.&lt;/p&gt;

&lt;p&gt;Clean code == write code so that it is easy to read and understand what it does. So that it is easy to make changes.&lt;/p&gt;

&lt;p&gt;And so on.&lt;/p&gt;

&lt;p&gt;Therefore, every time I ask myself questions about how to solve a problem in code, I just ask myself, "What is the ultimate goal of programming?" And then come up with a way through which the code will be easiest to change in the future. I recommend the same to you.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>beginners</category>
      <category>coding</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Should class names really be nouns? Rethinking the classics</title>
      <dc:creator>Mikhail Palei</dc:creator>
      <pubDate>Tue, 27 Dec 2022 11:35:18 +0000</pubDate>
      <link>https://dev.to/undeadlol1/should-class-names-really-be-nouns-rethinking-the-classics-n7p</link>
      <guid>https://dev.to/undeadlol1/should-class-names-really-be-nouns-rethinking-the-classics-n7p</guid>
      <description>&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;One of the most fundamental ways of thinking in terms of Object Oriented Programming is thinking in objects. Does this look familiar?&lt;br&gt;
&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;Dog&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;bark&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="n"&gt;waveTail&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;Sadly, in programming we rarely actually use nouns. We usually operate via verbs.&lt;/p&gt;

&lt;p&gt;For example, Repository names should not be written via nouns. Next code example is written via nouns and it breaks SOLID principles:&lt;br&gt;
&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;ChatsRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;getChat&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="n"&gt;getChats&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="n"&gt;updateChat&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="n"&gt;deleteChat&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;Here is the fixed version. This code does not break SOLID:&lt;br&gt;
&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;ChatGetterRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;getChat&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ChatsGetterRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;getChats&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ChatUpdaterRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;updateChat&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ChatDeleterRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;deleteChat&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;But this code is still far from being perfect. Can you name the problem with it?&lt;/p&gt;

&lt;p&gt;Programmers usually spend 90% of their time actually reading the code not writing it (source: Clean Code by Robert C. Martin). Thus the easier it is to read the code the less time you will spend on adding features and fixing bugs.&lt;/p&gt;

&lt;p&gt;Now we come to an important question: what code is easy to read and what is hard to read? Well, interesting thing about reading is the fact that we internally pronounce code while we read it. And if code is easy to pronounce then it is easy to read (source: also Clean Code by Robert C. Martin).&lt;/p&gt;

&lt;p&gt;Try to read out loud these 2 class names:  &lt;code&gt;ChatDeleter&lt;/code&gt; and &lt;code&gt;DeleteChat&lt;/code&gt;. Obviously, second one is easier on the tongue. The first one is too clunky. &lt;code&gt;Cha-t-de-le-te-r&lt;/code&gt; vs &lt;code&gt;De-le-te-cha-t&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;On top of that it is important to use words that we actually use in real life. Because the code should not be cryptic. The code is written for humans to understand not for the machines. The machines do not care if we name our class &lt;code&gt;x&lt;/code&gt;, &lt;code&gt;y&lt;/code&gt;, &lt;code&gt;ChatDeleter&lt;/code&gt;, or &lt;code&gt;MegaUltraZoomZoomChatDeleterAgentRepositoryClass9000&lt;/code&gt;. We write code programmers. For our fellow humans. For our selfs. So why on earth do we name our classes so alien and cryptic? Why do we write things like &lt;code&gt;ChatDeleter&lt;/code&gt; instead of &lt;code&gt;DeleteChat&lt;/code&gt;? Have ever tried to describe your code to your teammate?&lt;/p&gt;

&lt;p&gt;-Hey, team mate! What are you working on? What do you want to do?&lt;/p&gt;

&lt;p&gt;Compare these answers:&lt;/p&gt;

&lt;p&gt;-Hey! I want to use chat repository to delete a chat.&lt;br&gt;
-Hey! I want to use chat deleter to delete a chat.&lt;br&gt;
-Hey! I want to delete a chat.&lt;/p&gt;

&lt;p&gt;I think it goes without saying that first two answers are just plain weird. Yet these is exactly how we write code. We simply have been doing it for so long that we don’t even see the problem anymore.&lt;/p&gt;
&lt;h2&gt;
  
  
  The solution
&lt;/h2&gt;

&lt;p&gt;The solution is quite simple: we need to use verbs instead of nouns for naming our classes.&lt;/p&gt;

&lt;p&gt;Here are our new classes:&lt;br&gt;
&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;GetChatRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;getChat&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GetChatsRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;getChats&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UpdateChatRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;updateChat&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DeleteChatRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;deleteChat&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Example usage:&lt;/span&gt;
&lt;span class="n"&gt;DeleteChatRepository&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;deleteChat&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Some languages even allow us to avoid code duplication by using conventions. Java has &lt;code&gt;main()&lt;/code&gt; method, Dart has &lt;code&gt;call()&lt;/code&gt; and Go has… well, &lt;code&gt;go()&lt;/code&gt;.&lt;br&gt;
&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;GetChatRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GetChatsRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UpdateChatRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DeleteChatRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// Example usage:&lt;/span&gt;
&lt;span class="n"&gt;DeleteChatRepository&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;call&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="c1"&gt;// Dart allows us to have a shortcut:&lt;/span&gt;
&lt;span class="n"&gt;DeleteChatRepository&lt;/span&gt;&lt;span class="p"&gt;()();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you are still not convinced that nouns are the way to go let me demonstrate a typical code that uses Dependency Injection:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Example of DI using nouns.&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ChatDeleter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Next two lines represent the way Dependency injection usually works in Dart.&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;ChatDeleterRepository&lt;/span&gt; &lt;span class="n"&gt;chatDeleterRepo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;DeleteChatUseCase&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="kd"&gt;required&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;chatDeleterRepo&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="n"&gt;deleteChat&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;chatDeleterRepo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;deleteChat&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;ChatDeleterUseCase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;deleteChat&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Example of DI using verbs.&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DeleteChat&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Next two lines represent the way Dependency injection usually works in Dart.&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;DeleteChatRepository&lt;/span&gt; &lt;span class="n"&gt;deleteChat&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;DeleteChatUseCase&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="kd"&gt;required&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;deleteChat&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;deleteChat&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;DeleteChat&lt;/span&gt;&lt;span class="p"&gt;()();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why it is important
&lt;/h2&gt;

&lt;p&gt;If code is not written in plain english and you need to do any kind of mental transformation or guess work then it is not readable code. It is a structured mess.&lt;/p&gt;

&lt;p&gt;The sad thing is classes are the most fundamental thing we use. This means that we constantly mentally jump through hoops by doing guess work, mental transformation and internally pronouncing unreadable words. It is an invisible perpetual torture.&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>writing</category>
    </item>
    <item>
      <title>How to use build context outside of Flutter widgets</title>
      <dc:creator>Mikhail Palei</dc:creator>
      <pubDate>Fri, 16 Dec 2022 16:00:28 +0000</pubDate>
      <link>https://dev.to/undeadlol1/how-to-use-build-context-outside-of-flutter-widgets-4l70</link>
      <guid>https://dev.to/undeadlol1/how-to-use-build-context-outside-of-flutter-widgets-4l70</guid>
      <description>&lt;h2&gt;
  
  
  Short answer:
&lt;/h2&gt;

&lt;p&gt;If you need to use &lt;code&gt;BuildContext&lt;/code&gt; outside of Flutter widgets use the package created based on ideas of this article:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://pub.dev/packages/build_context_provider"&gt;https://pub.dev/packages/build_context_provider&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Long answer:
&lt;/h2&gt;

&lt;p&gt;When I started working with Flutter one of the most confusing things for me were inability to use methods that required &lt;code&gt;BuildContext&lt;/code&gt; outside of flutter widgets. &lt;/p&gt;

&lt;p&gt;Lets say you want to have a reusable class that navigates to a certain page of the app. You might want to use that class without a "context" argument. For example, in Clean Architecture use cases must never rely on any framework or library specific code. Since &lt;code&gt;BuildContext&lt;/code&gt; is specific to Flutter framework this code is invalid in Clean Architecture:&lt;br&gt;
&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;NavigateToProfileUseCase&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;call&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="n"&gt;Navigator&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;pushNamed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'/profile'&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;h3&gt;
  
  
  What is the solution?
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Note: the explanation of the solution is going to sound somewhat confusing. Please bear with me. It is going to get clearer by the end of the article.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In order to fix this problem we must change the way we call these functions. Instead calling functions directly we must pass these functions to the special widget that is going to run in UI layer.&lt;/p&gt;

&lt;p&gt;Here is what we must do:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We must create a special class which is going to hold a function. Let’s call it a &lt;code&gt;Publisher&lt;/code&gt;. This can be a Cubit/Bloc, a &lt;code&gt;Stream&lt;/code&gt; or a &lt;code&gt;ChangeNotifier&lt;/code&gt; or any other reactive class.&lt;/li&gt;
&lt;li&gt;We must create a special widget that is going to listen to the changes of the &lt;code&gt;Publisher&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;This widget must invoke functions pushed to the &lt;code&gt;Publisher&lt;/code&gt; with the latest &lt;code&gt;BuildContext&lt;/code&gt; instance.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let’s take a look at an example:&lt;br&gt;
&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;NavigateToProfileUseCase&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;- notice how we don't pass BuildContext anymore&lt;/span&gt;
        &lt;span class="n"&gt;functionRunnerCubit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;runFunction&lt;/span&gt;&lt;span class="p"&gt;(&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="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Navigator&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;pushNamed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'/profiile'&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="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;functionRunnerCubit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;FunctionRunnerCubit&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FunctionRunnerCubit&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;Cubit&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;FunctionRunnerState&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;FunctionRunnerCubit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FunctionRunnerWithNoFunctionsToRun&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;runFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Function&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="n"&gt;VoidCallback&lt;/span&gt; &lt;span class="n"&gt;functionToRun&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;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;FunctionRunnerWithFunctionToRun&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nl"&gt;function:&lt;/span&gt; &lt;span class="n"&gt;functionToRun&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="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FunctionRunner&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="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;FunctionRunner&lt;/span&gt;&lt;span class="p"&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;key&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;key:&lt;/span&gt; &lt;span class="n"&gt;key&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;BlocListener&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;FunctionRunnerCubit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ContextListenerState&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;listener:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buildContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="n"&gt;FunctionRunnerWithFunctionToRun&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buildContext&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;child:&lt;/span&gt; &lt;span class="n"&gt;SizedBox&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;Explanation of the code:&lt;/p&gt;

&lt;p&gt;Inside of the &lt;code&gt;UseCase&lt;/code&gt; we pass a function that we want to run with a &lt;code&gt;BuildContext&lt;/code&gt; to the &lt;code&gt;Cubit&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Cubit&lt;/code&gt; publishes this function to the listeners.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;FunctionRunner&lt;/code&gt; widget listens to the changes of the &lt;code&gt;Cubit&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;BlocListener&lt;/code&gt;(think of it simply as a &lt;code&gt;Listener&lt;/code&gt; if you don’t know the “bloc” library) invokes the function with a latest instance of the &lt;code&gt;BuildContext&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  In conclusion
&lt;/h2&gt;

&lt;p&gt;This simple combination of a Publisher and a Listener will allow you to run your Flutter specific code anywhere. Such freedom will allow you to write simpler, cleaner and more maintainable code.&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>mobile</category>
      <category>tutorial</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Mixing state and logic is an anti-pattern</title>
      <dc:creator>Mikhail Palei</dc:creator>
      <pubDate>Sun, 11 Dec 2022 16:15:41 +0000</pubDate>
      <link>https://dev.to/undeadlol1/mixing-state-and-logic-is-an-anti-pattern-4njd</link>
      <guid>https://dev.to/undeadlol1/mixing-state-and-logic-is-an-anti-pattern-4njd</guid>
      <description>&lt;p&gt;The art of programming is, at its core, the art of managing data. Take the Facebook app, for example: there are user posts, direct messages, friends lists, friend requests, and more. But does it really matter what the "Send" button in a chat looks like? Does it matter whether you scroll posts vertically or horizontally? Or whether the notification indicator is on the left or the right?&lt;/p&gt;

&lt;p&gt;On one hand, details like these do matter. On the other hand, it's easy to see that they're just surface-level concerns. If we strip all of them away, what remains is the essence of any application: data, and how we manage it.&lt;/p&gt;

&lt;p&gt;For example, when you send a message to a friend, two things happen:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A network request is sent to an API to save the message in a database.&lt;/li&gt;
&lt;li&gt;The message appears at the bottom of the chat screen.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In both steps, we're simply taking data and doing something with it—sending it or showing it. That's what programming boils down to: managing data.&lt;/p&gt;

&lt;p&gt;So how does state management relate to this? Well, "state management" literally means "managing the state of data"—or just data management. These two terms are essentially interchangeable.&lt;/p&gt;

&lt;p&gt;But most developers never make this connection. When people hear "state management," they often think of business logic, or a "glue" layer that connects the UI and the logic. Because of this, state management is often treated as an afterthought. Why care about the "glue" if it doesn't seem important?&lt;/p&gt;

&lt;p&gt;But if we replace the term "state management" with "data management," its importance becomes obvious. You can't afford to treat your data as an afterthought. It's the foundation of your application.&lt;/p&gt;

&lt;p&gt;Building applications is hard—especially when multiple teams and hundreds of thousands of lines of code are involved. In my opinion, one of the biggest reasons it's so difficult is that nobody handles data management properly. And as I've said, data management is the most fundamental part of software engineering.&lt;/p&gt;

&lt;p&gt;So, why was this article written? In my 10 years of programming, I've never seen a team, a developer, or even a single article that gets state management right.&lt;/p&gt;

&lt;p&gt;Today, we're going to talk about the most fundamental mistake in state management: unpredictable states—a problem that arises when logic and state are mixed together.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the problem?
&lt;/h2&gt;

&lt;p&gt;To understand the problem, let me explain with an example. Let's say we're building a chat application. The app has chat rooms, and each chat room has a list of messages. When a chat room is opened, we need to download the latest messages and display them to the user.&lt;/p&gt;

&lt;p&gt;Here's how state management is usually done in this case:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;When a user lands on the page, some kind of state method is called:&lt;br&gt;
&lt;code&gt;chatRoomState.getLatestMessages();&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Inside this method, there is typically a use case or a controller:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ChatRoomState&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;getLatestMessages&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;downloadedMessages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;GetChatRoomMessagesUseCase&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;call&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="c1"&gt;// Set the new state and notify all listeners.&lt;/span&gt;
    &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;latestMessages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;downloadedMessages&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;/li&gt;
&lt;li&gt;
&lt;p&gt;Inside the use case, we usually call a repository:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GetChatRoomMessagesUseCase&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&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;await&lt;/span&gt; &lt;span class="n"&gt;getChatRoomMessagesRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;call&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="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GetChatRoomMessagesRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&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;await&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'/chat-room/123/messages'&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;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here's a diagram of that process:&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%2F7k1ngskuiwigdj866kpq.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%2F7k1ngskuiwigdj866kpq.png" alt="A diagram where a state calls a use case that calls a repository." width="782" height="122"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: if you're unfamiliar with use cases or repositories, think of them simply as classes that perform specific actions. In this example, state methods call classes, which in turn call other classes. There's a clear nesting of responsibilities.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;So, what's the problem?&lt;/p&gt;

&lt;p&gt;Let's say we're asked to show a "Messages loaded successfully" snackbar after the messages are downloaded. Whether or not it's good UX is not our call—we just need to implement it.&lt;/p&gt;

&lt;p&gt;Now the question is: &lt;strong&gt;where should this code go&lt;/strong&gt;?&lt;/p&gt;

&lt;p&gt;Putting the snackbar inside the &lt;code&gt;ChatRoomState&lt;/code&gt; doesn't feel right—snackbars and chat room data shouldn't be mixed. Adding it to the repository is definitely wrong, since repositories should only handle one responsibility. So maybe we should place it in the use case?&lt;/p&gt;

&lt;p&gt;That sounds reasonable at first:&lt;br&gt;
&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;GetChatRoomMessagesUseCase&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;getChatRoomMessagesRepository&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;Snackbar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;message:&lt;/span&gt; &lt;span class="s"&gt;'Messages loaded successfully'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;display&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;messages&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;At first glance, it looks fine. But problems arise quickly.&lt;/p&gt;

&lt;p&gt;Imagine we now need to load messages on a second page, but with a specific requirement: don't show a snackbar on success. Meaning, sometimes we want to suppress the snackbar and sometimes we want to show it. So we add an argument to control that:&lt;br&gt;
&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;ChatRoomState&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;getLatestMessages&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;isSnackbarHidden&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;downloadedMessages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;GetChatRoomMessagesUseCase&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;isSnackbarHidden:&lt;/span&gt; &lt;span class="n"&gt;isSnackbarHidden&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;latestMessages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;downloadedMessages&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="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GetChatRoomMessagesUseCase&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;isSnackbarHidden&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;getChatRoomMessagesRepository&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isSnackbarHidden&lt;/span&gt; &lt;span class="o"&gt;==&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="n"&gt;Snackbar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;message:&lt;/span&gt; &lt;span class="s"&gt;'Messages loaded successfully'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;display&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;messages&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 code is already getting more complicated. And our example only has two layers. In real projects, it's not uncommon to have three or four layers of nested classes.&lt;/p&gt;

&lt;p&gt;But this isn't even the worst part.&lt;/p&gt;

&lt;p&gt;Imagine months go by, the app grows, and a new developer joins the team. They're tasked with loading messages on yet another page. They use the &lt;code&gt;ChatRoomState.getLatestMessages&lt;/code&gt; function without reading the underlying implementation. Everything looks good, and they mark the task as done. But somehow, the page displays a "Messages loaded successfully" snackbar.&lt;/p&gt;

&lt;p&gt;They're confused. This wasn't expected. But the root cause is a hidden side effect.&lt;/p&gt;

&lt;p&gt;Think about it: &lt;code&gt;ChatRoomState&lt;/code&gt; is supposed to be responsible for chat room data only. And yet, using it triggers a completely unrelated UI change—a snackbar. In other words: working with chat room data unexpectedly affects the UI.&lt;/p&gt;

&lt;p&gt;These kinds of issues are hard to detect and take time to:&lt;br&gt;
    • notice,&lt;br&gt;
    • debug,&lt;br&gt;
    • and fix.&lt;/p&gt;

&lt;p&gt;You might think this is a rare or exaggerated case, but it happens more often than you'd expect.&lt;/p&gt;

&lt;p&gt;Let me give you a real-world example from a project I worked on.&lt;/p&gt;

&lt;p&gt;The app had three major features. Over time, our analytics showed that one feature was being used far more than the others. So we shifted focus and began redesigning the app around it. The other features were put on hold.&lt;/p&gt;

&lt;p&gt;Months later, we discovered the truth: the feature wasn't actually being used that much. What happened?&lt;/p&gt;

&lt;p&gt;One of our shared state methods was producing a hidden side effect. Every time any page was opened, it triggered an analytics event saying "Feature X was used". This inflated the usage stats and led to major business decisions based on false data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This simple side effect cost us months of work and untold losses.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The solution
&lt;/h2&gt;

&lt;p&gt;So how do we fix this?&lt;/p&gt;

&lt;p&gt;By extracting logic out of the state.&lt;/p&gt;

&lt;p&gt;We change this:&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%2Fdz9xb6yxw2dzocvuap15.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%2Fdz9xb6yxw2dzocvuap15.png" alt="Here previous image is displayed again." width="782" height="122"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Into this:&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%2Fw3rvsbrp9zdxg4lnchs9.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%2Fw3rvsbrp9zdxg4lnchs9.png" alt="A diagram where a use case calls both repository and state." width="512" height="362"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First, let's rewrite our state:&lt;/p&gt;

&lt;p&gt;Step 1: Rewrite the state&lt;br&gt;
&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;ChatRoomState&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;setMessages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;latestMessages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;messages&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;Step 2: Move the logic into the use case&lt;br&gt;
&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;GetChatRoomMessagesUseCase&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;shouldDisplaySnackbar&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;downloadedMessages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;getChatRoomMessagesRepository&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;chatRoomState&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setMessages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;downloadedMessages&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shouldDisplaySnackbar&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;Snackbar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;message:&lt;/span&gt; &lt;span class="s"&gt;'Messages loaded successfully'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;display&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;In the end, everything that needs to happen for a specific action—like downloading chat messages—is placed into a single container: the use case. This makes the action easy to read, understand, reuse, extend, test, and maintain. If you ever need to change how messages are loaded, you simply go to the use case and make your changes—no need to dig through scattered classes.&lt;/p&gt;

&lt;p&gt;Need to sort the messages? Replace the snackbar with something else? Add analytics tracking? Switch to a different data source? All of that becomes straightforward, because you know exactly where to look. And you can be confident that making a change won't accidentally trigger unrelated behavior.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What happens in the use case is what happens in the UI.&lt;/strong&gt; No hidden side effects, no surprises, no accidental breakage.&lt;/p&gt;

&lt;p&gt;This is what I call predictable state management.&lt;/p&gt;

&lt;h1&gt;
  
  
  Rules of Predictable State Management
&lt;/h1&gt;

&lt;p&gt;To implement and make the most of Predictable State Management, let's define a few essential rules.&lt;/p&gt;

&lt;h2&gt;
  
  
  Don't create a state unless you need a single source of truth
&lt;/h2&gt;

&lt;p&gt;Many developers don't know—or have forgotten—why state management was invented in the first place.&lt;/p&gt;

&lt;p&gt;Let's say you're working on a Facebook-like website. Every few minutes, you fetch data about how many friend requests the user has. This number is displayed in three different places:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In the top-right corner, where the notification icon shows the count of friend requests.&lt;/li&gt;
&lt;li&gt;In the left-side menu, next to the "Friends" link.&lt;/li&gt;
&lt;li&gt;On the "Friends" page itself, inside the main content area.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, what's the problem?&lt;/p&gt;

&lt;p&gt;Every time the data is refreshed, the UI needs to be updated in three separate places. This quickly becomes complex and unmaintainable because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You need to know what page the user is on.&lt;/li&gt;
&lt;li&gt;You need to know how many places are displaying that data.&lt;/li&gt;
&lt;li&gt;Each spot requires its own update logic or script.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To solve this, state management was introduced. The idea was simple: UI elements should listen to shared data sources. When the data changes, the UI updates automatically.&lt;/p&gt;

&lt;p&gt;This gave developers a single source of truth. Instead of manually updating each UI element, you update the data once, and everything stays in sync.&lt;/p&gt;

&lt;p&gt;That's it. Nobody set out to create a fancy "state as glue between UI and logic" philosophy. We just wanted a clean way to reuse data across the UI.&lt;/p&gt;

&lt;p&gt;There's one important clarification: "single source of truth" does not mean "only create states that are used in multiple places". Even if a piece of data is used in just one place, managing it via state is still valid—because it might be needed elsewhere in the future. Using a state makes it easy to extend usage without major rewrites.&lt;/p&gt;

&lt;p&gt;The real rule is: don't create unnecessary state.&lt;/p&gt;

&lt;p&gt;Here's an example of unnecessary state:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;// BAD: Do not do this.&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AnalyticsState&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;trackAnalyticsEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;AnalyticsService&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;trackEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&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;This is not a real state. It doesn't hold or modify any data. Subscribing to it would provide no benefit. In this case, you should just call &lt;code&gt;AnalyticsService&lt;/code&gt; directly—there's no need to wrap it in a state class.&lt;/p&gt;

&lt;h2&gt;
  
  
  1 data point per state — plus optional metadata
&lt;/h2&gt;

&lt;p&gt;One of the most common mistakes in state management is creating a separate state for each page of the application. Developers often lump every single piece of data used on a page into the same container.&lt;/p&gt;

&lt;p&gt;Let's look at an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;// BAD: Don't do this.&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MainPageState&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;User&lt;/span&gt; &lt;span class="n"&gt;viewer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ChatRoom&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;chatRooms&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;isSideBarOpen&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;isCreateChatRoomDialogOpen&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// Setters/getters/methods below...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why is this a bad idea? There are several reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;It makes data non-reusable.&lt;br&gt;
For example, if you want to open the "Create Chat Room" dialog from somewhere other than the main page, you'd have to duplicate the &lt;code&gt;isCreateChatRoomDialogOpen&lt;/code&gt; flag in another state. This leads to code duplication and violates the DRY principle.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;It breaks SOLID principles.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Single Responsibility Principle: The state now has multiple reasons to change. If you want to modify viewer data, you edit &lt;code&gt;MainPageState&lt;/code&gt;. If you want to change how the sidebar opens, you edit the same class again.&lt;/li&gt;
&lt;li&gt;Open/Closed Principle: Adding a new feature or data point means editing this class, rather than extending functionality with new, focused classes.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;A better approach is to extract each meaningful piece of data into its own dedicated state:&lt;br&gt;
&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;ViewerState&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ChatRoomsState&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SideBarState&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CreateChatRoomDialogState&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This leads to a key insight:&lt;br&gt;
A good state holds a single, small, but meaningful piece of data.&lt;/p&gt;

&lt;p&gt;What does "small yet reasonable" mean?&lt;/p&gt;

&lt;p&gt;Let's take the example of the currently logged-in user. It makes sense to have a &lt;code&gt;ViewerState&lt;/code&gt; that holds a &lt;code&gt;User&lt;/code&gt; object. This is a single logical unit of data.&lt;/p&gt;

&lt;p&gt;However, adding something like &lt;code&gt;userHasOpenedLoginDialog&lt;/code&gt; to &lt;code&gt;ViewerState&lt;/code&gt; would be wrong. That piece of UI-related metadata belongs in its own state. When we think about a "user," we think about their name, email, ID—not whether a dialog is currently open.&lt;/p&gt;

&lt;p&gt;On the other hand, splitting &lt;code&gt;ViewerState&lt;/code&gt; into &lt;code&gt;ViewerFirstNameState&lt;/code&gt;, &lt;code&gt;ViewerLastNameState&lt;/code&gt;, etc., would also be a mistake. Over-fragmenting a small object into many microstates provides no benefit and introduces unnecessary complexity.&lt;/p&gt;

&lt;p&gt;To be clear: I'm not saying that objects should never be broken down. If an object grows too large, you should break it into smaller parts. But in cases like this, a single &lt;code&gt;ViewerState&lt;/code&gt; is perfectly reasonable and more maintainable.&lt;/p&gt;
&lt;h3&gt;
  
  
  Optional additional metadata
&lt;/h3&gt;

&lt;p&gt;As the previous rule mentions, we also have the option to include additional metadata in a state. But what exactly is metadata?&lt;/p&gt;

&lt;p&gt;Metadata is simply "data about data". In practical terms, when we load some data, we often want to track information about that process:&lt;br&gt;
Is it currently loading? Did it fail? How many times have we retried it? When did the request start?&lt;/p&gt;

&lt;p&gt;Let's look at an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;// A state that includes both data and metadata.&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ChatRoomsState&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Metadata&lt;/span&gt;
  &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;isDataLoading&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;loadingError&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;hasLoadingFailed&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;hasLoadingBeenRetried&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;num&lt;/span&gt; &lt;span class="n"&gt;amountOfLoadingRetries&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;DateTime&lt;/span&gt; &lt;span class="n"&gt;loadingRequestedAt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// Actual data&lt;/span&gt;
  &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ChatRoom&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;chatRooms&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;It generally makes sense to keep metadata as close to the data as possible. That way, everything related to a particular state lives in one place. However, if your app architecture calls for it, you can extract metadata into a separate state—it depends on what makes the most sense for your use case.&lt;/p&gt;

&lt;p&gt;You can also improve the example above by grouping the metadata into a nested object. For example:&lt;br&gt;
&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;ChatRoomsState&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="n"&gt;LoadableState&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ChatRoom&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;ChatRoomsStateMetaData&lt;/span&gt; &lt;span class="n"&gt;metaData&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ChatRoomsStateMetaData&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;isDataLoading&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;loadingError&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;hasLoadingFailed&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;hasLoadingBeenRetried&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;num&lt;/span&gt; &lt;span class="n"&gt;amountOfLoadingRetries&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;DateTime&lt;/span&gt; &lt;span class="n"&gt;loadingRequestedAt&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;Whether this structure is better is subjective. It's up to you to decide if the separation makes your code more readable or maintainable. Use it if it fits your style or project needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  State methods must set or return data. No side effects of any kind
&lt;/h2&gt;

&lt;p&gt;As we discussed earlier, doing any side effects inside state methods is a bad idea.&lt;/p&gt;

&lt;p&gt;When it comes to classes and restrictions, it's actually not uncommon to set healthy boundaries. For instance, it's very common to use the Repository pattern to deal with remote data. Here's an example of a repository:&lt;br&gt;
&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;ChatRoomsGetterRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ChatRooms&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;getChatRooms&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'/api/chat-rooms'&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;data&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;This class does only a single thing: it downloads remote data. It doesn't do anything else. It doesn't record analytics data, it doesn't modify the UI. It's basically an abstraction, a contract. We don't know how it downloads the data or where it gets it from. We only know that if we use this class, we will receive a list of chat rooms.&lt;/p&gt;

&lt;p&gt;This repository is useful because it encapsulates logic and allows us to replace the data source without too much hassle.&lt;/p&gt;

&lt;p&gt;Let's say we decided to migrate from REST to GraphQL. We can either rewrite the logic of &lt;code&gt;ChatRoomsGetterRepository&lt;/code&gt; or we can create a &lt;code&gt;ChatRoomsGraphqlGetterRepository&lt;/code&gt; with the same interface and simply replace the class. In the end, changing the source of chat rooms will not break anything else in our app.&lt;/p&gt;

&lt;p&gt;This pattern is commonly used and its usefulness is undeniable. In my opinion, good states should be treated the same as repositories. These are classes that do very little: they hold and modify a small amount of data. We don't know how exactly they're doing it and we don't care. We only know that they cannot do anything else, and when we call state methods, a certain piece of data is going to be updated. They are simple and obvious.&lt;/p&gt;

&lt;p&gt;Let's consider an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;// BAD STATE. Don't do this.&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ViewerState&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="n"&gt;viewer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="n"&gt;logout&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;What is wrong with this state, you may ask? Well, for instance, "logout" assumes that a lot of actions are going to happen when this method is invoked: a network request will be made, cache will be cleared, local storage will be erased, an analytics event will be recorded, most of the UI will be updated.&lt;/p&gt;

&lt;p&gt;On the other hand, this snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;// GOOD.&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ViewerState&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="n"&gt;viewer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;setViewer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="n"&gt;unsetViewer&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;does not have such assumptions. When you invoke "unsetViewer," it's obvious that only the state is going to change. The logged-in user object is going to be removed from the state. That's it. There are no side effects. No complications.&lt;/p&gt;

&lt;p&gt;This state is simple, obvious, and predictable.&lt;/p&gt;

&lt;p&gt;Another way to think about states is to treat them as &lt;strong&gt;micro databases&lt;/strong&gt;. Imagine a database that can only hold a very limited amount of data (a primitive, an object, or a list of objects). This database can only hold and modify its data. A database cannot and should not make API requests, update other databases, or force the UI to display notifications.&lt;/p&gt;

&lt;h2&gt;
  
  
  The less logic there is in a state, the better
&lt;/h2&gt;

&lt;p&gt;Note: a quick reminder. "Logic" in most cases means "business rules".&lt;/p&gt;

&lt;p&gt;It's very tempting to put logic inside your states. But by doing so, you might end up with the same problems as with side effects: by trying to reuse code in an improper place, you will eventually shoot yourself in the foot. Too much logic in states makes them unobvious and unpredictable.&lt;/p&gt;

&lt;p&gt;Let's say we need to display to the user the number of participants in a chatroom. Please consider this code snippet:&lt;br&gt;
&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;ChatRoomState&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;getNumberOfParticipants&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;Let's say the number is 101. But inside the settings page of this chat room, we also must display the number of participants. Though this number must be lower if the currently logged-in user is the creator of this chat room. Therefore, on the main chat room page, the number of participants would be 101, but on the settings page, the number would be 100. Such is the business requirement.&lt;/p&gt;

&lt;p&gt;This means that even though we are using the same data in two places of the application, that data must be slightly different in one of them. We must add a special check somewhere to change the number of participants. The question is: where would you put it?&lt;/p&gt;

&lt;p&gt;You might be tempted to change the state and add a special method:&lt;br&gt;
&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;ChatRoomState&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;getNumberOfParticipants&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;getNumberOfParticipantsWithoutAdmins&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;Or you might want to add a flag to an existing method:&lt;br&gt;
&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;ChatRoomState&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;getNumberOfParticipants&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;isNumberOfAdminsRemoved&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;Sadly, both of these solutions would be wrong because changing the state to fit a special use case opens the door to unobvious and unmaintainable states. For example, let's say after a while we receive new business requirements and now we need to display 0 participants for chatrooms that are marked as "private"? In that case, we will have to somehow check if the logged-in user is a member of the chatroom and if they should have access to this information. Since previously we were putting the logic regarding chat room participants inside the state, we will have to continue doing so. With time, the state will become more and more bloated and less and less predictable.&lt;/p&gt;

&lt;p&gt;Just to clarify: this rule does not mean that adding new methods to states is completely prohibited.&lt;/p&gt;

&lt;p&gt;Let's say we have a state that is responsible for the list of downloaded chat rooms:&lt;br&gt;
&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;ChatRoomsState&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ChatRoom&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;chatRooms&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;updatedChatRoomsList&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;In many parts of our application, we push new chat rooms to this list: after we created a chat room, after we were invited to the chat room, or for other reasons. In that case, it's quite handy to add a special method for it:&lt;br&gt;
&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;ChatRoomsState&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ChatRoom&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;chatRooms&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;updatedChatRoomsList&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="n"&gt;addChatRoom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newChatRoom&lt;/span&gt;&lt;span class="p"&gt;)&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;chatRooms&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newChatRoom&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;You might be wondering: what is the difference between the first example with the number of participants in a chat room where adding methods is bad and the current example? Well, it's simple: the first example adds business rules to the state, the second one simplifies the way we interact with the state. The second one is a shortcut for this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Before:&lt;/span&gt;
&lt;span class="n"&gt;newChatRoomsList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;chatRoomsState&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;chatRooms&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chatRoom&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;chatRoomsState&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newChatRoomsList&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// After:&lt;/span&gt;
&lt;span class="n"&gt;chatRoomsState&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addChatRoom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chatRoom&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even though the first example and the second one technically both add "logic" to states, the second one simplifies our life and the first one will eventually make our life harder.&lt;/p&gt;

&lt;p&gt;In conclusion: whenever you are unsure what to do, remember this rule—the less logic there is in a state, the better. Ideally, there should be a single "update()" method and nothing else. Though if it makes sense for your use case, do add new methods.&lt;/p&gt;

&lt;h2&gt;
  
  
  More complicated example
&lt;/h2&gt;

&lt;p&gt;Simple examples are good to understand the basics of the idea. But what is often missing is something more complicated to make sure you can apply the idea in practice. Because reality is always far more complicated and always forces you to reinvent the wheel.&lt;/p&gt;

&lt;p&gt;Let's say you were hired to work on a Twitch.tv-like website. On this site, you can watch people stream games, you can participate in the chat, subscribe to the streamer, and so on. Your first task is to add the ability to donate money to a streamer you are watching. How would you go about doing that task?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Task requirements:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The number of dollars in the wallet must decrease.&lt;/li&gt;
&lt;li&gt;The number of experience points must increase. (Context: users of our app can level up their profiles based on certain actions)&lt;/li&gt;
&lt;li&gt;The chat must display "X donated Y$ to the streamer" announcement.&lt;/li&gt;
&lt;li&gt;These changes to the UI must happen BEFORE network requests are fired/completed (this technique is called "optimistic UI").&lt;/li&gt;
&lt;li&gt;A "Success!" snackbar must be displayed if network requests were successful.&lt;/li&gt;
&lt;li&gt;A "Something went wrong." snackbar must be displayed if network requests were unsuccessful.&lt;/li&gt;
&lt;li&gt;All of the UI changes must be reverted if the API responded with an error.&lt;/li&gt;
&lt;li&gt;Donation success or failure must trigger an appropriate analytics event.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Before we jump into the implementation, let's take a look at how developers usually approach the development. Let's read code that was written via states that contain logic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;// BAD. DON'T DO THIS.&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DonationsState&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;= First problem.&lt;/span&gt;
  &lt;span class="n"&gt;donateToStreamer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;globalLoadingIndicatorState&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setIsLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;walletState&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;subtractFunds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;= Second problem.&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;viewerState&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addExperience&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;= Second problem.&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;activeChatState&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;announceDonation&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;= Second problem.&lt;/span&gt;

      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;submitDonationRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;analyticsTracker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;trackDonationToStreamer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="n"&gt;snackBarService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;displaySnackbar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Success!'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;= Third problem.&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;walletState&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addFunds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;= Fourth problem.&lt;/span&gt;
      &lt;span class="n"&gt;viewerState&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;subtractExperience&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;= Fourth problem.&lt;/span&gt;

      &lt;span class="n"&gt;activeChatState&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;removeDonationAnnouncement&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

      &lt;span class="n"&gt;analyticsTracker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;trackDonationToUserFailure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;reason:&lt;/span&gt; &lt;span class="n"&gt;error&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="n"&gt;snackBarService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;displaySnackbar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Oops, something went wrong'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;globalLoadingIndicatorState&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setIsLoading&lt;/span&gt;&lt;span class="p"&gt;(&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Descriptions of problems:&lt;/p&gt;

&lt;p&gt;1) A state without data defeats its purpose. What is the point of subscribing to it if it doesn't have any data? And if you don't plan on subscribing to it, then it's not a state.&lt;/p&gt;

&lt;p&gt;2) These state methods can internally call other state methods. When you read this code, you cannot be sure that the app will do exactly the things you want it to do. The behavior is unpredictable.&lt;/p&gt;

&lt;p&gt;3) Can you be sure that this service doesn't internally change states? Pretty much the same problem as in the previous point but with more steps.&lt;/p&gt;

&lt;p&gt;4) Without reading the implementation of these methods, can you be sure that they will do what you want of them? "walletState.addFunds" implies that we are giving money back to the user (we are increasing the amount of numbers in the UI in front of their eyes) because for whatever reason the network request failed. This means we only want to change the state (the state properties) without any side effects. We don't want any HTTP requests done, we don't want any extra snackbars to pop up. Are you sure that this method will do only that? And can you be sure that somebody won't change the implementation in the future? I highly doubt it.&lt;/p&gt;

&lt;p&gt;As you can imagine, this code will be hard to maintain and you're always going to have a feeling that anything can break at any point in the future. You can't rely on it. It's unpredictable.&lt;/p&gt;

&lt;p&gt;Let's take a look at the code where logic was extracted from the states. Here's how Predictable State Management looks in practice:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;// GOOD. DO THIS.&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DonateToStreamerUseCase&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;donateToStreamer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;globalLoadingIndicatorState&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setIsLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;activeChatState&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;announceDonation&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="n"&gt;walletState&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;subtractFunds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;viewerState&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addExperience&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;subtractFundsRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;subtract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;addExperienceRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;submitDonationRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="n"&gt;analyticsTracker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;trackDonationToStreamer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="n"&gt;snackBarService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;displaySnackbar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Donation successful!'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;walletState&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addFunds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;viewerState&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;subtractExperience&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="n"&gt;activeChatState&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;removeDonationAnnouncement&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

      &lt;span class="n"&gt;analyticsTracker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;trackDonationToUserFailure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;reason:&lt;/span&gt; &lt;span class="n"&gt;error&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="n"&gt;snackBarService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;displaySnackbar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Oops, something went wrong'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;globalLoadingIndicatorState&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setIsLoading&lt;/span&gt;&lt;span class="p"&gt;(&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, we did two things here: 1) we turned the class from a state into a use case and 2) we extracted all repositories from states. By doing so, we gain predictability and control over our code. And the ability to have total control over what happens in your app is the main point of this article. With this new way of writing code, you will be able to introduce any kind of changes. You want to make sure that the user has enough funds by making a special request to the API? Not a problem. You want to remove the global loading indicator and instead use the "isLoading" property of walletState? Sure, not a problem. You want to display errors by using activeChatState instead of a snackbar? You can do so by rewriting 4 lines of code instead of rewriting 4 methods.&lt;/p&gt;

&lt;p&gt;Even though predictability is amazing, the only downside of this approach is it's harder to reuse code now. Let's say that each time we award the user with experience, we also want to check if the user has enough points to level up. If they do, we want to display some kind of leveling up animation, track an analytics event, and make an API request.&lt;/p&gt;

&lt;p&gt;In that case, we are faced with a dilemma. Do we place all this leveling code into a service and lose predictability and control? Think of the "Optimistic UI" requirement of our task; with a separate service, it will be hard to implement it.&lt;/p&gt;

&lt;p&gt;How do we reuse code and keep predictability? That is a topic for our next conversation. TO BE CONTINUED.&lt;/p&gt;

&lt;h2&gt;
  
  
  Predictable vs unpredictable (properties comparison)
&lt;/h2&gt;

&lt;p&gt;Unpredictable states:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Contain multiple data points&lt;/li&gt;
&lt;li&gt;Have methods with side effects&lt;/li&gt;
&lt;li&gt;Can have unobvious method names&lt;/li&gt;
&lt;li&gt;Have no rules on how to use states&lt;/li&gt;
&lt;li&gt;Contain business rules of the application&lt;/li&gt;
&lt;li&gt;Do not follow SOLID principles. Mainly S and O&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Predictable states:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Contain only a single point of data&lt;/li&gt;
&lt;li&gt;Have methods that only change data of the state. No side effects of any kind&lt;/li&gt;
&lt;li&gt;Have obvious method names&lt;/li&gt;
&lt;li&gt;Have specific rules&lt;/li&gt;
&lt;li&gt;Act as containers for data. They do not contain business rules&lt;/li&gt;
&lt;li&gt;Follow SOLID principles.
Predictable states have only a single reason to change and new functionality is added by adding new states instead of extending existing ones&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Additional Benefits of PSM
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Easier maintenance and onboarding of new developers
&lt;/h3&gt;

&lt;p&gt;When logic is extracted out of states, it's usually placed inside Controllers or Use Cases. Compared to the previous approach where logic was mixed between the view layer, states, and controllers, this allows developers to more easily understand the business rules of the application.&lt;/p&gt;

&lt;p&gt;This also makes onboarding of new developers easier and reduces the "bus factor".&lt;/p&gt;

&lt;h3&gt;
  
  
  Undo/redo functionality
&lt;/h3&gt;

&lt;p&gt;When your states do not contain any logic or side effects, it's extremely easy to roll back state changes.&lt;br&gt;
&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;UndoableCounterState&lt;/span&gt; &lt;span class="p"&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;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;_stateHistory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

  &lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newCounterValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;_stateHistory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="p"&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;newCounterValue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;undo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&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;_stateHistory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;last&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;_stateHistory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;removeLast&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;h2&gt;
  
  
  Why do people get away with unpredictable states?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Short answer:
&lt;/h3&gt;

&lt;p&gt;Developers don't actually get away with doing states wrong. The reason why it feels that way is because it takes time for problems to pop up. And by the time they encounter bugs and difficulties, they are so deep down the rabbit hole that it's impossible to see solutions to fundamental problems. Quick fixes and workarounds do help in the beginning but eventually make states unmaintainable in the long run.&lt;/p&gt;

&lt;h3&gt;
  
  
  Long answer:
&lt;/h3&gt;

&lt;p&gt;Since I claimed that most teams and companies make a lot of fundamental mistakes when it comes to working with state management, how come nobody has noticed any problems?&lt;/p&gt;

&lt;p&gt;As with anything, there are a lot of ways to do something wrong and only a limited number of ways to do something right.&lt;/p&gt;

&lt;p&gt;1) They don't.&lt;/p&gt;

&lt;p&gt;Usually, it takes a lot of time to get in a situation when adding new features or fixing a bug gets frustratingly difficult. By that time, it's too hard to tell where exactly everything went wrong. And even if developers encounter such problems sooner, they simply update the state code and move on. Mind you: adding more methods to states in order to add a feature breaks SOLID principles.&lt;/p&gt;

&lt;p&gt;2) People don't write anything complicated&lt;/p&gt;

&lt;p&gt;Let's face it: the lion's share of applications don't encounter any problems because their lack of complicated logic allows them to get away with it. I'm not saying that most applications were easy to build. But I am saying that most of them do not deal with interconnected states, multi-team environments, and long lists of business requirements for every user action. Usually, it's as simple as: download an object, use the object to display something to the user, update the object in the state when an action occurred.&lt;/p&gt;

&lt;p&gt;Their approach quickly falls apart when logic gets complicated. For instance, when a single action leads to a change of 5 different states and a call to 20 different services.&lt;/p&gt;

&lt;p&gt;3) People work in small teams and/or on small projects.&lt;/p&gt;

&lt;p&gt;When a developer encounters a problem (and all of them inevitably do as a project gets larger), it's easy to rewrite big chunks of the application if 3 people are working on it. However, when there are 20 teams and 100 developers working on a single app, then changing existing code quickly gets complicated.&lt;/p&gt;

&lt;p&gt;4) People don't care about doing things properly. They are blind to problems.&lt;/p&gt;

&lt;p&gt;When we encounter problems during development, we usually try to add a quick fix on top of the problem or we try to do a workaround instead. We add bad code on top of bad code instead of rewriting the bad parts. Basically, we are more focused on finishing a task and gaining short-term benefits. These benefits always hurt us in the long run.&lt;br&gt;
As it was said in "Clean Code" by Robert C. Martin (and I am heavily paraphrasing here): "We don't have time to write clean code, so we write bad code that will slow us down even more in the future".&lt;/p&gt;

</description>
      <category>javascript</category>
    </item>
    <item>
      <title>How to fix performance issues in Flutter</title>
      <dc:creator>Mikhail Palei</dc:creator>
      <pubDate>Sat, 05 Nov 2022 17:13:51 +0000</pubDate>
      <link>https://dev.to/undeadlol1/how-to-fix-performance-issues-in-flutter-1h3</link>
      <guid>https://dev.to/undeadlol1/how-to-fix-performance-issues-in-flutter-1h3</guid>
      <description>&lt;h1&gt;
  
  
  How to fix common performance issues in Flutter
&lt;/h1&gt;

&lt;p&gt;This article is a compilation of tips and tricks regarding performance of Flutter applications. Basically, these are the things I wish someone told me when I just started using Flutter.&lt;/p&gt;

&lt;p&gt;Please keep in mind that it is best to test performance on a real device and in profile mode. Though, personally I use debug mode far more often since it allows me to have an instant feedback about performance since profile mode does not support hot refresh or reload.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance overlay.
&lt;/h2&gt;

&lt;p&gt;Performance overlay is the easiest way to track performance degradation. It is accessible by calling “toggle performance overlay” action in VS Code and Android Studio. You can also enable it via DevTools.&lt;/p&gt;

&lt;p&gt;In short: the top row tracks performance of code. The bottom row displays performance of actual drawing of pixels. The top row is in your control. It is performance of your code. The bottom row is usually outside of your control.&lt;/p&gt;

&lt;p&gt;Both rows are horizontally divided into 16ms sections. To achieve 60 FPS you need to make sure that performance never goes above first section. If you spot that you cross these thresholds this usually means one of two things: you either doing too much things in the main thread and need to use isolates or you are doing too many things inside of your widget’s “build” method.&lt;/p&gt;

&lt;p&gt;In screenshot below you will notice that top row is spilling over the first section. This is bad.&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%2Fi84wzpoof940bzrapalc.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%2Fuploads%2Farticles%2Fi84wzpoof940bzrapalc.png" alt="Screenshot of performance overlay activated in Android Emulator."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Widget rebuilds counter.
&lt;/h2&gt;

&lt;p&gt;“Display widget rebuilds” is a neat tool that allows you to see how many times do your widgets activate “build” method. Sadly this tool is only available in Android Studio. Though I highly recommend using it even if you use different IDE. The data is simply too valuable to ignore.&lt;/p&gt;

&lt;p&gt;This tool is a table that has 3 rows: list of widgets that were built in the app, number of widget rebuilds during last frame and a combined number of all rebuilds. Obviously the less you rebuild a widget the better. Thus if you have a lot of total rebuilds you might investigate how you use animations, how often you update your widgets arguments and how often you change the state of stateful widgets (hint: use AnimatedBuilder instead of calling “setState” method for animations).&lt;/p&gt;

&lt;p&gt;In the screenshot below you can see that Text widget of MainPage (main_page.dart) have been built in total 3 times per session and only a single time in the last frame. Which is good. The less the better. The Text widget of TasksListItem on the other hand have been rebuild 259 times in a single frame. Which of course forced my app to lag.&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%2Fcmiytb4i36mftn71ig97.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%2Fuploads%2Farticles%2Fcmiytb4i36mftn71ig97.png" alt="Screenshot of widget rebuild stats."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Event loop and isolates.
&lt;/h2&gt;

&lt;p&gt;One of the most common problems inexperienced Flutter developers encounter is a strange lag during application start. It goes like this: you launch the app, you see some loading animation, then loading animation freezes and after a second the app unfreezes and operates normally. This happens because when you request data from a remote server and receive the JSON your app can’t do anything else beside parsing the JSON for a few moments. Think of it this way: let’s say you have a list of 100 documents and each document has 10 fields. When you receive this JSON your app will have to go line by line 1000 times in order to convert this JSONs into usable Dart objects. This of course freezes the UI for a few moments.&lt;/p&gt;

&lt;p&gt;To fix this you need to parse the JSON in a separate isolate. A quick reminder: Isolates are basically Darts equivalent of threads.&lt;/p&gt;

&lt;p&gt;Below you will find a snippet extracted from one of my apps. There is quite a bit of code but the important line is this one: &lt;code&gt;return compute(_parseListOfJsons, listOfJsons);&lt;/code&gt; This line creates a new thread and instructs it to run the parsing function on a list of JSONs.&lt;br&gt;
&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;GetTasksToDoRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;FirebaseFirestore&lt;/span&gt; &lt;span class="n"&gt;firestore&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;GetTasksToDoRepository&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="kd"&gt;required&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;firestore&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="kd"&gt;required&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;tasksSnapshot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;firestore&lt;/span&gt;
          &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'tasks'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'userId'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;isEqualTo:&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'isDone'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;isEqualTo:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;250&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

      &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;listOfJsons&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tasksSnapshot&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;docs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;e&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;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toList&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;compute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_parseListOfJsons&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;listOfJsons&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stackTrace&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nl"&gt;stackTrace:&lt;/span&gt; &lt;span class="n"&gt;stackTrace&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;rethrow&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="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_parseListOfJsons&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;dynamic&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;docs&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;docs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fromJson&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toList&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;h2&gt;
  
  
  Follow performance best practices.
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.flutter.dev/perf/best-practices" rel="noopener noreferrer"&gt;https://docs.flutter.dev/perf/best-practices&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Animations.
&lt;/h2&gt;

&lt;p&gt;It is important not to forget to attach &lt;code&gt;SingleTickerProviderStateMixin&lt;/code&gt;  or &lt;code&gt;TickerProviderStateMixin&lt;/code&gt;. Tickers keep animations in sync with screens. For example your animations won’t use any hardware resources if they are not visible to the user, i.e. when the app is running in the background or when the user navigated to a different route mid animation. They also “smooth” out animations by adapting them to the screen refresh rate.&lt;/p&gt;

&lt;p&gt;It is also incredibly important to use &lt;code&gt;AnimatedBuilder&lt;/code&gt; when ever possible. &lt;code&gt;AnimatedBuilder&lt;/code&gt; does two things:&lt;/p&gt;

&lt;p&gt;1) It allows us to rebuild only the necessary widgets during animation.&lt;/p&gt;

&lt;p&gt;2) It allows us to to stop using  &lt;code&gt;_animation.addListener(() =&amp;gt; setState(() {}))&lt;/code&gt; to activate the animation. Why is it important to drop &lt;code&gt;setState&lt;/code&gt;? Because we don’t want to repaint widgets 60 times per second. It will inevitably lead to jank.&lt;/p&gt;

&lt;p&gt;See &lt;a href="https://api.flutter.dev/flutter/widgets/AnimatedBuilder-class.html" rel="noopener noreferrer"&gt;https://api.flutter.dev/flutter/widgets/AnimatedBuilder-class.html&lt;/a&gt; for more information.&lt;/p&gt;

&lt;h2&gt;
  
  
  Shaders and initial jank.
&lt;/h2&gt;

&lt;p&gt;When your app is first loaded you may notice that animations are janky. This jank is usually easy to spot when scrolling or jumping between router pages. This happens because Flutters rendering engine does not yet have required shaders to display smooth animations. This is fixable via compiling shaders manually. See the instructions here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.flutter.dev/perf/shader" rel="noopener noreferrer"&gt;https://docs.flutter.dev/perf/shader&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note: the first time I read the instructions they seemed too daunting to me. Fear not my friend. They are actually quite simple: run the app, play with animations, build the app with produced shaders file.&lt;/p&gt;

&lt;h2&gt;
  
  
  Repaint rainbow and RepaintBoundary.
&lt;/h2&gt;

&lt;p&gt;As we know Flutter repaints (rebuilds) widgets a lot even if there are no changes to widgets arguments. In order to spot this repaints you need to enable a special development feature that is going to highlight all of the repaints of the application. I highly recommend you to &lt;/p&gt;

&lt;p&gt;I highly encourage you to always have this option enabled during development to spot the unwanted repaints as early as possible. Place this snippet before your &lt;code&gt;runApp()&lt;/code&gt; in &lt;code&gt;main.dart&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;debugRepaintRainbowEnabled = kDebugMode;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In fact you will be surprised how many widgets are being repainted for no good reason. For instance: once I created a very simple countdown widget. All it was supposed to do is to display a single line of text that said: “You have 60 seconds left” and each second the number would decrease. This widget used only local state (it was a stateful widget) and it didn’t have any outside dependencies. Yet when I enabled repaint rainbow I was shocked to witness that somehow once a second whole screen of the application was repainted. What I expected to see is a single &lt;code&gt;Text&lt;/code&gt; widget to be repainted.&lt;/p&gt;

&lt;p&gt;The solution was to wrap my widget with &lt;code&gt;RepaintBoundary&lt;/code&gt; widget. When it was applied only the &lt;code&gt;Text&lt;/code&gt; widget was repainted once a second instead of the whole screen.&lt;/p&gt;

&lt;p&gt;Important: do not use &lt;code&gt;RepaintBoundary&lt;/code&gt; excessively. If misused this widget will put too much strain on the hardware and FPS will decrease.&lt;/p&gt;

&lt;h2&gt;
  
  
  Repaints caused by state changes.
&lt;/h2&gt;

&lt;p&gt;When using state management libraries it is always a good idea to place state builders as close to consumers as possible. Let me demonstrate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;// BAD.&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BadBuilderExample&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="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;BadBuilderExample&lt;/span&gt;&lt;span class="p"&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;key&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;key:&lt;/span&gt; &lt;span class="n"&gt;key&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;BlocBuilder&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ProfileCubit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ProfileState&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;builder:&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="n"&gt;profileState&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;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;[&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;profileState&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;profile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;CreatePostForm&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="n"&gt;Posts&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="c1"&gt;// GOOD.&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GoodBuilderExample&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="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;GoodBuilderExample&lt;/span&gt;&lt;span class="p"&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;key&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;key:&lt;/span&gt; &lt;span class="n"&gt;key&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;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;[&lt;/span&gt;
        &lt;span class="n"&gt;BlocBuilder&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ProfileCubit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ProfileState&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;
          &lt;span class="nl"&gt;buildWhen:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;previous&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;current&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;previous&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;profile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;profile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nl"&gt;builder:&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="n"&gt;profileState&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;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;profileState&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;profile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&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;CreatePostForm&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="n"&gt;Posts&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;In BadBuilderExample every change to ProfileCubit will force the whole widget to be repainted. In GoodBuilderExample only the Text widget will be repainted. Also, notice how I threw in &lt;code&gt;buildWhen&lt;/code&gt; into the &lt;code&gt;BlocBuilder&lt;/code&gt; this function will make sure that widget will be rebuilt only when &lt;code&gt;profile.name&lt;/code&gt; changes. This will reduce rebuilds to an absolute minimum.&lt;/p&gt;

&lt;p&gt;Even though I used BloC for this demonstration please remember that the general idea is important. Whatever you are doing, whatever library you are using, keep builders as close to consumers as possible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where to go from here.
&lt;/h2&gt;

&lt;p&gt;Flutter is one of those tools that is all about how you use it. If you don’t know what you are doing you will be punished with bad performance. If you are skilled you will be rewarded with silky smooth UI. Even though this article will help you to solve 90% of your problems you might want to keep improving your knowledge. The best way to do so is to learn Flutter DevTools. Here is a good overview to get you up and running:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=nq43mP7hjAE" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=nq43mP7hjAE&lt;/a&gt;&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>performance</category>
      <category>dart</category>
      <category>mobile</category>
    </item>
  </channel>
</rss>
