<?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: Leandro Boeing Vieira</title>
    <description>The latest articles on DEV Community by Leandro Boeing Vieira (@lepsistemas).</description>
    <link>https://dev.to/lepsistemas</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F472387%2F80e082cf-997e-4c67-9a59-ba254eece777.jpg</url>
      <title>DEV Community: Leandro Boeing Vieira</title>
      <link>https://dev.to/lepsistemas</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/lepsistemas"/>
    <language>en</language>
    <item>
      <title>Repository Harness, Part 2: 30 Runs Later, It Wasn’t Cheaper. It Was More Predictable.</title>
      <dc:creator>Leandro Boeing Vieira</dc:creator>
      <pubDate>Mon, 20 Jul 2026 19:24:35 +0000</pubDate>
      <link>https://dev.to/lepsistemas/repository-harness-part-2-30-runs-later-it-wasnt-cheaper-it-was-more-predictable-1d8p</link>
      <guid>https://dev.to/lepsistemas/repository-harness-part-2-30-runs-later-it-wasnt-cheaper-it-was-more-predictable-1d8p</guid>
      <description>&lt;p&gt;This is the follow-up to &lt;a href="https://dev.to/lepsistemas/coding-agents-evolved-our-repositories-didnt-f4"&gt;&lt;strong&gt;Coding Agents Evolved. Our Repositories Didn’t.&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;My first Repository Harness benchmark produced an uncomfortable result.&lt;/p&gt;

&lt;p&gt;The Harness completed the task faster than a monolithic &lt;code&gt;AGENTS.md&lt;/code&gt;, but it used more fresh input tokens.&lt;/p&gt;

&lt;p&gt;That could have meant the idea was wrong.&lt;/p&gt;

&lt;p&gt;It could also have meant that my first implementation of progressive disclosure was not strict enough.&lt;/p&gt;

&lt;p&gt;So I changed the routing model, rebuilt the benchmark baseline, and ran the experiment again.&lt;/p&gt;

&lt;p&gt;This time, I ran 30 measured executions.&lt;/p&gt;

&lt;p&gt;The result was not a dramatic reduction in token usage.&lt;/p&gt;

&lt;p&gt;It was something more useful:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The Repository Harness made the agent’s behavior substantially more predictable.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The idea
&lt;/h2&gt;

&lt;p&gt;Most repositories expose their knowledge through a mix of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;README files;&lt;/li&gt;
&lt;li&gt;architecture documents;&lt;/li&gt;
&lt;li&gt;contribution guides;&lt;/li&gt;
&lt;li&gt;scripts;&lt;/li&gt;
&lt;li&gt;tribal knowledge;&lt;/li&gt;
&lt;li&gt;one increasingly large &lt;code&gt;AGENTS.md&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A monolithic instruction file works, but every task receives the complete repository handbook, even when most of it is irrelevant.&lt;/p&gt;

&lt;p&gt;The Repository Harness replaces that model with a small entry point and routed context:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AGENTS.md
    ↓
.harness/
├── harness.yaml
├── project-specific guidance
├── engineering guidance
└── asset guidance
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The root file explains how to use the Harness.&lt;/p&gt;

&lt;p&gt;The manifest classifies the task and selects the repository guidance required for that task.&lt;/p&gt;

&lt;p&gt;The original hypothesis was:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Selective context routing should preserve implementation quality while reducing unnecessary context.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The first benchmark did not prove that.&lt;/p&gt;

&lt;h2&gt;
  
  
  What changed in version 2
&lt;/h2&gt;

&lt;p&gt;The first Harness used broad loading rules such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;load_when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;implementation&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;feature&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;validation&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Those labels were too general.&lt;/p&gt;

&lt;p&gt;Almost every coding task is an implementation. Many tasks are features. Every completed task needs validation.&lt;/p&gt;

&lt;p&gt;The agent therefore had a reasonable incentive to load most of the documentation.&lt;/p&gt;

&lt;p&gt;I had modularized the repository knowledge.&lt;/p&gt;

&lt;p&gt;I had not created strict routing.&lt;/p&gt;

&lt;p&gt;The second version added:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;repository-defined concerns;&lt;/li&gt;
&lt;li&gt;directory scopes;&lt;/li&gt;
&lt;li&gt;required and optional context;&lt;/li&gt;
&lt;li&gt;escalation rules;&lt;/li&gt;
&lt;li&gt;context budgets;&lt;/li&gt;
&lt;li&gt;route-specific validation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Before explaining how that routing behaved, it helps to understand the repository used in the experiment.&lt;/p&gt;

&lt;h2&gt;
  
  
  The benchmark project
&lt;/h2&gt;

&lt;p&gt;The benchmark used a real game project built with Godot and C#.&lt;/p&gt;

&lt;p&gt;The task was a gameplay-input change involving camera controls.&lt;/p&gt;

&lt;p&gt;The agent needed to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;move gamepad zoom from the triggers to the vertical right-stick axis;&lt;/li&gt;
&lt;li&gt;preserve horizontal right-stick rotation;&lt;/li&gt;
&lt;li&gt;preserve mouse-wheel zoom;&lt;/li&gt;
&lt;li&gt;add horizontal mouse movement rotation;&lt;/li&gt;
&lt;li&gt;update relevant prompts and tests;&lt;/li&gt;
&lt;li&gt;avoid breaking gameplay and menus.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This repository was useful for the experiment because it contained different kinds of knowledge:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Godot and gameplay conventions
general engineering rules
asset rules
validation commands
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A camera-input task should need the Godot-specific guidance.&lt;/p&gt;

&lt;p&gt;It should not need asset guidance.&lt;/p&gt;

&lt;p&gt;It should only need broader engineering guidance if the implementation crosses an architectural boundary.&lt;/p&gt;

&lt;p&gt;That made the task a practical test of selective routing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The two variants
&lt;/h2&gt;

&lt;p&gt;I created two isolated versions of the same repository.&lt;/p&gt;

&lt;h3&gt;
  
  
  Monolithic variant
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AGENTS.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All repository guidance lived in one concise root document.&lt;/p&gt;

&lt;h3&gt;
  
  
  Harness variant
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AGENTS.md
.harness/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The root file acted as an entry point.&lt;/p&gt;

&lt;p&gt;The Harness contained:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.harness/
├── harness.yaml
├── GODOT.md
├── ENGINEERING.md
└── ASSETS.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For this camera-input task, the expected route was:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AGENTS.md
+ .harness/harness.yaml
+ .harness/GODOT.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Across all 15 measured Harness runs, the agent inspected the manifest and the Godot-specific guidance without loading the unrelated engineering or asset documents.&lt;/p&gt;

&lt;p&gt;That confirmed that the routing mechanism itself was working.&lt;/p&gt;

&lt;p&gt;The remaining question was whether it improved the complete execution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benchmark design
&lt;/h2&gt;

&lt;p&gt;Both variants used the same:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;coding agent;&lt;/li&gt;
&lt;li&gt;model;&lt;/li&gt;
&lt;li&gt;source-code baseline;&lt;/li&gt;
&lt;li&gt;implementation prompt;&lt;/li&gt;
&lt;li&gt;test suite;&lt;/li&gt;
&lt;li&gt;acceptance criteria.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I ran:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;3 warm-ups per variant
15 measured runs per variant
30 measured runs total
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The order alternated between variants.&lt;/p&gt;

&lt;p&gt;The prompt was identical in every run.&lt;/p&gt;

&lt;p&gt;Each repository started from a clean, frozen commit.&lt;/p&gt;

&lt;p&gt;Every measured execution satisfied the benchmark acceptance criteria.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AGENTS:  15/15 accepted
HARNESS: 15/15 accepted
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Harness did not reduce reliability.&lt;/p&gt;

&lt;h2&gt;
  
  
  The average results were almost tied
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;AGENTS&lt;/th&gt;
&lt;th&gt;Harness&lt;/th&gt;
&lt;th&gt;Harness difference&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Duration&lt;/td&gt;
&lt;td&gt;188.36 s&lt;/td&gt;
&lt;td&gt;185.61 s&lt;/td&gt;
&lt;td&gt;-1.46%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Total input tokens&lt;/td&gt;
&lt;td&gt;803,295&lt;/td&gt;
&lt;td&gt;829,006&lt;/td&gt;
&lt;td&gt;+3.20%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Uncached input tokens&lt;/td&gt;
&lt;td&gt;63,147&lt;/td&gt;
&lt;td&gt;61,859&lt;/td&gt;
&lt;td&gt;-2.04%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output tokens&lt;/td&gt;
&lt;td&gt;5,947&lt;/td&gt;
&lt;td&gt;5,630&lt;/td&gt;
&lt;td&gt;-5.32%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reasoning tokens&lt;/td&gt;
&lt;td&gt;987&lt;/td&gt;
&lt;td&gt;952&lt;/td&gt;
&lt;td&gt;-3.63%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Commands&lt;/td&gt;
&lt;td&gt;14.40&lt;/td&gt;
&lt;td&gt;14.53&lt;/td&gt;
&lt;td&gt;+0.93%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Failed commands&lt;/td&gt;
&lt;td&gt;6.07&lt;/td&gt;
&lt;td&gt;7.00&lt;/td&gt;
&lt;td&gt;+15.38%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Changed files&lt;/td&gt;
&lt;td&gt;6.20&lt;/td&gt;
&lt;td&gt;6.00&lt;/td&gt;
&lt;td&gt;-3.23%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The Harness was slightly faster.&lt;/p&gt;

&lt;p&gt;It used slightly fewer uncached input tokens and produced less output.&lt;/p&gt;

&lt;p&gt;It also used more total input tokens and executed more failed commands.&lt;/p&gt;

&lt;p&gt;None of those mean differences was large enough to justify a strong claim that the Harness was reliably faster or cheaper.&lt;/p&gt;

&lt;p&gt;The honest conclusion is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Average efficiency was approximately tied.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That was not the most important result.&lt;/p&gt;

&lt;h2&gt;
  
  
  The routed context was only modestly smaller
&lt;/h2&gt;

&lt;p&gt;The concise monolithic &lt;code&gt;AGENTS.md&lt;/code&gt; was roughly 14 KB.&lt;/p&gt;

&lt;p&gt;The Harness route loaded about:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;small AGENTS.md       ~0.8 KB
harness.yaml          ~3.3 KB
GODOT.md              ~7.3 KB
--------------------------------
routed context       ~11.5 KB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Harness successfully avoided unrelated documents, but the direct reduction was only a few kilobytes.&lt;/p&gt;

&lt;p&gt;That is small compared with a complete agent execution containing source files, search results, command output, tests, diffs, and repeated tool context.&lt;/p&gt;

&lt;p&gt;The experiment averaged roughly 62,000 uncached input tokens per run.&lt;/p&gt;

&lt;p&gt;Saving a few kilobytes of instructions was unlikely to transform the total.&lt;/p&gt;

&lt;p&gt;This changed the main question.&lt;/p&gt;

&lt;p&gt;The Harness may not primarily optimize the size of the initial prompt.&lt;/p&gt;

&lt;p&gt;It may optimize how consistently the agent navigates the rest of the task.&lt;/p&gt;

&lt;h2&gt;
  
  
  The strongest result was lower variance
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;AGENTS standard deviation&lt;/th&gt;
&lt;th&gt;Harness standard deviation&lt;/th&gt;
&lt;th&gt;Reduction&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Duration&lt;/td&gt;
&lt;td&gt;46.67 s&lt;/td&gt;
&lt;td&gt;25.10 s&lt;/td&gt;
&lt;td&gt;46.2%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Total input tokens&lt;/td&gt;
&lt;td&gt;239,991&lt;/td&gt;
&lt;td&gt;108,745&lt;/td&gt;
&lt;td&gt;54.7%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Uncached input tokens&lt;/td&gt;
&lt;td&gt;19,211&lt;/td&gt;
&lt;td&gt;9,855&lt;/td&gt;
&lt;td&gt;48.7%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output tokens&lt;/td&gt;
&lt;td&gt;1,430&lt;/td&gt;
&lt;td&gt;772&lt;/td&gt;
&lt;td&gt;46.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Commands&lt;/td&gt;
&lt;td&gt;3.27&lt;/td&gt;
&lt;td&gt;1.13&lt;/td&gt;
&lt;td&gt;65.6%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;In this sample, the Harness produced:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;46% less variation in duration;&lt;/li&gt;
&lt;li&gt;55% less variation in total input;&lt;/li&gt;
&lt;li&gt;49% less variation in uncached input;&lt;/li&gt;
&lt;li&gt;46% less variation in output;&lt;/li&gt;
&lt;li&gt;66% less variation in command count.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I did not begin this project with variance as the primary hypothesis.&lt;/p&gt;

&lt;p&gt;But predictability may matter more than a small improvement in the mean.&lt;/p&gt;

&lt;p&gt;Lower variance improves:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;cost forecasting;&lt;/li&gt;
&lt;li&gt;CI capacity planning;&lt;/li&gt;
&lt;li&gt;timeout configuration;&lt;/li&gt;
&lt;li&gt;rate-limit management;&lt;/li&gt;
&lt;li&gt;anomaly detection;&lt;/li&gt;
&lt;li&gt;user expectations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Harness did not make every run dramatically cheaper.&lt;/p&gt;

&lt;p&gt;It made the execution path more repeatable.&lt;/p&gt;

&lt;h2&gt;
  
  
  What selective routing appears to change
&lt;/h2&gt;

&lt;p&gt;A monolithic instruction file gives the agent every repository rule at once.&lt;/p&gt;

&lt;p&gt;The agent must decide which ones matter while already performing the task.&lt;/p&gt;

&lt;p&gt;A routed Harness makes the selection explicit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;task classification
        ↓
repository route
        ↓
required context
        ↓
optional escalation
        ↓
selected validation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This does more than organize Markdown files.&lt;/p&gt;

&lt;p&gt;It constrains the agent’s decision space.&lt;/p&gt;

&lt;p&gt;That provides a plausible explanation for the lower variance, although this benchmark cannot prove causation.&lt;/p&gt;

&lt;p&gt;The strongest conclusion supported by the data is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Repository-defined routing preserved implementation success and made coding-agent behavior more consistent.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Did the Harness win?
&lt;/h2&gt;

&lt;p&gt;Not in the simple way I originally imagined.&lt;/p&gt;

&lt;p&gt;The experiment does not prove that the Harness always uses fewer tokens or is reliably faster.&lt;/p&gt;

&lt;p&gt;It does show that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;selective routing worked;&lt;/li&gt;
&lt;li&gt;unrelated documents were not loaded;&lt;/li&gt;
&lt;li&gt;implementation reliability was preserved;&lt;/li&gt;
&lt;li&gt;average efficiency remained close to the monolithic version;&lt;/li&gt;
&lt;li&gt;execution variability was substantially lower.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the result is not:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The Harness is cheaper.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The Harness is more predictable.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That may be the more valuable engineering property.&lt;/p&gt;

&lt;h2&gt;
  
  
  The next experiment should be full-stack
&lt;/h2&gt;

&lt;p&gt;The current benchmark tested one task inside one Godot repository.&lt;/p&gt;

&lt;p&gt;The next step should test whether the routing model generalizes to a repository with clearly different technical domains.&lt;/p&gt;

&lt;p&gt;A backend-and-frontend project is a stronger test because it contains knowledge that should not be loaded for every task:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;backend
database
API contracts
frontend
accessibility
design system
integration tests
deployment
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The next benchmark should include:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;a backend-only task;&lt;/li&gt;
&lt;li&gt;a frontend-only task;&lt;/li&gt;
&lt;li&gt;a cross-stack task.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A useful Harness should remain narrow for isolated work and expand only when the task crosses a boundary.&lt;/p&gt;

&lt;p&gt;A practical setup would be a TypeScript monorepo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apps/
├── api/
└── web/

packages/
├── contracts/
└── testing/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Validation could be fully automated:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;lint
type-check
unit tests
integration tests
production build
headless end-to-end tests
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The next benchmark should measure not only tokens and duration, but also:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;documents loaded;&lt;/li&gt;
&lt;li&gt;unnecessary documents loaded;&lt;/li&gt;
&lt;li&gt;route escalations;&lt;/li&gt;
&lt;li&gt;changed-file scope;&lt;/li&gt;
&lt;li&gt;p95 duration;&lt;/li&gt;
&lt;li&gt;variance.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The central question for Part 3 is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can repository-defined routing stay narrow for backend-only and frontend-only work, then expand correctly for a cross-stack task?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why memory should come later
&lt;/h2&gt;

&lt;p&gt;Persistent memory is promising.&lt;/p&gt;

&lt;p&gt;A Harness could eventually learn architectural decisions, recurring failures, conventions, validation paths, and known issues.&lt;/p&gt;

&lt;p&gt;But adding memory now would mix two different hypotheses:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Does static routing generalize?&lt;/li&gt;
&lt;li&gt;Does accumulated experience improve future tasks?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Memory also makes later runs depend on earlier ones, which complicates a controlled comparison.&lt;/p&gt;

&lt;p&gt;The cleaner sequence is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Part 2
Selective routing and predictability

Part 3
Full-stack generalization

Part 4
Lifecycle hooks and persistent memory
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the Harness generalizes in Part 3, memory becomes the next logical layer.&lt;/p&gt;

&lt;h2&gt;
  
  
  The project is not a failure
&lt;/h2&gt;

&lt;p&gt;The original promise was token reduction.&lt;/p&gt;

&lt;p&gt;The second benchmark did not produce a large or statistically conclusive reduction in average token use.&lt;/p&gt;

&lt;p&gt;Instead, it revealed a different benefit:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Repository-defined context routing can make coding-agent behavior more predictable without reducing implementation success.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Reliable agent workflows need more than correct final code.&lt;/p&gt;

&lt;p&gt;They need bounded behavior:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;bounded context;&lt;/li&gt;
&lt;li&gt;bounded validation;&lt;/li&gt;
&lt;li&gt;bounded tool use;&lt;/li&gt;
&lt;li&gt;explainable escalation;&lt;/li&gt;
&lt;li&gt;repeatable execution paths.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is what the Repository Harness is becoming.&lt;/p&gt;

&lt;p&gt;The first article proposed the idea.&lt;/p&gt;

&lt;p&gt;The first benchmark exposed a routing flaw.&lt;/p&gt;

&lt;p&gt;The second benchmark showed that stricter routing worked and made the agent more consistent.&lt;/p&gt;

&lt;p&gt;Part 3 will test whether that result generalizes beyond Godot.&lt;/p&gt;

&lt;p&gt;The question is no longer only:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can a Harness reduce tokens?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can a repository define a predictable, auditable, and progressively disclosed operating environment for any coding agent?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The project is available at:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Repository Harness Specification&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://github.com/Repository-Harness-Specification" rel="noopener noreferrer"&gt;https://github.com/Repository-Harness-Specification&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Coding Agents Evolved. Our Repositories Didn’t.</title>
      <dc:creator>Leandro Boeing Vieira</dc:creator>
      <pubDate>Fri, 17 Jul 2026 15:23:00 +0000</pubDate>
      <link>https://dev.to/lepsistemas/coding-agents-evolved-our-repositories-didnt-f4</link>
      <guid>https://dev.to/lepsistemas/coding-agents-evolved-our-repositories-didnt-f4</guid>
      <description>&lt;p&gt;Why giant &lt;code&gt;AGENTS.md&lt;/code&gt; files may be wasting context, hurting maintainability, and making AI-assisted development harder to scale.&lt;/p&gt;

&lt;p&gt;A few years ago, for many developers, using AI for software development meant copying a small piece of code into a chat window.&lt;/p&gt;

&lt;p&gt;We would ask for a refactoring, copy the response back into the editor, run the tests ourselves, and return to the chat when something failed.&lt;/p&gt;

&lt;p&gt;Coding agents changed that workflow.&lt;/p&gt;

&lt;p&gt;Tools such as Codex, Claude Code, and others can now explore an entire repository, modify multiple files, execute commands, run tests, and iterate on failures.&lt;/p&gt;

&lt;p&gt;Coding agents turned code assistants into tools capable of executing multi-step software development tasks.&lt;/p&gt;

&lt;p&gt;But most repositories were not designed for this new kind of contributor.&lt;/p&gt;

&lt;h2&gt;
  
  
  The repository became part of the agent's working context
&lt;/h2&gt;

&lt;p&gt;A coding agent needs much more than source code.&lt;/p&gt;

&lt;p&gt;It may need to understand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the project architecture;&lt;/li&gt;
&lt;li&gt;dependency boundaries;&lt;/li&gt;
&lt;li&gt;coding conventions;&lt;/li&gt;
&lt;li&gt;test strategy;&lt;/li&gt;
&lt;li&gt;build commands;&lt;/li&gt;
&lt;li&gt;local environment requirements;&lt;/li&gt;
&lt;li&gt;validation steps;&lt;/li&gt;
&lt;li&gt;security restrictions;&lt;/li&gt;
&lt;li&gt;the definition of done.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A common solution is to place these instructions inside files such as &lt;code&gt;AGENTS.md&lt;/code&gt;, &lt;code&gt;CLAUDE.md&lt;/code&gt;, or other agent-specific configuration files.&lt;/p&gt;

&lt;p&gt;This works.&lt;/p&gt;

&lt;p&gt;I have been doing something similar in my own projects for a while.&lt;/p&gt;

&lt;p&gt;But as the repository grows, the instruction file grows with it.&lt;/p&gt;

&lt;p&gt;Eventually, a single file may contain thousands of lines covering unrelated concerns:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Architecture
Testing
Environment setup
Coding standards
Infrastructure
UI conventions
Validation
Release workflows
Definition of done
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At that point, the file is no longer just a set of agent instructions.&lt;/p&gt;

&lt;p&gt;It has become an informal repository operating manual.&lt;/p&gt;

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

&lt;p&gt;A large &lt;code&gt;AGENTS.md&lt;/code&gt; has an obvious advantage: the agent knows where to find it.&lt;/p&gt;

&lt;p&gt;But it also creates several problems.&lt;/p&gt;

&lt;h3&gt;
  
  
  It is difficult for humans to navigate
&lt;/h3&gt;

&lt;p&gt;These files are not only for agents.&lt;/p&gt;

&lt;p&gt;Developers also need to read, review, maintain, and discuss the rules.&lt;/p&gt;

&lt;p&gt;Someone changing a test should not need to navigate through multiplayer architecture, asset conventions, deployment rules, and UI standards.&lt;/p&gt;

&lt;h3&gt;
  
  
  Unrelated context may be loaded
&lt;/h3&gt;

&lt;p&gt;A small bug in a domain class may not require information about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;production deployment;&lt;/li&gt;
&lt;li&gt;UI assets;&lt;/li&gt;
&lt;li&gt;database migrations;&lt;/li&gt;
&lt;li&gt;release procedures;&lt;/li&gt;
&lt;li&gt;external integrations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When a large root instruction file is injected into every task, unrelated guidance may consume context that could otherwise be used for the task, the code, and the relevant documentation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Different knowledge changes at different speeds
&lt;/h3&gt;

&lt;p&gt;Architecture rules may remain stable for months.&lt;/p&gt;

&lt;p&gt;Bootstrap commands may change after a toolchain update.&lt;/p&gt;

&lt;p&gt;Validation rules may evolve every week.&lt;/p&gt;

&lt;p&gt;Keeping all of them in one document makes ownership and maintenance harder.&lt;/p&gt;

&lt;h3&gt;
  
  
  The file becomes difficult to validate
&lt;/h3&gt;

&lt;p&gt;A giant Markdown document is mostly passive guidance.&lt;/p&gt;

&lt;p&gt;It may describe commands that no longer work, paths that no longer exist, or rules that contradict the current codebase.&lt;/p&gt;

&lt;p&gt;This problem is not entirely theoretical.&lt;/p&gt;

&lt;p&gt;OpenAI has publicly described moving away from a large &lt;code&gt;AGENTS.md&lt;/code&gt; file because it consumed context, became difficult to maintain, and was hard to validate mechanically.&lt;/p&gt;

&lt;p&gt;Their solution was to use a shorter &lt;code&gt;AGENTS.md&lt;/code&gt; as a table of contents for a structured repository knowledge base.&lt;/p&gt;

&lt;p&gt;That experience supports the direction of this experiment, but it leaves an important question open:&lt;/p&gt;

&lt;p&gt;Can this approach become a vendor-neutral, reusable, and measurable repository specification?&lt;/p&gt;

&lt;h2&gt;
  
  
  A repository harness
&lt;/h2&gt;

&lt;p&gt;I agree with the direction OpenAI has described: &lt;code&gt;AGENTS.md&lt;/code&gt; should not contain the repository's entire operating model.&lt;/p&gt;

&lt;p&gt;It should act as an entry point, while the detailed knowledge lives in a modular and versioned repository structure.&lt;/p&gt;

&lt;p&gt;A small bootloader.&lt;/p&gt;

&lt;p&gt;The actual repository knowledge could live in a versioned and modular structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AGENTS.md
    ↓
.harness/
├── architecture
├── environment
├── validation
├── workflows
└── manifest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;.harness&lt;/code&gt; directory is a proposed convention, not something coding agents currently understand automatically.&lt;/p&gt;

&lt;p&gt;In the first version, &lt;code&gt;AGENTS.md&lt;/code&gt; would remain the supported entry point and instruct the agent how to discover and use the repository harness.&lt;/p&gt;

&lt;p&gt;The exact filenames are intentionally undefined at this stage.&lt;/p&gt;

&lt;p&gt;For example, testing could be part of validation in a small project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;validation/
└── testing rules and commands
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A larger project might need a dedicated testing document containing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;when to use unit tests;&lt;/li&gt;
&lt;li&gt;when to use integration tests;&lt;/li&gt;
&lt;li&gt;how to run each suite;&lt;/li&gt;
&lt;li&gt;mocking and fake conventions;&lt;/li&gt;
&lt;li&gt;test naming standards;&lt;/li&gt;
&lt;li&gt;patterns for writing new tests.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal is not to force every repository into the same directory tree.&lt;/p&gt;

&lt;p&gt;The goal is to define capabilities that agents can discover.&lt;/p&gt;

&lt;h2&gt;
  
  
  Progressive disclosure of repository context
&lt;/h2&gt;

&lt;p&gt;With a modular harness, an agent working on a domain bug might load:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Architecture
Testing
Validation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An agent preparing the project for the first time might load:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Bootstrap
Environment
Validation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A task involving deployment might load an entirely different set.&lt;/p&gt;

&lt;p&gt;This creates a form of progressive context loading:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Provide the agent with the context required for the current task, rather than the entire repository handbook.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The approach could potentially improve:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;context efficiency;&lt;/li&gt;
&lt;li&gt;token usage;&lt;/li&gt;
&lt;li&gt;instruction discoverability;&lt;/li&gt;
&lt;li&gt;human readability;&lt;/li&gt;
&lt;li&gt;documentation ownership;&lt;/li&gt;
&lt;li&gt;consistency between different coding agents.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But this is still a hypothesis.&lt;/p&gt;

&lt;h2&gt;
  
  
  Documentation is not enough
&lt;/h2&gt;

&lt;p&gt;A useful repository harness should not consist only of Markdown files.&lt;/p&gt;

&lt;p&gt;Whenever possible, instructions should point to executable and reproducible operations.&lt;/p&gt;

&lt;p&gt;Instead of documenting a long sequence of test commands, the repository could expose:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./scripts/test-unit
./scripts/test-integration
./scripts/validate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Markdown explains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;when the command must be used;&lt;/li&gt;
&lt;li&gt;what it validates;&lt;/li&gt;
&lt;li&gt;what failure means;&lt;/li&gt;
&lt;li&gt;which exceptions are allowed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The script defines how the operation is performed.&lt;/p&gt;

&lt;p&gt;This also makes the repository easier to validate through CI and less dependent on an agent correctly reproducing a sequence of commands.&lt;/p&gt;

&lt;h2&gt;
  
  
  Beyond implementation tasks
&lt;/h2&gt;

&lt;p&gt;The same concept could eventually apply before coding begins.&lt;/p&gt;

&lt;p&gt;A team using Jira, GitHub Issues, Linear, Azure DevOps, another issue tracker, or an internal product backlog might define a repository-specific Definition of Ready.&lt;/p&gt;

&lt;p&gt;Before a task enters the implementation pipeline, an agent could verify whether:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;acceptance criteria are clear;&lt;/li&gt;
&lt;li&gt;required architectural context exists;&lt;/li&gt;
&lt;li&gt;dependencies are identified;&lt;/li&gt;
&lt;li&gt;the task conflicts with existing documentation;&lt;/li&gt;
&lt;li&gt;expected validation is defined;&lt;/li&gt;
&lt;li&gt;important information is missing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The team could also encode its agreed Definition of Done in the repository harness before implementation begins.&lt;/p&gt;

&lt;p&gt;During and after implementation, the agent could use that definition to determine which tests, validations, reviews, documentation updates, and manual checks are required before considering the task complete.&lt;/p&gt;

&lt;h2&gt;
  
  
  The experiment
&lt;/h2&gt;

&lt;p&gt;I am starting an open project called &lt;strong&gt;Repository Harness Specification&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The first goal is to compare two versions of the same repository:&lt;/p&gt;

&lt;h3&gt;
  
  
  Monolithic
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AGENTS.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All instructions are contained in one large file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Modular
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AGENTS.md
.harness/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same information is organized into task-relevant modules that the agent can discover and load as needed.&lt;/p&gt;

&lt;p&gt;I plan to evaluate both approaches using the same:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;coding agent;&lt;/li&gt;
&lt;li&gt;model;&lt;/li&gt;
&lt;li&gt;repository;&lt;/li&gt;
&lt;li&gt;starting commit;&lt;/li&gt;
&lt;li&gt;implementation task;&lt;/li&gt;
&lt;li&gt;validation criteria.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The experiment will measure more than token consumption.&lt;/p&gt;

&lt;p&gt;Possible metrics include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;input tokens, when exposed by the selected agent or runtime;&lt;/li&gt;
&lt;li&gt;cached and uncached input tokens, when available;&lt;/li&gt;
&lt;li&gt;task success rate;&lt;/li&gt;
&lt;li&gt;tests passed;&lt;/li&gt;
&lt;li&gt;validation failures;&lt;/li&gt;
&lt;li&gt;files changed outside the expected scope;&lt;/li&gt;
&lt;li&gt;number of correction cycles;&lt;/li&gt;
&lt;li&gt;execution time.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Reducing tokens is not useful if the agent produces worse code.&lt;/p&gt;

&lt;p&gt;The real objective is to determine whether modular repository context can improve efficiency without reducing implementation quality.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building it in public
&lt;/h2&gt;

&lt;p&gt;The project will be developed publicly.&lt;/p&gt;

&lt;p&gt;The next steps include:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;defining the minimum repository harness;&lt;/li&gt;
&lt;li&gt;migrating a real project manually;&lt;/li&gt;
&lt;li&gt;creating reproducible benchmark tasks;&lt;/li&gt;
&lt;li&gt;comparing monolithic and modular context;&lt;/li&gt;
&lt;li&gt;publishing the results;&lt;/li&gt;
&lt;li&gt;building a CLI to initialize and validate repository harnesses;&lt;/li&gt;
&lt;li&gt;exploring integrations with different coding agents.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The structure presented in this article is not the final specification.&lt;/p&gt;

&lt;p&gt;It is the first experiment.&lt;/p&gt;

&lt;p&gt;Coding agents are evolving quickly.&lt;/p&gt;

&lt;p&gt;Now we need to understand how repositories should evolve with them.&lt;/p&gt;

&lt;p&gt;The project is available at:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Repository Harness Specification&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://github.com/Repository-Harness-Specification" rel="noopener noreferrer"&gt;https://github.com/Repository-Harness-Specification&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Feedback, criticism, and contributions are welcome.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>productivity</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Unity + Arquitetura Model-View-Presenter?</title>
      <dc:creator>Leandro Boeing Vieira</dc:creator>
      <pubDate>Thu, 04 Jan 2024 21:21:26 +0000</pubDate>
      <link>https://dev.to/lepsistemas/unity-arquitetura-model-view-presenter-3ild</link>
      <guid>https://dev.to/lepsistemas/unity-arquitetura-model-view-presenter-3ild</guid>
      <description>&lt;h1&gt;
  
  
  Motivação
&lt;/h1&gt;

&lt;p&gt;Ao longo da minha carreira de engenheiro de software, eu fui dando cada vez mais valor a código manutenível. Para muitos, perda de tempo, ou mesmo falta de tempo pra aplicar boas práticas e testes. Para outros, o grande salvador dos projetos de longo prazo, por ter sido possível dar manutenção às infinitas mudanças nos requisitos/escopo que sempre irão ocorrer.&lt;/p&gt;

&lt;p&gt;Claro que para projetos pequenos, frutos de hobby, Provas de Conceito (PoC), eu não recomendo fazer seguindo essas práticas, principalmente pra quem ainda as está aprendendo e treinando. Isso pode sim atrasar bastante o desenvolvimento.&lt;/p&gt;

&lt;p&gt;Porém, eu recomendo o estudo, a prática, o treinamento. Pois se um dia surgir uma vaga numa empresa grande de games, essas skills certamente chamarão a atenção do recrutador. Ou mesmo se você tiver aquela ideia genial de um jogo relativamente grande, elas podem te salvar horas de debug e dezenas de bugs.&lt;/p&gt;

&lt;p&gt;Como primeira tentativa de trazer um padrão arquitetural para a Unity, eu pensei em MVC ou MVP. Inclusive, tem um artigo excelente do Baeldung que traz as diferenças dos dois: &lt;a href="https://www.baeldung.com/mvc-vs-mvp-pattern"&gt;https://www.baeldung.com/mvc-vs-mvp-pattern&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;E dadas essas diferenças, por exemplo entre as funções da Controller do MVC e da Presenter do MVP, eu optei por iniciar pelo MVP. Me pareceu que encaixou melhor. Principalmente porque eu também queria escrever testes unitários para as regras do Model e Presenter. E pra isso o MVP se mostra melhor que o MVC, já que a Presenter é desacoplada da View, enquanto a Controller tem um alto acoplamento.&lt;/p&gt;

&lt;h1&gt;
  
  
  TicTacToe (Jogo da Velha)
&lt;/h1&gt;

&lt;p&gt;Jogo simples, de UI simples, principalmente a minha que chega a ser feia de tão simples, porém vamos focar é na programação, no código, e principalmente na separação de responsabilidades desse código.&lt;/p&gt;

&lt;p&gt;Na Unity, crie seu Canvas e sua grid da maneira que achar melhor. Eu utilizei Panel e Button com TextMeshPro:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9H8I8E_e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lavxcvpj4bjtsndhb4nd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9H8I8E_e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lavxcvpj4bjtsndhb4nd.png" alt="Unity" width="800" height="463"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A estrutura ficou assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MainScene
  GameManager
  Canvas
    GameBordPanel (Panel)
      Cell00 (Button)
      ...
      Cell22 (Button)
    PlayerInfoPanel (Panel)
      PlayerInfoText (TextMeshPro)
      WinnerInfoText (TextMeshPro)
      Reset (Button)
      Exit (Button)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Onde GameManager é um GameObject com 2 Script Components: GameManager e TicTacToeView. GameManager é o entrypoint da "aplicação", similar à classe Main do Java ou ao index.js do Javascript.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;UnityEngine&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GameManager&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MonoBehaviour&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;GetComponent&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TicTacToeView&lt;/span&gt;&lt;span class="p"&gt;&amp;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;view&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;TicTacToeModel&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;TicTacToePresenter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LogError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"TicTacToeView component not found on the GameObject."&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;E esse é o Inspector do GameObject chamado GameManager:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Gtw-6Vdg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/haqc4ay3vjxrch0m4ydy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Gtw-6Vdg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/haqc4ay3vjxrch0m4ydy.png" alt="GameManager Inspector" width="407" height="773"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ainda não sabemos o que são a TicTacToePresenter, TicTacToeModel e nem TicTacToeView, mas sabemos que GameManager as gerencia.&lt;/p&gt;

&lt;h1&gt;
  
  
  Model
&lt;/h1&gt;

&lt;p&gt;Essa camada existe independentemente de framework e biblioteca, dependendo apenas da arquitetura geral do sistema, nesse caso utilizando linguagem C#. Ela inclusive independe de detalhes de implementação da Unity.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TicTacToeModel&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;[,]&lt;/span&gt; &lt;span class="n"&gt;board&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;CurrentPlayer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;set&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="sc"&gt;'X'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;gameOver&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;TicTacToeModel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;ResetBoard&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;MakeMove&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;x&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;y&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;board&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="sc"&gt;'\0'&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="n"&gt;gameOver&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;board&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CurrentPlayer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;gameOver&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;CheckForWinner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&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;gameOver&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nf"&gt;SwitchPlayer&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="k"&gt;true&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="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;SwitchPlayer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;CurrentPlayer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CurrentPlayer&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="sc"&gt;'X'&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="sc"&gt;'O'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sc"&gt;'X'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;CheckForWinner&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;x&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;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Check row&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;board&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;CurrentPlayer&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;board&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;CurrentPlayer&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;board&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;CurrentPlayer&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;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// Check column&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;board&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;CurrentPlayer&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;board&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;CurrentPlayer&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;board&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;CurrentPlayer&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;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// Check diagonals&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;x&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;board&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;CurrentPlayer&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;board&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;CurrentPlayer&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;board&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;CurrentPlayer&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;true&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;x&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;board&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;CurrentPlayer&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;board&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;CurrentPlayer&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;board&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;CurrentPlayer&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;true&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;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;IsGameOver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;isDraw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;isDraw&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&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;gameOver&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Game over due to a win&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;true&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="nf"&gt;IsBoardFull&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Game over due to a draw&lt;/span&gt;
            &lt;span class="n"&gt;isDraw&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&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;true&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="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;IsBoardFull&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;for&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;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;for&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;j&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&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;board&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="sc"&gt;'\0'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&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;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ResetBoard&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;for&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;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;for&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;j&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;board&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="sc"&gt;'\0'&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;CurrentPlayer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="sc"&gt;'X'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;gameOver&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="nf"&gt;GetCurrentPlayerSymbol&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;CurrentPlayer&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;Note que ela não tem nenhuma dependência a nenhum namespace da Unity, como &lt;code&gt;using UnityEngine;&lt;/code&gt; ou &lt;code&gt;using System;&lt;/code&gt; no código. Ela poderia até ser utilizada em um projeto .NET tranquilamente.&lt;/p&gt;

&lt;p&gt;O intuito dela é guardar e proteger as regras do negócio. Que negócio? Nesse caso as regras do Jogo da Velha. Eu confesso que fiz na pressa, e poderia ter sido mais bem escrita, com alguns métodos a mais para extrair a lógica da checagem de um ganhador na horizontal, vertical e diagonal, entre outros, mas a ideia é mostrar essa classe sendo responsável pelo core do jogo.&lt;/p&gt;

&lt;p&gt;O importante é perceber que ela está isolada de detalhes de infraestrutura.&lt;/p&gt;

&lt;h1&gt;
  
  
  Presenter
&lt;/h1&gt;

&lt;p&gt;Presenter na MVP serve para orquestrar os inputs recebidos da View e informar ao Model, atualizando assim seu estado, bem como receber operações do Model e atualizar a View se necessário.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wsNbJAV3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dm9ibbbtnmafghjvnbyx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wsNbJAV3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dm9ibbbtnmafghjvnbyx.png" alt="Model-View-Presenter" width="300" height="227"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sua implementação é até mais simples que o Model, já que ela apenas faz a intermediação entre Model e View:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TicTacToePresenter&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;TicTacToeModel&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;ITicTacToeView&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;TicTacToePresenter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ITicTacToeView&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TicTacToeModel&lt;/span&gt; &lt;span class="n"&gt;model&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="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;view&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OnCellClicked&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;HandleCellClicked&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OnResetClicked&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;ResetBoard&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nf"&gt;UpdatePlayerInfo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;HandleCellClicked&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;x&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;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;currentPlayerSymbol&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetCurrentPlayerSymbol&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;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MakeMove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UpdateCell&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;currentPlayerSymbol&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;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsGameOver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;isDraw&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;isDraw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ShowWinner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;'\0'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="k"&gt;else&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ShowWinner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CurrentPlayer&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="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nf"&gt;UpdatePlayerInfo&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="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;UpdatePlayerInfo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CurrentPlayer&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="sc"&gt;'X'&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s"&gt;"Player X's Turn"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Player O's Turn"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UpdatePlayerInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ResetBoard&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ResetBoard&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ResetBoard&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;Note que ela orquestra os inputs recebidos na View e executa os comandos necessários no Model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Recebe inputs da View&lt;/span&gt;
&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OnCellClicked&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;HandleCellClicked&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// invoca ações no Model&lt;/span&gt;
&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MakeMove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&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;Note também que a Presenter recebe como parâmetro no seu construtor tanto a View quanto a Model, e mais, a View que ela recebe é uma interface e não uma classe concreta. Explico logo mais.&lt;/p&gt;

&lt;h1&gt;
  
  
  SOLID Principles
&lt;/h1&gt;

&lt;p&gt;Os SOLID Principles ajudam a guiar seu código a uma solução manutenível. Se você aplicá-los, o efeito colateral será sempre um código desacoplado, testável e flexível.&lt;/p&gt;

&lt;p&gt;Nesse caso específico estamos utilizando a DIP, Dependency Inversion Principle, com uma interface de View como dependência, para conseguir os seguintes resultados:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Desacoplamento&lt;/strong&gt;: O TicTacToePresenter é desacoplado da implementação específica da View. Ele não precisa conhecer os detalhes de como a View é implementada; ele depende apenas do contrato definido pela interface.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Testabilidade&lt;/strong&gt;: Fica mais fácil escrever testes unitários para o TicTacToePresenter, pois você pode criar implementações mock ou stub de ITicTacToeView para fins de teste. Isso permite isolar e testar o comportamento do Presenter independentemente da View real.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Flexibilidade&lt;/strong&gt;: Você pode trocar a implementação concreta da View sem afetar a Presenter. Por exemplo, se um dia você decidir criar uma interface de usuário diferente para o seu jogo, ou delegar isso a um outro time mais especializado em UI, você pode implementar uma nova View que respeita o contrato da interface ITicTacToeView, e a Presenter não precisa mudar.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Você verá essa capacidade de testabilidade mais pra frente.\ quando falarmos dos testes automatizados.&lt;/p&gt;

&lt;h1&gt;
  
  
  View
&lt;/h1&gt;

&lt;p&gt;Como sabemos, a View tem uma interface e uma implementação concreta. A interface fica no mesmo pacote que a Presenter, pois o motivo dela existir é a segregação de interface promovida pela camada Presenter.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;ITicTacToeView&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;event&lt;/span&gt; &lt;span class="n"&gt;Action&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;OnCellClicked&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;event&lt;/span&gt; &lt;span class="n"&gt;Action&lt;/span&gt; &lt;span class="n"&gt;OnResetClicked&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;event&lt;/span&gt; &lt;span class="n"&gt;Action&lt;/span&gt; &lt;span class="n"&gt;OnExitClicked&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;UpdateCell&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;x&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;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;playerSymbol&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;UpdatePlayerInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ShowWinner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;winner&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ResetBoard&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ExitGame&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;Perceba que ela expõe o contrato que uma View deve ter para saber se comunicar corretamente com a Presenter.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;UnityEngine&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;UnityEngine.UI&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;TMPro&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TicTacToeView&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MonoBehaviour&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ITicTacToeView&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;event&lt;/span&gt; &lt;span class="n"&gt;Action&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;OnCellClicked&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;event&lt;/span&gt; &lt;span class="n"&gt;Action&lt;/span&gt; &lt;span class="n"&gt;OnResetClicked&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;event&lt;/span&gt; &lt;span class="n"&gt;Action&lt;/span&gt; &lt;span class="n"&gt;OnExitClicked&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;cellButtons&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Button&lt;/span&gt; &lt;span class="n"&gt;resetButton&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Button&lt;/span&gt; &lt;span class="n"&gt;exitButton&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;TextMeshProUGUI&lt;/span&gt; &lt;span class="n"&gt;playerInfoText&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;TextMeshProUGUI&lt;/span&gt; &lt;span class="n"&gt;winnerInfoText&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;for&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;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;cellButtons&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;cellButtons&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddListener&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;OnCellButtonClicked&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;resetButton&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OnResetButtonClicked&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;exitButton&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OnExitButtonClicked&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;OnExitClicked&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;ExitGame&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnCellButtonClicked&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;cellIndex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cellIndex&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;3&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;y&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cellIndex&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;OnCellClicked&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;Invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnResetButtonClicked&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;OnResetClicked&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;Invoke&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnExitButtonClicked&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;OnExitClicked&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;Invoke&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;UpdateCell&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;x&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;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;playerSymbol&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;cellIndex&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cellButtons&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;cellIndex&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;GetComponentInChildren&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TextMeshProUGUI&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;().&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;playerSymbol&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;UpdatePlayerInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;info&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="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;playerInfoText&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;info&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ShowWinner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;winner&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="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;winnerInfoText&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;winner&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="sc"&gt;'\0'&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s"&gt;"It's a draw!"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$"Player &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;winner&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; wins!"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ResetBoard&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;button&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;cellButtons&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetComponentInChildren&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TextMeshProUGUI&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;().&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nf"&gt;UpdatePlayerInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Player X's Turn"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;winnerInfoText&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="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ExitGame&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;UNITY_EDITOR&lt;/span&gt;
            &lt;span class="n"&gt;UnityEditor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EditorApplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isPlaying&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;
            &lt;span class="n"&gt;Application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Quit&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="n"&gt;endif&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;E perceba que a View e a primeira classe em nosso projeto que conhece dependências de Unity, como as namespaces &lt;code&gt;UnityEngine, UnityEngine.UI e TMPro&lt;/code&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Tests
&lt;/h1&gt;

&lt;p&gt;Você pode clonar o repo no link do final do artigo, e rodar o jogo na Unity e vai ver que ele roda e funciona bem. Porém, lembra que uma das maiores vantagens de ter usado o padrão arquitetural MVP com DIP foi conseguir uma testabilidade isolada dos componentes?&lt;/p&gt;

&lt;p&gt;Olha como podemos testar as regras do jogo, independentemente de UI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;NUnit.Framework&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TicTacToeModelTests&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;TicTacToeModel&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SetUp&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;TicTacToeModel&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;Test&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Should_Return_True_For_A_Valid_Move&lt;/span&gt;&lt;span class="p"&gt;()&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;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MakeMove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsTrue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&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;Test&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Should_Return_False_For_An_Invalid_Move&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MakeMove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&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;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MakeMove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsFalse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&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;Test&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Should_Have_Winner_In_Horizontal_Line&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MakeMove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// X&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MakeMove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// O&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MakeMove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// X&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MakeMove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// O&lt;/span&gt;

        &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MakeMove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsTrue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Should_Have_Winner_In_Vertical_Line&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MakeMove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// X&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MakeMove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// O&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MakeMove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// X&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MakeMove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// O&lt;/span&gt;

        &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MakeMove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsTrue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Other tests for the Model can be added here&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E, mais do que isso, se usar uma biblioteca tipo Moq, podemos ainda testar a Presenter para garantir que ela chama as atualizações de View corretamente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;NUnit.Framework&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Moq&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TicTacToePresenterTests&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;TicTacToePresenter&lt;/span&gt; &lt;span class="n"&gt;presenter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;Mock&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ITicTacToeView&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;viewMock&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;TicTacToeModel&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SetUp&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;viewMock&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Mock&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ITicTacToeView&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;TicTacToeModel&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;presenter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;TicTacToePresenter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;viewMock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;model&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;Test&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Should_Update_Player_Info_In_View&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;expectedInfo&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Player X's Turn"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;viewMock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Setup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;view&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UpdatePlayerInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;It&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsAny&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;&amp;gt;()));&lt;/span&gt;

        &lt;span class="n"&gt;presenter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UpdatePlayerInfo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="n"&gt;viewMock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;view&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UpdatePlayerInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expectedInfo&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;Times&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Exactly&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Other tests for the Presenter can be added here&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E note, adicionar essa meia dúzia de testes não atrasa muito o desenvolvimento do seu projeto, seja honesto. Não estou falando que você precisa atingir 100% de cobertura de linhas, mas as features principais, como determinar que uma linha com 3 X's faz um vencedor, pode estar testada, certo?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wx8kIg0---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o9qwx9njiijjbxvtojyp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wx8kIg0---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o9qwx9njiijjbxvtojyp.png" alt="Tests Run" width="584" height="230"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Clean Architecture
&lt;/h1&gt;

&lt;p&gt;Model-View-Presenter não compreende todas as peculiaridades da Arquitetura Limpa, porém ela endereça pelo menos a separação entre camada de negocio da UI. Framework Adapters e Use Cases com Entities são assunto para um outro momento.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ogDWHt84--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k0fdfy7uaofovq6vn44s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ogDWHt84--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k0fdfy7uaofovq6vn44s.png" alt="Clean Architecture" width="800" height="580"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusão
&lt;/h1&gt;

&lt;p&gt;Embora a MVP não resolva todas as nuances da Clean Architecture, ela pelo menos separa o domínio da UI. Isso em projetos grandes/longos tende a facilitar muito em termos de manutenção.&lt;/p&gt;

&lt;p&gt;Note que criar as classes Model-View-Controller não mudaram MUITO o tempo de implementação. Com exceção de um evento a mais aqui ou ali, a lógica que antes estaria na View, e agora está na Model.&lt;/p&gt;

&lt;p&gt;E o maior ganho do advento dessa arquitetura foi a possibilidade da criação dos testes automatizados. Você não precisa testar seu jogo inteiro de forma automatizada, mas que tranquilidade saber que a lógica para o vencedor do TicTacToe permanecerá intacta, garantida por uma suíte de teste automatizado!&lt;/p&gt;

&lt;p&gt;Espero que tenha gostado desse artigo. E se quiser aprender mais sobre Clean Code, Clean Architecture, Hexagonal Architecture, Domain-Driven Design, Agilidade, testes Automatizados, TDD, recomendo ler meu livro "Minha Jornada para Ganhar em Dólar como Programador". Link da Hotmart seguir.&lt;/p&gt;

&lt;p&gt;Link do projeto no Github: &lt;a href="https://github.com/lepsistemas/MVP-TicTacToe"&gt;https://github.com/lepsistemas/MVP-TicTacToe&lt;/a&gt;&lt;br&gt;
Minha Jornada para ganhar em Dólar como Programador: &lt;a href="https://go.hotmart.com/K89021018W"&gt;https://go.hotmart.com/K89021018W&lt;/a&gt;&lt;/p&gt;

</description>
      <category>unity3d</category>
      <category>testing</category>
      <category>gamedev</category>
      <category>architecture</category>
    </item>
    <item>
      <title>gRPC + Spring Boot application compiling proto files as a dependency</title>
      <dc:creator>Leandro Boeing Vieira</dc:creator>
      <pubDate>Wed, 27 Oct 2021 00:49:33 +0000</pubDate>
      <link>https://dev.to/lepsistemas/grpc-spring-boot-application-compiling-proto-files-as-a-dependency-64l</link>
      <guid>https://dev.to/lepsistemas/grpc-spring-boot-application-compiling-proto-files-as-a-dependency-64l</guid>
      <description>&lt;p&gt;If you're working with gRPC you're probably also working with Protobuf. And manually sharing your proto files with clients may not scale well.&lt;/p&gt;

&lt;p&gt;What if I tell you that you could have a separated project and share your proto files as gradle/maven dependencies? That's the main goal of this article. Of course there'll be many more ways do to it out there, but if you use this article as a guide to do better, I'll be really honored.&lt;/p&gt;

&lt;p&gt;So, I created 2 projects on Github:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/lepsistemas/grpc-hexagonal-architecture-proto"&gt;https://github.com/lepsistemas/grpc-hexagonal-architecture-proto&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/lepsistemas/grpc-hexagonal-architecture"&gt;https://github.com/lepsistemas/grpc-hexagonal-architecture&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Noticed the names? One of them ends with "-proto". Yes, that's the project where we'll keep the proto files related to the "grpc-hexagonal-architecture" service. Oh, you're telling me you also noticed the names "hexagonal architecture"? That's a talk for another article. Let's focus on sharing the proto files in this one. And similarly I created 2 maven projects with the very same names.&lt;/p&gt;

&lt;p&gt;The structure of the "proto project" is really simple:&lt;/p&gt;

&lt;p&gt;src&lt;br&gt;
+---main&lt;br&gt;
+---+---proto&lt;br&gt;
+---+---+---common&lt;br&gt;
+---+---+---+---messages.proto&lt;br&gt;
+---+---+---service&lt;br&gt;
+---+---+---+---task.proto&lt;br&gt;
pom.xml&lt;/p&gt;

&lt;p&gt;No java classes, no extra configuration, just a pom file and a src folder. But if you pay attention to the pom file you'll wanna look at two parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &amp;lt;project.scm.id&amp;gt;&lt;/li&gt;
&lt;li&gt;The maven-release-plugin&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &amp;lt;project.scm.id&amp;gt; tag only exists to support multiple Github users on the same machine. If you only have one user, please define it with the value "github.com". In my case, "github.com" refers to the repositories I use in my job and for my personal repositories I use "github-lepsistemas". Please, refer to this article if you need help with it: &lt;a href="https://www.freecodecamp.org/news/manage-multiple-github-accounts-the-ssh-way-2dadc30ccaca/"&gt;https://www.freecodecamp.org/news/manage-multiple-github-accounts-the-ssh-way-2dadc30ccaca/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The maven-release-plugin will allow you to create tags and releases for your project in Github. For that, you'll need to be working on a SNAPSHOT (&amp;lt;version&amp;gt;1.0.0-SNAPSHOT&amp;lt;/version&amp;gt;) and then you need to execute the maven task:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mvn &lt;span class="nt"&gt;-B&lt;/span&gt; release:clean release:prepare release:perform
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create tag and release 1.0.0 in Github and will increase your local pom to 1.0.1-SNAPSHOT version.&lt;/p&gt;

&lt;p&gt;At this point you have a release available in Github and you could download it as a dependency in another project. We'll use it in "grpc-hexagonal-architecture", another maven project.&lt;/p&gt;

&lt;p&gt;Along with the dependencies that the project needs to compile/test/run, you'll also need this under &amp;lt;project&amp;gt; tag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;repositories&amp;gt;&lt;/span&gt;
     &lt;span class="nt"&gt;&amp;lt;repository&amp;gt;&lt;/span&gt;
         &lt;span class="nt"&gt;&amp;lt;id&amp;gt;&lt;/span&gt;jitpack.io&lt;span class="nt"&gt;&amp;lt;/id&amp;gt;&lt;/span&gt;
         &lt;span class="nt"&gt;&amp;lt;url&amp;gt;&lt;/span&gt;https://jitpack.io&lt;span class="nt"&gt;&amp;lt;/url&amp;gt;&lt;/span&gt;
     &lt;span class="nt"&gt;&amp;lt;/repository&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/repositories&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will allow you to download a dependency directly from Github.&lt;/p&gt;

&lt;p&gt;Add the dependency under the &amp;lt;dependencies&amp;gt; tag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.github.lepsistemas&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;grpc-hexagonal-architecture-proto&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.0.0&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And configure the compiler like this under the &amp;lt;plugins&amp;gt; tag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.xolstice.maven.plugins&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;protobuf-maven-plugin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;0.6.1&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;protocArtifact&amp;gt;&lt;/span&gt;com.google.protobuf:protoc:3.17.3:exe:${os.detected.classifier}&lt;span class="nt"&gt;&amp;lt;/protocArtifact&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;pluginId&amp;gt;&lt;/span&gt;grpc-java&lt;span class="nt"&gt;&amp;lt;/pluginId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;pluginArtifact&amp;gt;&lt;/span&gt;io.grpc:protoc-gen-grpc-java:1.41.0:exe:${os.detected.classifier}&lt;span class="nt"&gt;&amp;lt;/pluginArtifact&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;protoSourceRoot&amp;gt;&lt;/span&gt;${basedir}/../grpc-hexagonal-architecture-proto/src/main/proto/&lt;span class="nt"&gt;&amp;lt;/protoSourceRoot&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;executions&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;execution&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;goals&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;goal&amp;gt;&lt;/span&gt;compile&lt;span class="nt"&gt;&amp;lt;/goal&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;goal&amp;gt;&lt;/span&gt;compile-custom&lt;span class="nt"&gt;&amp;lt;/goal&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/goals&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/execution&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/executions&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All set. Your new gRPC project has a dependency from another project that exposes only the proto files. If you have any doubts, please refer to the Github repositories or you can always ask me.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>What Financial Softwares, Martin Fowler, Uncle Bob and Alexander Hamilton have in common?</title>
      <dc:creator>Leandro Boeing Vieira</dc:creator>
      <pubDate>Mon, 24 May 2021 12:57:12 +0000</pubDate>
      <link>https://dev.to/lepsistemas/what-financial-softwares-martin-fowler-uncle-bob-and-alexander-hamilton-have-in-common-2o21</link>
      <guid>https://dev.to/lepsistemas/what-financial-softwares-martin-fowler-uncle-bob-and-alexander-hamilton-have-in-common-2o21</guid>
      <description>&lt;p&gt;As Martin Fowler said in his article about &lt;em&gt;Patterns of Enterprise Application Architecture&lt;/em&gt; (&lt;a href="https://martinfowler.com/eaaCatalog/money.html):" rel="noopener noreferrer"&gt;https://martinfowler.com/eaaCatalog/money.html):&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"A large proportion of the computers in this world manipulate money, so it's always puzzled me that money isn't actually a first class data type in any mainstream programming language."&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;p&gt;Well, I didn't read the book &lt;em&gt;Patterns of Enterprise Application Architecture&lt;/em&gt;, but I do know that he suggests the implementation of a class &lt;em&gt;Money&lt;/em&gt;, with the attributes &lt;em&gt;currency&lt;/em&gt; and &lt;em&gt;amount&lt;/em&gt;, as well as a method called &lt;strong&gt;allocate&lt;/strong&gt; that receives a list of proportions and &lt;strong&gt;distributes that money without leaking values with rounding&lt;/strong&gt;. In this article I'll show how we've implemented our &lt;em&gt;Money&lt;/em&gt; to solve a real problem of losing cents in apportionments, and also solve the mystery of this article's title.&lt;/p&gt;

&lt;p&gt;We already had a &lt;em&gt;Money&lt;/em&gt; class, which made it really easier to write the &lt;em&gt;Money Pattern&lt;/em&gt;. So, if I am to give you a first hint, it is: &lt;strong&gt;DO NOT use &lt;em&gt;Double&lt;/em&gt; or &lt;em&gt;Big Decimal&lt;/em&gt; to financial values&lt;/strong&gt;. Build your "Value Object". After having financial values spread all over your system, it's gonna be harder - but not impossible - to refactor.&lt;/p&gt;

&lt;p&gt;Our &lt;em&gt;Money&lt;/em&gt; class doesn't have the attribute &lt;em&gt;currency&lt;/em&gt; because we don't have the need for a internationalization, at least not yet. And we are not going to implement &lt;em&gt;currency&lt;/em&gt; until we actually need it. Just like we didn't have the &lt;em&gt;allocate&lt;/em&gt; method. Until we needed it. So, our &lt;em&gt;Money&lt;/em&gt; was like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Money&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Serializable&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;Money&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;AmountCantBeEmptyException&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;Money&lt;/span&gt; &lt;span class="nf"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Money&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Money&lt;/span&gt; &lt;span class="nf"&gt;plus&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Money&lt;/span&gt; &lt;span class="n"&gt;addition&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Money&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;addition&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Money&lt;/span&gt; &lt;span class="nf"&gt;minus&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Money&lt;/span&gt; &lt;span class="n"&gt;discount&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Money&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;subtract&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;discount&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Money&lt;/span&gt; &lt;span class="nf"&gt;times&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;factor&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Money&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;multiply&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;factor&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="nf"&gt;getAmount&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="nd"&gt;@Override&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;Money&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;compareTo&lt;/span&gt;&lt;span class="o"&gt;(((&lt;/span&gt;&lt;span class="nc"&gt;Money&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="nd"&gt;@Override&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;hashCode&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hashCode&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This used to solve most of our financial problems. Until the day we needed the &lt;strong&gt;allocate&lt;/strong&gt; method. A &lt;strong&gt;debit worth of $ 1000.20 should be apportioned between several accounts&lt;/strong&gt; with the following rules:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;Proportion&lt;/th&gt;
&lt;th&gt;Gross Value&lt;/th&gt;
&lt;th&gt;Rounded Down&lt;/th&gt;
&lt;th&gt;Rounded Up&lt;/th&gt;
&lt;th&gt;Rounded Half Even&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;22,9%&lt;/td&gt;
&lt;td&gt;229.0458&lt;/td&gt;
&lt;td&gt;229.04&lt;/td&gt;
&lt;td&gt;229.05&lt;/td&gt;
&lt;td&gt;229.05&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;27.7%&lt;/td&gt;
&lt;td&gt;277.0554&lt;/td&gt;
&lt;td&gt;277.05&lt;/td&gt;
&lt;td&gt;277.06&lt;/td&gt;
&lt;td&gt;277.06&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;7.8%&lt;/td&gt;
&lt;td&gt;78.0156&lt;/td&gt;
&lt;td&gt;78.01&lt;/td&gt;
&lt;td&gt;78.02&lt;/td&gt;
&lt;td&gt;78.02&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;22.6%&lt;/td&gt;
&lt;td&gt;226.0452&lt;/td&gt;
&lt;td&gt;226.04&lt;/td&gt;
&lt;td&gt;226.05&lt;/td&gt;
&lt;td&gt;226.05&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;19%&lt;/td&gt;
&lt;td&gt;190.038&lt;/td&gt;
&lt;td&gt;190.03&lt;/td&gt;
&lt;td&gt;190.04&lt;/td&gt;
&lt;td&gt;190.04&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Total&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;td&gt;1000.20&lt;/td&gt;
&lt;td&gt;1000.17&lt;/td&gt;
&lt;td&gt;1000.22&lt;/td&gt;
&lt;td&gt;1000.22&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;As you can see, applying the apportionment percentage on every item, we'll never get to &lt;strong&gt;1000.20&lt;/strong&gt; - this happens because &lt;strong&gt;cents&lt;/strong&gt; are an indivisible unit, so the financial value represented by Money can't be 229.0458, for example. If we round down, 3 cents are lost in the end. If we round up, we get 2 extra cents. Even using Round Half Even will have precision loss.&lt;/p&gt;

&lt;p&gt;And guess who faced a problem like this? George Washington himself and one of the proposed solutions came from Alexander Hamilton, one of the Founding Fathers, and first United States Secretary of the Treasury, using his Largest Remainder Method.&lt;/p&gt;

&lt;p&gt;The problem faced at that time, described in &lt;a href="https://www.census.gov/history/www/reference/apportionment/methods_of_apportionment.html" rel="noopener noreferrer"&gt;U.S. Census Bureau&lt;/a&gt;, was shortly:&lt;/p&gt;

&lt;p&gt;A country with 4 states, each one with its own population, and 20 Seats at the House of Representatives. How many senators each state should have so they are represented proportionally? A senator, just like a penny, can't be divided in pieces. Right? Just double checking...&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;State&lt;/th&gt;
&lt;th&gt;Population&lt;/th&gt;
&lt;th&gt;Seats by State&lt;/th&gt;
&lt;th&gt;Seats by State before Hamilton's method&lt;/th&gt;
&lt;th&gt;Seats by State after Hamilton's method&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;2560&lt;/td&gt;
&lt;td&gt;4.31&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;3315&lt;/td&gt;
&lt;td&gt;5.&lt;strong&gt;58&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;995&lt;/td&gt;
&lt;td&gt;1.&lt;strong&gt;67&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;5012&lt;/td&gt;
&lt;td&gt;8.44&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Total&lt;/td&gt;
&lt;td&gt;11882&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;18&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Hamilton's method consists in calculating the proportion between the population of &lt;strong&gt;11882&lt;/strong&gt; and the number of &lt;strong&gt;20&lt;/strong&gt; seats, resulting in the quota of &lt;strong&gt;594.1&lt;/strong&gt;. Now, for each state, divide its population for the quota. For example in the state &lt;strong&gt;1&lt;/strong&gt;, &lt;strong&gt;2560/594.1&lt;/strong&gt; getting a quotient of &lt;strong&gt;4.31&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;As we have agreed, &lt;strong&gt;we can't have 4 senators and 0.31 of a senator&lt;/strong&gt; for a state. So the number of senators for the state 1 is 4, which is the &lt;strong&gt;whole part&lt;/strong&gt; of the result. That happens for every state. In the end, because of the rounding, the &lt;strong&gt;number of senators allocated in the states is 18&lt;/strong&gt;. Which states should the other &lt;strong&gt;2 senators&lt;/strong&gt; go to? That's when &lt;strong&gt;Hamilton&lt;/strong&gt; comes with a possible solution. His idea is that we distribute these 2 seats to the states that had the &lt;strong&gt;largest decimal part before the rounding&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I'll explain. If we suppress the whole part of the &lt;strong&gt;Seats by State&lt;/strong&gt; column and desc order by the decimal part, we get:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;1,&lt;strong&gt;67&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;5,&lt;strong&gt;58&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;8,&lt;strong&gt;44&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;4,&lt;strong&gt;31&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Since we have a total of &lt;strong&gt;2 seats to redistribute&lt;/strong&gt;, the states that will receive these senators are the &lt;strong&gt;first 2 of the list&lt;/strong&gt;. Resulting in the column &lt;strong&gt;Seats by State after Hamilton's method&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;There's a paradox to be noticed that was discovered by applying Hamilton's method in the population of Alabama, reason it is called the &lt;a href="https://en.wikipedia.org/wiki/Apportionment_paradox#Alabama_paradox" rel="noopener noreferrer"&gt;Alabama Paradox&lt;/a&gt;. That will not be covered here. But this is when &lt;strong&gt;Uncle Bob&lt;/strong&gt; comes in the article.&lt;/p&gt;

&lt;p&gt;Amongst his &lt;strong&gt;countless contributions&lt;/strong&gt; to the software development community, Uncle Bob spread the &lt;strong&gt;SOLID principles&lt;/strong&gt;. They were relevant in the 90's, they are relevant now. The principle we are focusing now is the Open-Closed Principle.&lt;/p&gt;

&lt;p&gt;We need to change our &lt;strong&gt;Money&lt;/strong&gt; class to implement the &lt;strong&gt;allocate&lt;/strong&gt; method to distribute its values in ratios without losing any cents. So we created it like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Money&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Serializable&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="no"&gt;ONE_HUNDRED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Money&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;allocate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;BigDecimal&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ratios&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;RemainderDistribution&lt;/span&gt; &lt;span class="n"&gt;distribution&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;amountInCents&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;toCents&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Quota&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;quotas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="nl"&gt;ratio:&lt;/span&gt; &lt;span class="n"&gt;ratios&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;quotas&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Quota&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amountInCents&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ratio&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;distribution&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;distribute&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;quotas&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amountInCents&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;quotas&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;Quota:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;toMoney&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;collect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Collectors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toList&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="nf"&gt;toCents&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;multiply&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;ONE_HUNDRED&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;longValue&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Quota&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="no"&gt;ONE_HUNDRED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;ratio&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;Quota&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;ratio&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ratio&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ratio&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ratio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;multiply&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BigDecimal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;valueOf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="o"&gt;)).&lt;/span&gt;&lt;span class="na"&gt;longValue&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;RemainderDistribution&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;distribute&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Quota&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;quotas&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember the Alabama Paradox? Even having validated with our Product Manager that we would adopt Hamilton's method we still have some doubts about how this will behave in the user's hands. So we didn't want to have this hard-coded in &lt;strong&gt;Money&lt;/strong&gt; class. We wanted to have it changeable whenever needed. We wanted to make our &lt;strong&gt;Value Object&lt;/strong&gt; Opened for extension but Closed for modification. That's why &lt;strong&gt;RemainderDistribution&lt;/strong&gt; is an interface. One of its possible implementations, the one we used, is &lt;strong&gt;HamiltonApportionmentDistribution&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HamiltonApportionmentDistribution&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;RemainderDistribution&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

  &lt;span class="nd"&gt;@Override&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;distribute&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Quota&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;quotas&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;remain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Quota&lt;/span&gt; &lt;span class="n"&gt;quota&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;quotas&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;remain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;remain&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;quota&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAmount&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Quota&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;sortedQuotas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;quotas&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;sorted&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Comparator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;comparing&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;Quota:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;getFractionalPart&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;reversed&lt;/span&gt;&lt;span class="o"&gt;()).&lt;/span&gt;&lt;span class="na"&gt;collect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Collectors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toList&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="nc"&gt;Iterator&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Quota&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;iterator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sortedQuotas&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;iterator&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;remain&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;remain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;remain&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;iterator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;next&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;addRemain&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This way we &lt;strong&gt;solved&lt;/strong&gt; that initial problem. where &lt;strong&gt;rounding down we lost 3 cents&lt;/strong&gt; (remember that rounding down is due to the cents, similar to when we round a senator down). &lt;strong&gt;The calculation must be done using the smallest unit, in this case, cents&lt;/strong&gt;. And we got this result:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;Proportion&lt;/th&gt;
&lt;th&gt;Gross Value&lt;/th&gt;
&lt;th&gt;Gross Value in Cents&lt;/th&gt;
&lt;th&gt;Final Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;22.9%&lt;/td&gt;
&lt;td&gt;229.0458&lt;/td&gt;
&lt;td&gt;22904.&lt;strong&gt;58&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;229.05&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;27.7%&lt;/td&gt;
&lt;td&gt;277.0554&lt;/td&gt;
&lt;td&gt;27705.54&lt;/td&gt;
&lt;td&gt;277.05&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;7.8%&lt;/td&gt;
&lt;td&gt;78.0156&lt;/td&gt;
&lt;td&gt;7801.&lt;strong&gt;56&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;78.02&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;22.6%&lt;/td&gt;
&lt;td&gt;226.0452&lt;/td&gt;
&lt;td&gt;22604.52&lt;/td&gt;
&lt;td&gt;226.04&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;19%&lt;/td&gt;
&lt;td&gt;190.038&lt;/td&gt;
&lt;td&gt;19003.&lt;strong&gt;80&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;190.04&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Total&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;td&gt;1000.20&lt;/td&gt;
&lt;td&gt;100020&lt;/td&gt;
&lt;td&gt;1000.20&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;At this point I hope I have demystified the intersection between &lt;strong&gt;Alexander Hamilton&lt;/strong&gt;, &lt;strong&gt;Martin Fowler&lt;/strong&gt; and &lt;strong&gt;Uncle Bob&lt;/strong&gt; with the &lt;strong&gt;Financial Systems&lt;/strong&gt;. And, as bonus, you get some code to apply in your favorite language. Ah, all this &lt;strong&gt;code was covered with Unit Tests&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bonus&lt;/strong&gt;: if you don't know who &lt;strong&gt;Alexander Hamilton&lt;/strong&gt; was, there is a musical movie available in Disney+, called Hamilton. It tells the story of this who was the &lt;strong&gt;American First Secretary of Treasury&lt;/strong&gt; recorded with rap, hip hop and jazz, directly from the Broadway in 2016. Here's the trailer of this amazing film:&lt;/p&gt;

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

</description>
    </item>
    <item>
      <title>Spring Boot Development Environment with Docker and VS Code</title>
      <dc:creator>Leandro Boeing Vieira</dc:creator>
      <pubDate>Mon, 03 May 2021 12:04:34 +0000</pubDate>
      <link>https://dev.to/lepsistemas/spring-boot-development-environment-with-docker-and-vs-code-42mg</link>
      <guid>https://dev.to/lepsistemas/spring-boot-development-environment-with-docker-and-vs-code-42mg</guid>
      <description>&lt;p&gt;"It works on my machine."&lt;/p&gt;

&lt;p&gt;If you're a developer, chances you've heard, and said, it at least once in your life are huge. There can be tons of reasons for that: your processor architecture, your operational system, your compiler version, may be different from your colleague's. Even worse scenario is when you deploy your applications in cloud environments and they crash. But how? It worked on my machine!&lt;/p&gt;

&lt;h1&gt;
  
  
  The old way
&lt;/h1&gt;

&lt;p&gt;In a recent past, for Java projects - more specifically &lt;a href="https://spring.io/projects/spring-boot" rel="noopener noreferrer"&gt;Spring Boot&lt;/a&gt; ones, I used to install &lt;a href="https://sdkman.io/" rel="noopener noreferrer"&gt;sdkman&lt;/a&gt; and tried to arrange with the whole team to use the very same vendor and version of the JDK. Problem is, it depends on human actions to work. And humans can fail.&lt;/p&gt;

&lt;p&gt;With that in mind, I'd like to introduce to you a whole new world: development of a Spring Boot application in &lt;a href="https://code.visualstudio.com/" rel="noopener noreferrer"&gt;Visual Studio Code&lt;/a&gt; and compile, test and run in a &lt;a href="https://www.docker.com/" rel="noopener noreferrer"&gt;Docker&lt;/a&gt; container. I know you just turned up the nose about Java and VS Code, but trust me, it's gonna work and be worth it.&lt;/p&gt;

&lt;h1&gt;
  
  
  The new Era
&lt;/h1&gt;

&lt;p&gt;So, no need for a JDK installed on your machine. But you'll need VS Code and Docker, of course. After you install them, open your VS Code. In the Extensions menu, search for "Remote - Containers" and install it:&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%2F8mjrr7to0n7dmg4wu0ng.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%2F8mjrr7to0n7dmg4wu0ng.png" alt="Remote - Containers Extension"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, head to &lt;a href="https://start.spring.io/" rel="noopener noreferrer"&gt;Spring Initializr&lt;/a&gt;, scaffold a new project, download and extract the files on your machine:&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%2Fdz23mxz9d9da7b9hkffs.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%2Fdz23mxz9d9da7b9hkffs.png" alt="Spring Boot Initializr"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Remember to add Spring Web and Spring Boot DevTools.&lt;/p&gt;

&lt;p&gt;Now, in your VS Code, open the  Command Palette (usually Ctrl  or Command + Shift + P) and type "&amp;gt;Remote-Containers: Open Folder in Container", select it and choose the location of your extracted Spring Boot application:&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%2F1a8cyi47weqo56oqijoa.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%2F1a8cyi47weqo56oqijoa.png" alt="Open Folder in Container"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, it's time to configure your development environment container.&lt;/p&gt;

&lt;p&gt;Select "Java - Develop Java applications":&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%2F6uxy4bgko49gu88fh43u.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%2F6uxy4bgko49gu88fh43u.png" alt="Java Image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select your Java version, in my case, 11:&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%2Fqwqv990qgmbfrztvp09w.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%2Fqwqv990qgmbfrztvp09w.png" alt="Java version"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select "Install Maven":&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%2Fdnh9ftr4eqyy3p75u1ic.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%2Fdnh9ftr4eqyy3p75u1ic.png" alt="Install Maven"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By now, your VS Code should have created a new folder in your project, called .devcontainer with a Dockerfile and devcontainer.json. You don't need to worry about them for now. Since this will be the first time your VS Code will run your application in a Docker container, it can take some time to download the images. Be patient. Once it is finished, you will be notified.&lt;/p&gt;

&lt;p&gt;Select the Run menu, click on "Open a file" and navigate to your Main class, in my case HelloFromContainerApplication:&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%2F8r0ww7un8gkfykugrxgu.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%2F8r0ww7un8gkfykugrxgu.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, if you click on the button "Run and Debug" it will run the application. Optionally, clicking on "No Configuration" and then "Add Configuration", VS Code will create a launch.json configuration file.&lt;/p&gt;

&lt;p&gt;Finally, if you hit &lt;a href="http://localhost:8080/" rel="noopener noreferrer"&gt;http://localhost:8080/&lt;/a&gt; in your browser you will see that the application is up and running in Debug mode, perfect to install some breakpoints and start your awesome solution. And remember DevTools? Go ahead and add a new endpoint to your application. It will live-reload in the container as well.&lt;/p&gt;

&lt;h1&gt;
  
  
  Push config to Github?
&lt;/h1&gt;

&lt;p&gt;Now comes the controversy part. Although it's recommended that you do not push specific IDE configuration files to your repository, I believe that if the whole team agrees to work in that manner, the .devcontainer could reside remotely. By doing this, you will mitigate the human failures and there will be no more "it works on my machine" excuses. Every environment, regardless of operational system, processor architecture or previous JDK installations, will behave similarly. This may even improve the speed of newcomers to the project for it will require less guidance and hit fewer issues related to environment setup.&lt;/p&gt;

&lt;h1&gt;
  
  
  Dockerfile for production environment
&lt;/h1&gt;

&lt;p&gt;As a final hint, if you look closely to the Dockerfile created by VS Code inside .devcontainer folder, you will see a comment like:&lt;/p&gt;

&lt;p&gt;// See here for image contents: &lt;a href="https://github.com/microsoft/vscode-dev-containers/tree/v0.158.0/containers/java/.devcontainer/base.Dockerfile" rel="noopener noreferrer"&gt;https://github.com/microsoft/vscode-dev-containers/tree/v0.158.0/containers/java/.devcontainer/base.Dockerfile&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This can be your guidance to creating your own Dockerfile, based on your local working environment. In this case, the Java image being used is the openjdk:11-jdk-buster and I would most likely want to use the same in production.&lt;/p&gt;

</description>
      <category>vscode</category>
      <category>docker</category>
      <category>springboot</category>
    </item>
    <item>
      <title>O que Softwares Financeiros, Martin Fowler, Uncle Bob e Alexander Hamilton têm em comum?</title>
      <dc:creator>Leandro Boeing Vieira</dc:creator>
      <pubDate>Tue, 26 Jan 2021 14:10:02 +0000</pubDate>
      <link>https://dev.to/lepsistemas/o-que-softwares-financeiros-martin-fowler-uncle-bob-e-alexander-hamilton-tem-em-comum-230l</link>
      <guid>https://dev.to/lepsistemas/o-que-softwares-financeiros-martin-fowler-uncle-bob-e-alexander-hamilton-tem-em-comum-230l</guid>
      <description>&lt;p&gt;Como disse &lt;strong&gt;Martin Fowler&lt;/strong&gt; no livro &lt;a href="https://martinfowler.com/eaaCatalog/money.html" rel="noopener noreferrer"&gt;&lt;em&gt;Patterns of Enterprise Application Architecture&lt;/em&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Uma boa parte dos computadores neste mundo manipula dinheiro, então sempre me intrigou que &lt;em&gt;Money&lt;/em&gt; não seja um tipo de dados em qualquer linguagem de programação convencional."&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;p&gt;&lt;em&gt;Patterns of Enterprise Application Architecture&lt;/em&gt; sugere a implementação de uma classe &lt;em&gt;Money&lt;/em&gt;, com atributos &lt;em&gt;currency&lt;/em&gt; e &lt;em&gt;amount&lt;/em&gt;, bem como um método &lt;strong&gt;&lt;em&gt;allocate&lt;/em&gt;&lt;/strong&gt; que recebe uma lista de proporções e &lt;strong&gt;distribui esse dinheiro sem perder valor com arredondamentos&lt;/strong&gt;. Nesse artigo vou mostrar como implementamos nosso &lt;em&gt;Money&lt;/em&gt; pra resolver um problema real de perda de centavos em rateio, bem como resolver o mistério do título.&lt;/p&gt;

&lt;p&gt;Já tínhamos uma classe &lt;em&gt;Money&lt;/em&gt;, o que facilitou muito na escrita do &lt;em&gt;Money Pattern&lt;/em&gt;. Então se eu puder ter a pretensão de dar uma primeira dica é: &lt;strong&gt;não use &lt;em&gt;Double&lt;/em&gt; ou &lt;em&gt;BigDecimal&lt;/em&gt; pra valores financeiros&lt;/strong&gt;. Construa seu &lt;em&gt;Value Object&lt;/em&gt;. Depois de ter valores financeiros espalhados por todo seu sistema, vai ser bem difícil - mas não impossível - refatorar.&lt;/p&gt;

&lt;p&gt;Nossa classe &lt;em&gt;Money&lt;/em&gt; não tem o atributo &lt;em&gt;currency&lt;/em&gt; pois não temos a necessidade de internacionalização, pelo menos não ainda. E não vamos ter implementação de &lt;em&gt;currency&lt;/em&gt; enquanto não precisarmos de fato. Assim como também não tínhamos o método allocate. Até que precisamos. Portanto nosso &lt;em&gt;Money&lt;/em&gt; era assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Money&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Serializable&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;Money&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;AmountCantBeEmptyException&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;Money&lt;/span&gt; &lt;span class="nf"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Money&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Money&lt;/span&gt; &lt;span class="nf"&gt;plus&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Money&lt;/span&gt; &lt;span class="n"&gt;addition&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Money&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;addition&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Money&lt;/span&gt; &lt;span class="nf"&gt;minus&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Money&lt;/span&gt; &lt;span class="n"&gt;discount&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Money&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;subtract&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;discount&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Money&lt;/span&gt; &lt;span class="nf"&gt;times&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;factor&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Money&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;multiply&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;factor&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="nf"&gt;getAmount&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="nd"&gt;@Override&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;Money&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;compareTo&lt;/span&gt;&lt;span class="o"&gt;(((&lt;/span&gt;&lt;span class="nc"&gt;Money&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="nd"&gt;@Override&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;hashCode&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hashCode&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isso resolvia boa parte dos nossos problemas financeiros. Até que o fatídico dia em que precisamos do &lt;strong&gt;allocate&lt;/strong&gt; chegou. Uma &lt;strong&gt;despesa de R$ 1000,20 deveria ser rateada entre várias contas&lt;/strong&gt; da seguinte maneira:&lt;/p&gt;

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

&lt;p&gt;Como podem perceber, se aplicarmos o percentual de proporção de rateio em cada item, nunca chegaremos em &lt;strong&gt;R$ 1000,20&lt;/strong&gt; - isso porque &lt;strong&gt;centavo é uma medida indivisível&lt;/strong&gt;, então um valor financeiro representado por &lt;em&gt;Money&lt;/em&gt; &lt;strong&gt;não pode ser R$ 229,0458&lt;/strong&gt; por exemplo. Se arredondarmos pra baixo, "perdemos" 3 centavos. Se arredondarmos pra cima, "ganhamos" 2 centavos. E note que mesmo usando o Round Half Even, perdemos precisão. Esse último é o modo de arredondamento comumente utilizado em sistemas financeiros, inclusive homologado pela ABNT através da norma &lt;a href="https://pt.wikipedia.org/wiki/Arredondamento#Regras_de_arredondamento" rel="noopener noreferrer"&gt;NBR 5891&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;E sabem quem enfrentou um problema parecido? Ele mesmo, George Washington, o primeiro presidente dos Estados Unidos, e uma das soluções propostas foi de &lt;strong&gt;Alexander Hamilton&lt;/strong&gt;, que veio a ser o Primeiro Secretário do Tesouro dos EUA, e seu &lt;em&gt;Largest Remainder Method&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;O problema enfrentado por eles à época era resumidamente o seguinte, descrito no &lt;a href="https://www.census.gov/history/www/reference/apportionment/methods_of_apportionment.html" rel="noopener noreferrer"&gt;U.S. Census Bureau&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;Um país com 4 estados, com diferentes populações em cada estado, e 20 assentos no Senado. Quantos senadores cada estado teria para que eles fossem representados proporcionalmente? Um senador, assim como um centavo, também não pode ser dividido em partes. Certo? Só pra confirmar aqui... =D&lt;/p&gt;

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

&lt;p&gt;O método de Hamilton consiste em calcular a proporção da &lt;strong&gt;população total de 11882&lt;/strong&gt; pela quantidade de &lt;strong&gt;20 assentos disponíveis&lt;/strong&gt; chegando no &lt;strong&gt;divisor&lt;/strong&gt; de 594,1. Agora pra cada estado &lt;strong&gt;divide-se sua população por esse divisor&lt;/strong&gt;, por exemplo no estado 1 &lt;strong&gt;2560/594,1&lt;/strong&gt; chegando no &lt;strong&gt;quociente de 4,31&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Como já concordamos, &lt;strong&gt;não podemos ter 4 senadores e 0,31 de um senador&lt;/strong&gt; para um estado. Então o número de senadores do estado 1 é &lt;strong&gt;4&lt;/strong&gt;, que é a &lt;strong&gt;parte inteira&lt;/strong&gt; do resultado. E isso acontece para cada um dos outros resultados. Ao final, por conta dos arredondamentos da parte inteira, o &lt;strong&gt;total de senadores alocados&lt;/strong&gt; nos estados &lt;strong&gt;é de 18&lt;/strong&gt;. Pra quais estados vão os outros 2? É aí que &lt;strong&gt;Hamilton&lt;/strong&gt; entra com uma &lt;strong&gt;possível solução&lt;/strong&gt;. A proposta dele é que distribuamos esses 2 assentos para os estados que ficaram com a maior parte decimal antes do arredondamento.&lt;/p&gt;

&lt;p&gt;Explico. Se suprimirmos a parte inteira da coluna &lt;strong&gt;&lt;em&gt;Senadores por Estado&lt;/em&gt;&lt;/strong&gt; e ordenarmos pela parte decimal, o resto, em ordem decrescente, ficaríamos com:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;1,&lt;strong&gt;67&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;5,&lt;strong&gt;58&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;8,&lt;strong&gt;44&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;4,&lt;strong&gt;31&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Como temos um total de &lt;strong&gt;2 senadores pra redistribuir&lt;/strong&gt;, os estados que recebem esses senadores são os &lt;strong&gt;2 primeiros da lista&lt;/strong&gt;. Resultando na coluna &lt;strong&gt;&lt;em&gt;Senadores por estado após Método Hamilton&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Existe um paradoxo a se notar que foi descoberto ao aplicar o método Hamilton na população do Alabama, por isso também é chamado de &lt;a href="https://en.wikipedia.org/wiki/Apportionment_paradox#Alabama_paradox" rel="noopener noreferrer"&gt;Paradoxo do Alabama&lt;/a&gt;, que não será coberto aqui. Mas é onde entra o nosso querido &lt;strong&gt;Uncle Bob&lt;/strong&gt; no artigo.&lt;/p&gt;

&lt;p&gt;Entre suas &lt;strong&gt;inúmeras contribuições&lt;/strong&gt; para a comunidade de desenvolvimento de software, Uncle Bob popularizou os &lt;strong&gt;princípios SOLID&lt;/strong&gt;. Era relevante lá na década de 90, é relevante hoje. O princípio que iremos focar agora é o Open-Closed Principle.&lt;/p&gt;

&lt;p&gt;Precisamos alterar nossa classe &lt;em&gt;Money&lt;/em&gt; para comportar o método &lt;strong&gt;allocate&lt;/strong&gt; pra conseguir distribuir seu valor em propoções sem perder centavos. Então criamos o seguinte método:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Money&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Serializable&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="no"&gt;ONE_HUNDRED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Money&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;allocate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;BigDecimal&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ratios&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;RemainderDistribution&lt;/span&gt; &lt;span class="n"&gt;distribution&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;amountInCents&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;toCents&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Quota&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;quotas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="nl"&gt;ratio:&lt;/span&gt; &lt;span class="n"&gt;ratios&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;quotas&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Quota&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amountInCents&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ratio&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;distribution&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;distribute&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;quotas&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amountInCents&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;quotas&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;Quota:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;toMoney&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;collect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Collectors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toList&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="nf"&gt;toCents&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;multiply&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;ONE_HUNDRED&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;longValue&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Quota&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="no"&gt;ONE_HUNDRED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;ratio&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;Quota&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;ratio&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ratio&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ratio&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ratio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;multiply&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BigDecimal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;valueOf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="o"&gt;)).&lt;/span&gt;&lt;span class="na"&gt;longValue&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;RemainderDistribution&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;distribute&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Quota&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;quotas&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lembra do Paradoxo do Alabama? Mesmo tendo validado com nosso Product Manager que adotaríamos o método de Hamilton ainda temos dúvidas sobre quais consequências esse paradoxo, ou até outro, pode ter. Então não queríamos "chumbar" a distribuição no código do &lt;em&gt;Money&lt;/em&gt;. Queríamos deixar nosso &lt;em&gt;Value Object&lt;/em&gt; aberto para extensão mas fechado para modificação. Por isso &lt;em&gt;RemainderDistribution&lt;/em&gt; é uma interface. Uma das suas implementações, a que utilizamos, é a &lt;em&gt;HamiltonApportionmentDistribution&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HamiltonApportionmentDistribution&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;RemainderDistribution&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

  &lt;span class="nd"&gt;@Override&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;distribute&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Quota&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;quotas&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;remain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Quota&lt;/span&gt; &lt;span class="n"&gt;quota&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;quotas&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;remain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;remain&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;quota&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAmount&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Quota&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;sortedQuotas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;quotas&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;sorted&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Comparator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;comparing&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;Quota:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;getFractionalPart&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;reversed&lt;/span&gt;&lt;span class="o"&gt;()).&lt;/span&gt;&lt;span class="na"&gt;collect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Collectors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toList&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="nc"&gt;Iterator&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Quota&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;iterator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sortedQuotas&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;iterator&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;remain&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;remain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;remain&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;iterator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;next&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;addRemain&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dessa maneira &lt;strong&gt;resolvemos&lt;/strong&gt; aquele problema inicial, onde &lt;strong&gt;arredondando pra baixo "perdíamos" 3 centavos&lt;/strong&gt; (lembre-se que o arredondamento pra baixo é por conta dos centavos, similar a quando "arredondamos um senador" pra baixo). &lt;strong&gt;O cálculo deve ser feito utilizando a menor unidade de medida, ou seja, centavos&lt;/strong&gt;. E chegamos no seguinte resultado:&lt;/p&gt;

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

&lt;p&gt;Espero que até aqui eu tenha desmistificado a intersecção entre &lt;strong&gt;Alexander Hamilton&lt;/strong&gt;, &lt;strong&gt;Martin Fowler&lt;/strong&gt; e &lt;strong&gt;Uncle Bob&lt;/strong&gt; com os &lt;strong&gt;sistemas financeiros&lt;/strong&gt;. E, de quebra, você ganha uns códigos pra poder aplicar na sua linguagem favorita. Ah, todo esse código foi &lt;strong&gt;coberto por testes unitários&lt;/strong&gt;. E sabe quando você leu as sentenças na &lt;strong&gt;primeira pessoa do plural&lt;/strong&gt;? É porque &lt;strong&gt;desenvolvemos essa solução em 3&lt;/strong&gt;, então todo o crédito também ao &lt;a href="https://www.linkedin.com/in/victorsalesbrito/" rel="noopener noreferrer"&gt;Victor Sales de Brito&lt;/a&gt; e &lt;a href="https://www.linkedin.com/in/lucelia-siqueira-ab454919/" rel="noopener noreferrer"&gt;Lucelia Siqueira&lt;/a&gt;. Valeu, time!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bônus&lt;/strong&gt;: pra saber quem foi &lt;strong&gt;Alexander Hamilton&lt;/strong&gt;, existe um musical disponível na &lt;strong&gt;Disney+&lt;/strong&gt;, chamado Hamilton. Conta a história desse que foi o &lt;strong&gt;Primeiro Secretário do Tesouro Americano&lt;/strong&gt; em forma de rap, hip hop e jazz, gravado diretamente da Broadway em 2016. Segue trailer desse musical fantástico:&lt;/p&gt;

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

</description>
    </item>
    <item>
      <title>Introduction - A bot responding to a recruiter via Telegram using Watson Assistant's Natural Language Processing</title>
      <dc:creator>Leandro Boeing Vieira</dc:creator>
      <pubDate>Sun, 20 Sep 2020 20:07:00 +0000</pubDate>
      <link>https://dev.to/lepsistemas/um-bot-respondendo-a-um-recrutador-via-telegram-utilizando-o-processamento-de-linguagem-natural-do-watson-assistant-94m</link>
      <guid>https://dev.to/lepsistemas/um-bot-respondendo-a-um-recrutador-via-telegram-utilizando-o-processamento-de-linguagem-natural-do-watson-assistant-94m</guid>
      <description>&lt;p&gt;I believe that naming articles is as difficult as naming variables and classes, but let's go. For now, that'll do. Although large, it seems significant enough to demonstrate what I intend to cover in this series.&lt;/p&gt;

&lt;p&gt;As you may have seen in my LinkedIn post &lt;a href="https://www.linkedin.com/posts/leandro-boeing-vieira_tdd-springboot-java-activity-6712687112602349568-FhoD"&gt;https://www.linkedin.com/posts/leandro-boeing-vieira_tdd-springboot-java-activity-6712687112602349568-FhoD&lt;/a&gt;, I will "teach" (how much pretension) how to train a bot to respond to recruiters, making decisions for me, using the good principles of a clean architecture to separate the logic of my business from the necessary infrastructure for that.&lt;/p&gt;

&lt;p&gt;Ok, but what are my business rules? Respond to a recruiter based on the context of the conversation. And what is the infra? Telegram API, Watson Assistant, REST etc. You'll see below a drawing of the initial architecture. Of course, it may change until the end of the project, but whenever it happens, I will tell you what has changed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aA8wyWyI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/ozyre9g8gelsf4v4xnf0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aA8wyWyI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/ozyre9g8gelsf4v4xnf0.png" alt="Bot's Architecture" width="792" height="633"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I was surprised that an architecture for such a cool theme is as simple as that. I finished drawing and thought: something must be missing. But in fact, it has served me well so far. Some points to highlight in relation to the stack I use to implement this architecture:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Telegram itself indicates some unofficial SDKs for developers at &lt;a href="https://core.telegram.org/bots/samples"&gt;https://core.telegram.org/bots/samples&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I decided to use the Java Telegram Bot API (&lt;a href="https://github.com/pengrad/java-telegram-bot-api"&gt;https://github.com/pengrad/java-telegram-bot-api&lt;/a&gt;) because it suited me well and I liked the support on github, answering a question in less than 24 hrs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;This implementation of the telegram API provides a much better Webhook mechanism than polling the server for a possible new message. With that, I end up being "nice" with Heroku too, as my application can shut down after 30 minutes of inactivity. With the polling solution, the application receives a POST every X seconds and it never sleeps.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Currently, the application does not yet have the "Take decision based on context" logic developed within the Use Case "Answer Recruiter". I mean, we will develop together. Nice right?! But it already communicates with IBM Watson Assistant and returns the context I need for the bot to be able to answer at least the initial greeting.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I have a minimum logging for development level so I can analyze what the user is sending and what he is receiving as a response. As the application sleeps from time to time (characteristic of Heroku) I always lose these logs. If anyone has a cool idea on how to persist these logs for free, I would appreciate it very much!&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It is worth noting that, in an initial idea, I will not "teach" how to create an instance of IBM's Watson Assistant. There is a very complete material at: &lt;a href="https://cloud.ibm.com/docs/assistant?topic=assistant-getting%20-started"&gt;https://cloud.ibm.com/docs/assistant?topic=assistant-getting-startedodos&lt;/a&gt;. But I will show you how I created the dialog nodes, the intents and the entities related to the domain of my application. I think it makes more sense that way.&lt;/p&gt;

&lt;p&gt;I'm also not going to teach you how to create a bot on Telegram. It is VERY simple and they teach here: &lt;a href="https://core.telegram.org/bots#3-%20how-do-i-create-a-bot"&gt;https://core.telegram.org/bots#3- how-do-i-create-a-bot&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;That's it for now. We haven't entered "show me the code" yet, but be patient. I thought this introduction is important for us to give a cool rhythm in this series, without too much information at once. I also think it is important that you have a first contact with the architecture, become familiar with it, before looking at the implementation decisions soon.&lt;/p&gt;

</description>
      <category>java</category>
      <category>bot</category>
      <category>telegram</category>
      <category>ibmwatson</category>
    </item>
  </channel>
</rss>
