<?xml version="1.0" encoding="utf-8" standalone="yes"?><feed xmlns="http://www.w3.org/2005/Atom">
  <title></title>
  <subtitle></subtitle>
  <id>https://www.endpointdev.com/blog/tags/programming/</id>
  <link href="https://www.endpointdev.com/blog/tags/programming/"/>
  <link href="https://www.endpointdev.com/blog/tags/programming/" rel="self"/>
  <updated>2026-05-15T00:00:00+00:00</updated>
  <author>
    <name>End Point Dev</name>
  </author>
  
    <entry>
      <title>Building a Multi-Agent Travel Planner with Microsoft Agent Framework and .NET</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2026/05/building-multi-agent-travel-planner-dotnet/"/>
      <id>https://www.endpointdev.com/blog/2026/05/building-multi-agent-travel-planner-dotnet/</id>
      <published>2026-05-15T00:00:00+00:00</published>
      <author>
        <name>Bimal Gharti Magar</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;img src=&#34;/blog/2026/05/building-multi-agent-travel-planner-dotnet/cover.webp&#34; alt=&#34;Traditional Dutch canal houses with ornate gabled facades photographed from below against a stormy sky.&#34;&gt;&lt;br&gt;
Photo by Seth Jensen, 2022.&lt;/p&gt;
&lt;p&gt;Large language models can answer travel questions well enough, but a single prompt is rarely enough to produce a plan you can trust end to end. Budget math can drift, travel times can be unrealistic, and a confident recommendation may not be grounded in the data the model actually saw.&lt;/p&gt;
&lt;p&gt;One way to improve that is to split the work across specialized agents. In this project, one agent researches the destination, another builds the itinerary, another checks the budget, another audits the result, and the last one turns everything into a polished response.&lt;/p&gt;
&lt;p&gt;In this post, we will build that workflow in .NET 10 using the &lt;a href=&#34;https://github.com/microsoft/agents&#34;&gt;Microsoft Agent Framework (MAF)&lt;/a&gt;. The project supports both local Ollama models and Anthropic through a shared &lt;code&gt;IChatClient&lt;/code&gt; abstraction, exposes a Web API with a streaming endpoint, and includes evaluation tests using &lt;a href=&#34;https://learn.microsoft.com/en-us/dotnet/ai/evaluation/libraries&#34;&gt;Microsoft.Extensions.AI.Evaluation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The source code is available on &lt;a href=&#34;https://github.com/bimalghartimagar/LocalAgentTravelPlanner&#34;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;what-well-build&#34;&gt;What we&amp;rsquo;ll build&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;A sequential multi-agent pipeline: Researcher -&amp;gt; Planner -&amp;gt; Accountant -&amp;gt; Auditor -&amp;gt; Aggregator&lt;/li&gt;
&lt;li&gt;Provider-swappable LLM integration with Ollama and Anthropic&lt;/li&gt;
&lt;li&gt;Deterministic validation tools for budget, timing, groundedness, and safety&lt;/li&gt;
&lt;li&gt;An ASP.NET Core Web API with both blocking and streaming endpoints&lt;/li&gt;
&lt;li&gt;A browser UI that shows live progress from each agent&lt;/li&gt;
&lt;li&gt;MEAI-based evaluation tests for output quality&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;prerequisites&#34;&gt;Prerequisites&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;.NET 10 SDK&lt;/li&gt;
&lt;li&gt;Ollama running locally with &lt;code&gt;qwen2.5:7b&lt;/code&gt;, or an Anthropic API key&lt;/li&gt;
&lt;li&gt;Optional: an &lt;a href=&#34;https://opentripmap.io/&#34;&gt;OpenTripMap API key&lt;/a&gt; for live hotel, attraction, and restaurant data&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;project-structure&#34;&gt;Project structure&lt;/h3&gt;
&lt;p&gt;The solution contains three projects:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;LocalAgentTravelPlanner&lt;/code&gt; for agents, services, models, and tools&lt;/li&gt;
&lt;li&gt;&lt;code&gt;LocalAgentTravelPlanner.Api&lt;/code&gt; for the ASP.NET Core Web API and static UI&lt;/li&gt;
&lt;li&gt;&lt;code&gt;LocalAgentTravelPlanner.Tests&lt;/code&gt; for unit tests and evaluation tests&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The core project uses these packages:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;PackageReference&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;Include=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Anthropic.SDK&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;Version=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;5.8.0&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;PackageReference&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;Include=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Microsoft.Agents.AI&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;Version=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;1.0.0-preview.251219.1&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;PackageReference&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;Include=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Microsoft.Agents.AI.Workflows&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;Version=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;1.0.0-preview.251219.1&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;PackageReference&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;Include=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Microsoft.Extensions.AI&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;Version=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;10.1.1&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;PackageReference&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;Include=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;OllamaSharp&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;Version=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;5.4.12&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;the-agent-pipeline&#34;&gt;The agent pipeline&lt;/h3&gt;
&lt;p&gt;The workflow is sequential, and each agent receives the accumulated conversation history from the earlier agents.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2026/05/building-multi-agent-travel-planner-dotnet/pipeline.svg&#34; alt=&#34;Sequential pipeline diagram showing User Request flowing through Researcher, Planner, Accountant, Auditor, and Aggregator agents back to the User&#34;&gt;&lt;/p&gt;
&lt;p&gt;That composition is built with &lt;code&gt;AgentWorkflowBuilder.BuildSequential&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;var&lt;/span&gt; workflow = AgentWorkflowBuilder.BuildSequential(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;new&lt;/span&gt; List&amp;lt;ChatClientAgent&amp;gt; { researcher, planner, accountant, auditor, aggregator }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;StreamingRun run = &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;await&lt;/span&gt; InProcessExecution.StreamAsync(workflow, userRequest);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;await&lt;/span&gt; run.TrySendMessageAsync(&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;new&lt;/span&gt; TurnToken(emitEvents: &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;true&lt;/span&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The important detail here is not just the order. It is the division of responsibility:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The Researcher gathers facts and options&lt;/li&gt;
&lt;li&gt;The Planner turns those facts into a day-by-day itinerary&lt;/li&gt;
&lt;li&gt;The Accountant checks whether the itinerary fits the budget&lt;/li&gt;
&lt;li&gt;The Auditor validates the plan&lt;/li&gt;
&lt;li&gt;The Aggregator prepares the final user-facing output&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That separation makes the system easier to reason about than a single all-purpose prompt.&lt;/p&gt;
&lt;h3 id=&#34;abstracting-the-model-provider&#34;&gt;Abstracting the model provider&lt;/h3&gt;
&lt;p&gt;Both Ollama and Anthropic are exposed through &lt;code&gt;IChatClient&lt;/code&gt; from &lt;code&gt;Microsoft.Extensions.AI&lt;/code&gt;, so the agents do not need provider-specific logic.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ChatClientFactory&lt;/code&gt; handles provider selection:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;static&lt;/span&gt; (IChatClient Client, Provider Provider, &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt; Model) CreateWithAutoDetect(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string?&lt;/span&gt; preferredProvider = &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;null&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; (!&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt;.IsNullOrEmpty(preferredProvider) &amp;amp;&amp;amp;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Enum.TryParse&amp;lt;Provider&amp;gt;(preferredProvider, ignoreCase: &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;true&lt;/span&gt;, &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;out&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;var&lt;/span&gt; provider))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;var&lt;/span&gt; model = provider == Provider.Anthropic
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            ? &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;claude-sonnet-4-20250514&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            : &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;qwen2.5:7b&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; (Create(provider, model), provider, model);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;var&lt;/span&gt; anthropicKey = Environment.GetEnvironmentVariable(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;ANTHROPIC_API_KEY&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; (!&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt;.IsNullOrEmpty(anthropicKey))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt; model = &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;claude-sonnet-4-20250514&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; (CreateAnthropicClient(model), Provider.Anthropic, model);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt; ollamaModel = &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;qwen2.5:7b&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; (CreateOllamaClient(ollamaModel), Provider.Ollama, ollamaModel);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is one of the more practical design decisions in the project. It lets you develop against a local model, then switch to Anthropic without rewriting the agent layer.&lt;/p&gt;
&lt;h3 id=&#34;fixing-the-anthropic-adapter-mismatch&#34;&gt;Fixing the Anthropic adapter mismatch&lt;/h3&gt;
&lt;p&gt;One of the more interesting details in the project is the &lt;code&gt;AnthropicOptionsInjector&lt;/code&gt; middleware.&lt;/p&gt;
&lt;p&gt;The Anthropic SDK requires &lt;code&gt;ModelId&lt;/code&gt; and &lt;code&gt;MaxOutputTokens&lt;/code&gt; on every request, but MAF does not populate those values in &lt;code&gt;ChatOptions&lt;/code&gt;. That means requests can fail even though the agent pipeline itself looks correct.&lt;/p&gt;
&lt;p&gt;The fix is to wrap the client with a &lt;code&gt;DelegatingChatClient&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;internal&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;AnthropicOptionsInjector&lt;/span&gt; : DelegatingChatClient
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;readonly&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt; _model;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;int&lt;/span&gt; DefaultMaxOutputTokens = &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;8192&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; AnthropicOptionsInjector(IChatClient inner, &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt; model) : &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;base&lt;/span&gt;(inner)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        =&amp;gt; _model = model;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;override&lt;/span&gt; Task&amp;lt;ChatResponse&amp;gt; GetResponseAsync(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        IEnumerable&amp;lt;ChatMessage&amp;gt; messages,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ChatOptions? options = &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;null&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        CancellationToken cancellationToken = &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;default&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        options ??= &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;new&lt;/span&gt; ChatOptions();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt;.IsNullOrEmpty(options.ModelId)) options.ModelId = _model;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; (options.MaxOutputTokens == &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;null&lt;/span&gt;) options.MaxOutputTokens = DefaultMaxOutputTokens;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;base&lt;/span&gt;.GetResponseAsync(messages, options, cancellationToken);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This pattern is useful beyond Anthropic. Any time an orchestration library and an SDK disagree about defaults, a &lt;code&gt;DelegatingChatClient&lt;/code&gt; can bridge the gap cleanly.&lt;/p&gt;
&lt;h3 id=&#34;creating-specialized-agents&#34;&gt;Creating specialized agents&lt;/h3&gt;
&lt;p&gt;Each agent is created through a static factory that keeps its instructions, tools, and name in one place.&lt;/p&gt;
&lt;p&gt;The Researcher is a good example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;static&lt;/span&gt; ChatClientAgent Create(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    IChatClient chatClient,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ResearchTools researchTools,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    TravelTools travelTools)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;var&lt;/span&gt; tools = &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;new&lt;/span&gt; List&amp;lt;AITool&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        AIFunctionFactory.Create(researchTools.GetWeatherForecast),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        AIFunctionFactory.Create(researchTools.SearchHotels),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        AIFunctionFactory.Create(researchTools.GetAttractions),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        AIFunctionFactory.Create(researchTools.GetTransportOptions),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        AIFunctionFactory.Create(researchTools.GetFoodRecommendations),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        AIFunctionFactory.Create(researchTools.GetSafetyInfo),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        AIFunctionFactory.Create(travelTools.GetWeather),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        AIFunctionFactory.Create(travelTools.GetFlightEstimate),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        AIFunctionFactory.Create(travelTools.GetEmergencyContacts),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        AIFunctionFactory.Create(travelTools.GetVisaInfo)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;new&lt;/span&gt; ChatClientAgent(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        chatClient,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        instructions: RESEARCHER_INSTRUCTIONS,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        tools: tools,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        name: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Researcher_Agent&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    );
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Not every agent needs tools. The Planner and Aggregator work from the shared conversation history alone, while the Accountant and Auditor rely on deterministic helper functions.&lt;/p&gt;
&lt;p&gt;That split is important. The model handles synthesis and language generation, while ordinary C# code handles the parts where determinism matters.&lt;/p&gt;
&lt;h3 id=&#34;using-live-apis-without-making-the-system-brittle&#34;&gt;Using live APIs without making the system brittle&lt;/h3&gt;
&lt;p&gt;The early version of the project relied on hardcoded destination data. That was useful while bootstrapping the workflow, but it limited the planner to a small set of cities.&lt;/p&gt;
&lt;p&gt;The updated tool layer pulls data from several live APIs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Nominatim for geocoding&lt;/li&gt;
&lt;li&gt;Open-Meteo for current weather and forecasts&lt;/li&gt;
&lt;li&gt;OpenTripMap for attractions, accommodation names, and food spots&lt;/li&gt;
&lt;li&gt;OSRM for distance and routing estimates&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For example, weather forecasting follows a simple pattern:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Convert a city name into coordinates&lt;/li&gt;
&lt;li&gt;Query Open-Meteo with those coordinates&lt;/li&gt;
&lt;li&gt;Parse the JSON response into a formatted text block for the agent&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;var&lt;/span&gt; coords = &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;await&lt;/span&gt; GeocodingHelper.GetCoordinatesAsync(_http, city);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; (coords &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;is&lt;/span&gt; { } c)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;var&lt;/span&gt; url = &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;$&amp;#34;https://api.open-meteo.com/v1/forecast&amp;#34;&lt;/span&gt; +
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;$&amp;#34;?latitude={c.Lat:F4}&amp;amp;longitude={c.Lon:F4}&amp;#34;&lt;/span&gt; +
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;$&amp;#34;&amp;amp;daily=weather_code,temperature_2m_max,temperature_2m_min,precipitation_sum&amp;#34;&lt;/span&gt; +
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;$&amp;#34;&amp;amp;forecast_days={Math.Clamp(days, 1, 16)}&amp;amp;timezone=auto&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;var&lt;/span&gt; json = &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;await&lt;/span&gt; _http.GetStringAsync(url);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;// parse response and format it for the agent&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The project also uses a practical fallback strategy: every external call is wrapped so tool failures degrade into a useful message instead of breaking the entire workflow.&lt;/p&gt;
&lt;p&gt;That matters in agent systems. A failed API call should reduce confidence, not take down the whole run.&lt;/p&gt;
&lt;h3 id=&#34;the-auditor-pattern&#34;&gt;The Auditor pattern&lt;/h3&gt;
&lt;p&gt;The Auditor is the part of the project that makes the architecture more than a simple agent chain.&lt;/p&gt;
&lt;p&gt;Instead of asking one model to plan and validate everything at the same time, the system introduces a dedicated review stage backed by deterministic tools:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ValidateMathConsistency&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ValidateBudgetFit&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ValidateTravelTime&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CheckGroundedness&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CheckSafetyRequirements&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CheckRelevance&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CheckCompleteness&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DetermineAuditDecision&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This allows the Auditor to score the plan across six criteria:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Financial integrity&lt;/li&gt;
&lt;li&gt;Temporal logic&lt;/li&gt;
&lt;li&gt;Safety compliance&lt;/li&gt;
&lt;li&gt;Groundedness&lt;/li&gt;
&lt;li&gt;Relevance&lt;/li&gt;
&lt;li&gt;Completeness&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That is the strongest idea in the whole project. LLMs are useful for synthesis and judgment, but they are still weak at arithmetic and consistency checking. Offloading those checks to tools makes the final response more trustworthy.&lt;/p&gt;
&lt;h3 id=&#34;streaming-the-pipeline-to-the-browser&#34;&gt;Streaming the pipeline to the browser&lt;/h3&gt;
&lt;p&gt;The Web API exposes two main endpoints:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;POST /api/travel/plan&lt;/code&gt; to return the final plan as JSON&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET /api/travel/plan/stream&lt;/code&gt; to stream progress over Server-Sent Events&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The streaming endpoint maps workflow events to frontend-friendly SSE events:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; (evt &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;is&lt;/span&gt; ExecutorInvokedEvent invokedEvt)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;await&lt;/span&gt; SendSseEvent(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;agent-start&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;new&lt;/span&gt; TravelPlanProgressEvent { ... });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; (evt &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;is&lt;/span&gt; AgentRunUpdateEvent updateEvent)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;await&lt;/span&gt; SendSseEvent(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;content&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;new&lt;/span&gt; TravelPlanProgressEvent { ... });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; (evt &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;is&lt;/span&gt; ExecutorCompletedEvent completedEvt)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;await&lt;/span&gt; SendSseEvent(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;agent-complete&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;new&lt;/span&gt; TravelPlanProgressEvent { ... });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;On the frontend, the stream is consumed with &lt;code&gt;fetch&lt;/code&gt; and &lt;code&gt;ReadableStream&lt;/code&gt; instead of &lt;code&gt;EventSource&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;That choice is subtle but practical. &lt;code&gt;EventSource&lt;/code&gt; automatically reconnects, which is often helpful for dashboards, but in this case a reconnect could restart an expensive multi-agent run. Using &lt;code&gt;fetch&lt;/code&gt; keeps cancellation and reconnection behavior under explicit control.&lt;/p&gt;
&lt;p&gt;The UI then uses those events to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;highlight the active agent in the pipeline&lt;/li&gt;
&lt;li&gt;append streaming content into the correct tab&lt;/li&gt;
&lt;li&gt;render Markdown progressively&lt;/li&gt;
&lt;li&gt;show a final polished output when the Aggregator finishes&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;handling-mafs-silent-failures&#34;&gt;Handling MAF&amp;rsquo;s silent failures&lt;/h4&gt;
&lt;p&gt;One thing to watch for with MAF in its current preview state: if an agent throws an exception, the workflow does not propagate it. It completes normally with empty output. Your API returns a success response, your UI shows nothing, and the logs are clean.&lt;/p&gt;
&lt;p&gt;The fix is to explicitly listen for &lt;code&gt;ExecutorFailedEvent&lt;/code&gt; and &lt;code&gt;WorkflowErrorEvent&lt;/code&gt; in the event loop:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; (evt &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;is&lt;/span&gt; ExecutorFailedEvent failedEvt)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;var&lt;/span&gt; ex = failedEvt.Data &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;as&lt;/span&gt; Exception;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;await&lt;/span&gt; SendSseEvent(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;error&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;new&lt;/span&gt; TravelPlanProgressEvent
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Agent = resolved,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Status = &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;failed&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Content = ex?.InnerException?.Message ?? ex?.Message ?? &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Agent failed&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; (evt &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;is&lt;/span&gt; WorkflowErrorEvent errorEvt)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;var&lt;/span&gt; ex = errorEvt.Data &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;as&lt;/span&gt; Exception;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;// handle workflow-level failure&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Without these handlers, a failed agent produces a blank response that looks like a success. This applies to both the blocking and streaming endpoints.&lt;/p&gt;
&lt;h4 id=&#34;filtering-empty-streaming-chunks&#34;&gt;Filtering empty streaming chunks&lt;/h4&gt;
&lt;p&gt;A related issue: MAF emits &lt;code&gt;AgentRunUpdateEvent&lt;/code&gt; with null or empty content during tool-calling turns. If you forward these directly to the browser, the SSE stream floods with empty &lt;code&gt;content&lt;/code&gt; events. The fix is a one-line guard before sending:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; (evt &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;is&lt;/span&gt; AgentRunUpdateEvent updateEvent)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;var&lt;/span&gt; content = updateEvent.Data?.ToString();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt;.IsNullOrEmpty(content)) &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;continue&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;await&lt;/span&gt; SendSseEvent(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;content&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;new&lt;/span&gt; TravelPlanProgressEvent { ... });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Both of these are easy to miss during development because the happy path works fine. They only surface under real load or when an external API (like an LLM provider) fails.&lt;/p&gt;
&lt;h3 id=&#34;evaluating-output-with-meai&#34;&gt;Evaluating output with MEAI&lt;/h3&gt;
&lt;p&gt;Once the pipeline works, the next question is whether the output is consistently good.&lt;/p&gt;
&lt;p&gt;The project answers that with &lt;code&gt;Microsoft.Extensions.AI.Evaluation.Quality&lt;/code&gt;, which uses an LLM as a judge to score the output across several axes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Coherence&lt;/strong&gt; — does the response hang together logically? Are ideas connected, or does it jump around or contradict itself?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fluency&lt;/strong&gt; — is the language natural, grammatically correct, and readable? This is about style and surface quality, not factual content.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Relevance&lt;/strong&gt; — does the response actually address what the user asked? A fluent answer to the wrong question scores low here.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Truth&lt;/strong&gt; — are the factual claims correct given the available evidence? The judge flags statements that are unsupported or contradicted by the source data.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Completeness&lt;/strong&gt; — does the response cover all the parts of the request? A travel plan missing a budget breakdown would lose points.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Groundedness&lt;/strong&gt; — are the claims traceable to the input or research data, rather than invented? This is the main hallucination signal.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each evaluator returns a score and a short explanation. Running them on real pipeline output gives you a numeric quality baseline that you can track over time as you change prompts, models, or tools.&lt;/p&gt;
&lt;p&gt;The evaluation tests run the real pipeline, then score the resulting output:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;results[&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Coherence&amp;#34;&lt;/span&gt;] = &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;await&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;new&lt;/span&gt; CoherenceEvaluator()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    .EvaluateAsync(messages, response, _evalConfiguration!);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;results[&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Fluency&amp;#34;&lt;/span&gt;] = &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;await&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;new&lt;/span&gt; FluencyEvaluator()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    .EvaluateAsync(messages, response, _evalConfiguration!);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;results[&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;RelevanceTruthCompleteness&amp;#34;&lt;/span&gt;] = &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;await&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;new&lt;/span&gt; RelevanceTruthAndCompletenessEvaluator()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    .EvaluateAsync(messages, response, _evalConfiguration!);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;These tests are intentionally skipped by default because they require a live model provider. That is a sensible tradeoff: keep ordinary unit tests fast, but retain a path for deeper quality checks when you want to validate the full system.&lt;/p&gt;
&lt;h3 id=&#34;running-the-application&#34;&gt;Running the application&lt;/h3&gt;
&lt;p&gt;To run the Web API with Ollama:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ollama serve
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ollama pull qwen2.5:7b
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dotnet run --project Api/LocalAgentTravelPlanner.Api.csproj&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To run it with Anthropic:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# PowerShell
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$env:ANTHROPIC_API_KEY=&amp;#34;sk-ant-...&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dotnet run --project Api/LocalAgentTravelPlanner.Api.csproj&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To run the unit tests:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dotnet test Tests/LocalAgentTravelPlanner.Tests.csproj&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To enable the evaluation tests:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# PowerShell
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$env:ENABLE_EVAL_TESTS=&amp;#34;true&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dotnet test Tests/LocalAgentTravelPlanner.Tests.csproj --filter &amp;#34;Category=Evaluation&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;securing-the-api&#34;&gt;Securing the API&lt;/h3&gt;
&lt;p&gt;Each request in this project triggers multiple LLM calls across five agents. Without any protection, a single user could exhaust your token budget in minutes. Two basic measures help here.&lt;/p&gt;
&lt;p&gt;First, an API key middleware that checks an &lt;code&gt;X-Api-Key&lt;/code&gt; header on every &lt;code&gt;/api/*&lt;/code&gt; route except the health endpoint. The key is loaded from ASP.NET&amp;rsquo;s configuration system, so it works with &lt;code&gt;appsettings.json&lt;/code&gt;, environment variables, or a mounted file for Docker secrets. The middleware runs early in the pipeline so unauthenticated requests never reach the agents.&lt;/p&gt;
&lt;p&gt;Second, a rate limiter on the plan endpoints. The project uses a fixed-window policy — five requests per minute per client IP — which is enough to prevent accidental abuse without blocking normal use. Behind nginx, the app reads the real client IP from forwarded headers rather than the Docker bridge address.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;builder.Services.AddRateLimiter(options =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    options.AddPolicy(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;plan&amp;#34;&lt;/span&gt;, context =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        RateLimitPartition.GetFixedWindowLimiter(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            partitionKey: context.Connection.RemoteIpAddress?.ToString() ?? &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;unknown&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            factory: _ =&amp;gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;new&lt;/span&gt; FixedWindowRateLimiterOptions
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                PermitLimit = &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;5&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                Window = TimeSpan.FromMinutes(&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                QueueLimit = &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Neither of these is novel, but they are easy to forget when the focus is on the agent pipeline itself. If you are exposing LLM-backed endpoints publicly, even for a demo, protecting them early saves a lot of trouble later.&lt;/p&gt;
&lt;h3 id=&#34;key-takeaways&#34;&gt;Key takeaways&lt;/h3&gt;
&lt;p&gt;This project is a good example of how to make an agent workflow more practical in a real application.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A multi-agent pipeline is useful when each stage has a distinct responsibility&lt;/li&gt;
&lt;li&gt;&lt;code&gt;IChatClient&lt;/code&gt; is a strong abstraction for provider-swappable .NET AI applications&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DelegatingChatClient&lt;/code&gt; middleware is a clean way to fix SDK integration mismatches&lt;/li&gt;
&lt;li&gt;Deterministic tools are still essential for math, validation, and consistency checks&lt;/li&gt;
&lt;li&gt;Streaming progress makes long-running agent workflows easier to understand and trust&lt;/li&gt;
&lt;li&gt;Evaluation is worth treating as a first-class part of the architecture, not an afterthought&lt;/li&gt;
&lt;li&gt;MAF silently swallows agent errors — always handle &lt;code&gt;ExecutorFailedEvent&lt;/code&gt; and &lt;code&gt;WorkflowErrorEvent&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Protect LLM-backed endpoints with API key auth and rate limiting, even for demos&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The main lesson is that the quality gains do not come from adding more agents for the sake of it. They come from giving each agent a clear role, grounding it with useful tools, and validating the result before it reaches the user.&lt;/p&gt;
&lt;p&gt;The source code is available on &lt;a href=&#34;https://github.com/bimalghartimagar/LocalAgentTravelPlanner&#34;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Build a Smarter Telegram Bot: Integrating a RAG Pipeline for FAQ Answering</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2025/12/telegram-bot-rag-pipeline/"/>
      <id>https://www.endpointdev.com/blog/2025/12/telegram-bot-rag-pipeline/</id>
      <published>2025-12-01T00:00:00+00:00</published>
      <author>
        <name>Bimal Gharti Magar</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;img src=&#34;/blog/2025/12/telegram-bot-rag-pipeline/mountains-and-clouds.webp&#34; alt=&#34;A black-and-white image of clouds hanging over a sharp mountain, jutting from the bottom right of the image, and a longer mountain ridge further back in the bottom left of the image.&#34;&gt;&lt;/p&gt;
&lt;!-- Photo by Seth Jensen, 2025. --&gt;
&lt;p&gt;In this post, we will show you how to build an intelligent FAQ bot using Python and the Telegram Bot API. We&amp;rsquo;ll go beyond simple commands by integrating a Retrieval-Augmented Generation (RAG) pipeline with LangChain.&lt;/p&gt;
&lt;p&gt;This RAG pipeline lets our bot pull information from a custom knowledge base (in our case, a simple &lt;code&gt;faqs.json&lt;/code&gt; file) and use a local Large Language Model (LLM) through Ollama to generate accurate answers. The best part? This approach (which works great with interfaces like Open WebUI) gives you full control over your models and data with zero API costs.&lt;/p&gt;
&lt;h3 id=&#34;what-is-telegram&#34;&gt;What is Telegram?&lt;/h3&gt;
&lt;p&gt;You&amp;rsquo;ve probably heard of &lt;a href=&#34;https://telegram.org/&#34;&gt;Telegram&lt;/a&gt;—it&amp;rsquo;s a popular, cloud-based instant messaging app. It’s fast, works everywhere (mobile, web, and desktop), and has powerful features like huge group chats and easy file sharing.&lt;/p&gt;
&lt;p&gt;One of its most powerful features for developers is the Telegram Bot API, an open platform that allows anyone to build and integrate automated applications (like ours!) directly into the chat interface.&lt;/p&gt;
&lt;h3 id=&#34;a-warning-on-privacy-and-encryption&#34;&gt;A Warning on Privacy and Encryption&lt;/h3&gt;
&lt;p&gt;Before we build our bot, it is critical to understand how Telegram handles encryption, as it directly impacts user privacy.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Cloud Chats (The Default)&lt;/strong&gt;: All standard chats, group chats, and all bot interactions are &amp;ldquo;Cloud Chats.&amp;rdquo; These use server-client encryption. This means your messages are encrypted between your device and Telegram&amp;rsquo;s servers, and then stored (encrypted) on their servers. This is what allows you to access your chat history from any device. However, Telegram itself holds the encryption keys and can access this data.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Secret Chats (Manual)&lt;/strong&gt;: Telegram also offers &amp;ldquo;Secret Chats,&amp;rdquo; which are end-to-end encrypted (E2EE). In this mode, only you and the recipient can read the messages. Telegram has no access. However, bots cannot operate in Secret Chats.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This means that any message a user sends to our bot is a &amp;ldquo;Cloud Chat&amp;rdquo; and is &lt;em&gt;not end-to-end encrypted&lt;/em&gt;. The data is accessible to Telegram and will be processed in plain text by our bot.py script on our server.&lt;/p&gt;
&lt;p&gt;For this reason, you should never build a bot that asks for or encourages users to send sensitive private data such as passwords, financial information, or social security numbers. Always treat bot conversations as non-private.&lt;/p&gt;
&lt;h3 id=&#34;what-is-retrieval-augmented-generation-rag&#34;&gt;What is Retrieval-Augmented Generation (RAG)?&lt;/h3&gt;
&lt;p&gt;Retrieval-Augmented Generation (RAG) is a technique that makes Large Language Models (LLMs) smarter by connecting them to external, private knowledge.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The Problem: An LLM like llama3 only knows the information it was trained on. It has no access to your company&amp;rsquo;s internal FAQs, new documents, or any private data.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The Solution (RAG): RAG solves this in two steps:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Retrieve: When you ask a question, the system first retrieves relevant information from your own knowledge base (for us, our faqs.json file).&lt;/li&gt;
&lt;li&gt;Augment: It then augments the LLM&amp;rsquo;s prompt by pasting that retrieved information in as context, along with your original question.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In short, instead of just asking the bot &amp;ldquo;What&amp;rsquo;s the shipping policy?&amp;rdquo;, we&amp;rsquo;re effectively asking, &amp;ldquo;Based on this specific text: &amp;lsquo;&amp;hellip;We offer standard shipping&amp;hellip;&amp;rsquo; — what is the shipping policy?&amp;rdquo; This forces the LLM to base its answer on our facts, not its own general knowledge, making the response accurate and reliable.&lt;/p&gt;
&lt;h3 id=&#34;what-youll-build&#34;&gt;What you’ll build&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Telegram bot&lt;/li&gt;
&lt;li&gt;faqs.json knowledge base&lt;/li&gt;
&lt;li&gt;RAG pipeline with local embeddings (FAISS) + LLM (Open WebUI)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;prerequisites&#34;&gt;Prerequisites&lt;/h3&gt;
&lt;p&gt;You’ll need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Python 3.12+&lt;/li&gt;
&lt;li&gt;a Telegram bot token (from BotFather)&lt;/li&gt;
&lt;li&gt;access to an LLM via a locally hosted Open WebUI instance (OpenAI-compatible API)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;setting-up-the-project-for-telegram-bot&#34;&gt;Setting up the Project for Telegram Bot&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;uv&lt;/code&gt; is a high-performance Python package manager, so we&amp;rsquo;ll use it to set up our project. If you don&amp;rsquo;t have it installed, you can get it with or visit the &lt;a href=&#34;https://docs.astral.sh/uv/getting-started/installation/&#34;&gt;site&lt;/a&gt; for installation steps:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pip install uv&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Create a new project directory and navigate into it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir telegram-rag-bot
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd telegram-rag-bot&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Initialize a new Python project.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;uv init --bare&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This command creates a minimal pyproject.toml file. This file will track our project&amp;rsquo;s metadata and, most importantly, its dependencies.&lt;/p&gt;
&lt;p&gt;Create a virtual environment using uv:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;uv venv&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will create a .venv directory. Activate it with the following:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;source .venv/bin/activate
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# On Windows, use
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#.venv\Scripts\activate&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Install the necessary Python packages using uv:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;uv add python-telegram-bot python-dotenv langchain langchain-openai langchain-community faiss-cpu jq sentence-transformers&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The key libraries are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;python-telegram-bot&lt;/code&gt;: For handling all Telegram communication&lt;/li&gt;
&lt;li&gt;&lt;code&gt;langchain&lt;/code&gt;: The primary framework for building the RAG pipeline&lt;/li&gt;
&lt;li&gt;&lt;code&gt;langchain-openai&lt;/code&gt;: Connector to Open WebUI’s OpenAI-compatible API&lt;/li&gt;
&lt;li&gt;&lt;code&gt;faiss-cpu&lt;/code&gt;: An efficient library for similarity search, used as a local vector store to quickly find relevant chunks of your FAQ data&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;environment-and-configuration&#34;&gt;Environment and configuration&lt;/h4&gt;
&lt;p&gt;The bot reads the Telegram token from the environment variable &lt;code&gt;BOT_TOKEN&lt;/code&gt;. We can store it in a .env file as &lt;code&gt;BOT_TOKEN=your-token-here&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;# .env (Open WebUI)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;# Open WebUI_URL must end with /v1 (e.g., http://localhost:3000/v1).&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;BOT_TOKEN&lt;/span&gt;=123456:abcdefg
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Open &lt;span style=&#34;color:#369&#34;&gt;WebUI_URL&lt;/span&gt;=http://localhost:3000/v1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Open &lt;span style=&#34;color:#369&#34;&gt;WebUI_API_KEY&lt;/span&gt;=your_key_here&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href=&#34;https://core.telegram.org/bots/features#inline-requests&#34;&gt;Inline mode&lt;/a&gt; requires enabling inline for the bot via BotFather.&lt;/p&gt;
&lt;p&gt;Create a new file named &lt;code&gt;bot.py&lt;/code&gt; and add the following code to set up and add message handlers for the Telegram bot.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;logging&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;os&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;uuid&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;import&lt;/span&gt; uuid4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;telegram&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;import&lt;/span&gt; Update, InlineQueryResultArticle, InputTextMessageContent
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;telegram.ext&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;import&lt;/span&gt; filters, MessageHandler, ApplicationBuilder, CommandHandler, ContextTypes, InlineQueryHandler
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;dotenv&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;import&lt;/span&gt; load_dotenv
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;# load .env variables&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;load_dotenv()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bot_token = os.getenv(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;BOT_TOKEN&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;# Setup logging&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;logging.basicConfig(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#038&#34;&gt;format&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;%(asctime)s&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt; - &lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;%(name)s&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt; - &lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;%(levelname)s&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt; - &lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;%(message)s&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    level=logging.INFO
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;logger = logging.getLogger(&lt;span style=&#34;color:#369&#34;&gt;__name__&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;async&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;start&lt;/span&gt;(update: Update, context: ContextTypes.DEFAULT_TYPE):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;await&lt;/span&gt; context.bot.send_message(chat_id=update.effective_chat.id, text=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;I&amp;#39;m a bot, please talk to me!&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;async&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;echo&lt;/span&gt;(update: Update, context: ContextTypes.DEFAULT_TYPE):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;await&lt;/span&gt; context.bot.send_message(chat_id=update.effective_chat.id, text=update.message.text)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;async&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;caps&lt;/span&gt;(update: Update, context: ContextTypes.DEFAULT_TYPE):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    text_caps = &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39; &amp;#39;&lt;/span&gt;.join(context.args).upper()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;await&lt;/span&gt; context.bot.send_message(chat_id=update.effective_chat.id, text=text_caps)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;async&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;inline_caps&lt;/span&gt;(update: Update, context: ContextTypes.DEFAULT_TYPE):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    query = update.inline_query.query
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#080&#34;&gt;not&lt;/span&gt; query:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    results = []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    results.append(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        InlineQueryResultArticle(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#038&#34;&gt;id&lt;/span&gt;=&lt;span style=&#34;color:#038&#34;&gt;str&lt;/span&gt;(uuid4()),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            title=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;Caps&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            input_message_content=InputTextMessageContent(query.upper())
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        )
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    )
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;await&lt;/span&gt; context.bot.answer_inline_query(update.inline_query.id, results)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;async&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;unknown&lt;/span&gt;(update: Update, context: ContextTypes.DEFAULT_TYPE):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;await&lt;/span&gt; context.bot.send_message(chat_id=update.effective_chat.id, text=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Sorry, I didn&amp;#39;t understand that command.&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;async&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;document&lt;/span&gt;(update: Update, context: ContextTypes.DEFAULT_TYPE):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; update.message.document:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        file = &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;await&lt;/span&gt; update.message.document.get_file()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        file_name = update.message.document.file_name
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;await&lt;/span&gt; file.download_to_drive(file_name)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;elif&lt;/span&gt; update.message.photo:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#888&#34;&gt;# Get the largest photo size&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        file = &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;await&lt;/span&gt; update.message.photo[-&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt;].get_file()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        file_name = &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;photo_&lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;{&lt;/span&gt;file.file_unique_id&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;.jpg&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#888&#34;&gt;# Create a unique name for photos&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;await&lt;/span&gt; file.download_to_drive(file_name)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;elif&lt;/span&gt; update.message.video:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        file = &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;await&lt;/span&gt; update.message.video.get_file()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        file_name = update.message.video.file_name
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;await&lt;/span&gt; file.download_to_drive(file_name)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;else&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;await&lt;/span&gt; update.message.reply_text(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Please send a document, photo, or video.&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;main&lt;/span&gt;() -&amp;gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;None&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    start_handler = CommandHandler(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;start&amp;#39;&lt;/span&gt;, start)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    echo_handler = MessageHandler(filters.TEXT &amp;amp; (~filters.COMMAND), echo)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    caps_handler = CommandHandler(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;caps&amp;#39;&lt;/span&gt;, caps)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    inline_caps_handler = InlineQueryHandler(inline_caps)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    document_handler = MessageHandler(filters.PHOTO | filters.Document.PDF | filters.VIDEO, document)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    unknown_handler = MessageHandler(filters.COMMAND, unknown)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    application = ApplicationBuilder().token(bot_token).build()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    application.add_handler(start_handler)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    application.add_handler(echo_handler)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    application.add_handler(caps_handler)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    application.add_handler(inline_caps_handler)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    application.add_handler(document_handler)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    application.add_handler(unknown_handler)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;# Run the bot&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    logger.info(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Starting bot polling...&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    application.run_polling()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;__name__&lt;/span&gt; == &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    main()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4 id=&#34;try-it-out&#34;&gt;Try it out&lt;/h4&gt;
&lt;p&gt;To run the application, simply run:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;uv run bot.py&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Search for your bot name in Telegram and send the bot a message or command like &lt;code&gt;/start&lt;/code&gt; or &lt;code&gt;/caps&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id=&#34;what-this-bot-does&#34;&gt;What this bot does&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Responds to /start with a greeting&lt;/li&gt;
&lt;li&gt;Echoes back any plain text message (that isn’t a command)&lt;/li&gt;
&lt;li&gt;Converts text to uppercase via /caps or inline mode&lt;/li&gt;
&lt;li&gt;Downloads files users send (photos, PDFs, and videos) to local storage&lt;/li&gt;
&lt;li&gt;Politely handles unknown commands&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;core-structure&#34;&gt;Core structure&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;start()&lt;/code&gt;: Sends a simple welcome message when the user runs /start&lt;/li&gt;
&lt;li&gt;&lt;code&gt;echo()&lt;/code&gt;: Replies with the exact same text the user sent (only for non-commands)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;caps()&lt;/code&gt;: Turns the arguments after /caps into uppercase and sends them back&lt;/li&gt;
&lt;li&gt;&lt;code&gt;inline_caps()&lt;/code&gt;: Provides an inline result that uppercases whatever users type after @YourBotName in any chat&lt;/li&gt;
&lt;li&gt;&lt;code&gt;document()&lt;/code&gt;: Saves received media to disk:
&lt;ul&gt;
&lt;li&gt;Photos: Downloads the largest size, naming it photo_&amp;lt;unique_id&amp;gt;.jpg&lt;/li&gt;
&lt;li&gt;PDFs: Downloads using the document’s file name. Note: The filter only accepts PDFs as documents&lt;/li&gt;
&lt;li&gt;Videos: Downloads using the video’s file name&lt;/li&gt;
&lt;li&gt;If none of these are present, it prompts the user to send a supported file&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;unknown()&lt;/code&gt;: Catches any unrecognized commands and replies with a friendly error&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;handlers-and-filters&#34;&gt;Handlers and filters&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;CommandHandler(&#39;start&#39;, start)&lt;/code&gt; and &lt;code&gt;CommandHandler(&#39;caps&#39;, caps)&lt;/code&gt; handle &lt;a href=&#34;https://core.telegram.org/bots/features#commands&#34;&gt;commands&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MessageHandler(filters.TEXT &amp;amp; (~filters.COMMAND), echo)&lt;/code&gt; ensures normal text (not commands) is echoed&lt;/li&gt;
&lt;li&gt;&lt;code&gt;InlineQueryHandler(inline_caps)&lt;/code&gt; answers inline queries&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MessageHandler(filters.PHOTO | filters.Document.PDF | filters.VIDEO, document)&lt;/code&gt; restricts downloads to photos, PDFs, and videos&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MessageHandler(filters.COMMAND, unknown)&lt;/code&gt; is added last to catch all other commands&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;running-the-bot&#34;&gt;Running the bot&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;main()&lt;/code&gt; wires up the handlers, builds the Application with the token, logs a startup message, and starts long polling via &lt;code&gt;application.run_polling()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This script is a clean, async-first Telegram bot scaffold that demonstrates commands, inline mode, message filtering, and media downloads—ready to extend for more sophisticated behaviors.&lt;/p&gt;
&lt;p&gt;Now that we have our bot ready, we will extend the code to add a RAG pipeline to the bot.&lt;/p&gt;
&lt;h3 id=&#34;setting-up-the-knowledge-base&#34;&gt;Setting up the knowledge base&lt;/h3&gt;
&lt;p&gt;Let’s set up a knowledge base by creating a file named &lt;code&gt;faqs.json&lt;/code&gt; to hold our data. The RAG pipeline will load and search this content. An example structure is shown below.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;category&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;General&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;question&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;What are your operating hours?&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;answer&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Monday to Friday, 9:00 AM–5:00 PM (local time).&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;category&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Accounts&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;question&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;How do I reset my password?&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;answer&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Go to our website, click Login, then Forgot Password. Check your email for the reset link.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;setting-up-the-rag-pipeline&#34;&gt;Setting up the RAG Pipeline&lt;/h3&gt;
&lt;p&gt;The RAG pipeline is the engine that converts our static JSON file into a searchable brain for our bot. This part initializes once and creates a vector database. In simple steps,&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Load faqs.json&lt;/li&gt;
&lt;li&gt;Create embeddings&lt;/li&gt;
&lt;li&gt;Store them in FAISS&lt;/li&gt;
&lt;li&gt;When a user asks a question, find similar answers and ask the LLM to write a reply based only on those&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&#34;data-ingestion-indexing-the-faqs-handled-by-setup_rag_chain-method&#34;&gt;Data Ingestion (Indexing the FAQs) handled by &lt;code&gt;setup_rag_chain()&lt;/code&gt; method&lt;/h5&gt;
&lt;p&gt;This part happens once when the bot starts. We load the &lt;code&gt;faqs.json&lt;/code&gt; file, create vector embeddings, and store them in a searchable database (FAISS).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Load Data: Read the faqs.json file&lt;/li&gt;
&lt;li&gt;Embeddings: Use an embedding model (like &lt;a href=&#34;https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2&#34;&gt;&lt;code&gt;HuggingFace (Sentence-Transformers) all‑MiniLM‑L6‑v2.&lt;/code&gt;&lt;/a&gt;) to convert the text into numerical vectors&lt;/li&gt;
&lt;li&gt;Vector Store: Store these vectors in a FAISS index for fast retrieval&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&#34;the-rag-retrieval-logic-handled-by-handle_message-method&#34;&gt;The RAG Retrieval Logic handled by &lt;code&gt;handle_message()&lt;/code&gt; method&lt;/h5&gt;
&lt;p&gt;When a user asks a question:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Embed Query: The user&amp;rsquo;s question is converted into an embedding vector&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Retrieve Context: The query vector is used to perform a similarity search against the FAISS index. This returns the top K most relevant FAQs (question and answer pairs)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Construct Prompt: A final prompt is built, containing the user&amp;rsquo;s question and the retrieved relevant context&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Example Prompt Template:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;You are an expert FAQ assistant. Use the following context to answer
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;the user&amp;#39;s question. If the context does not contain the answer,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;state that you cannot help with this specific question. Context:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[Retrieved FAQs] Question: [User&amp;#39;s message]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Generate Response: The complete prompt is sent to our Open WebUI model via the OpenAI-compatible API, e.g. &lt;code&gt;gpt-5&lt;/code&gt; or another model exposed by Open WebUI, which generates a coherent, context-grounded final answer&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Send to Telegram: The bot sends the LLM&amp;rsquo;s final response back to the user&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&#34;new-capabilities-added-to-botpy&#34;&gt;New capabilities added to &lt;code&gt;bot.py&lt;/code&gt;&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;RAG pipeline: Loads FAQs from a local JSON file, embeds them with HuggingFace, retrieves the most relevant entries via FAISS, and drafts answers with an LLM served by Open WebUI.&lt;/li&gt;
&lt;li&gt;Inline UX polish: Sends a “typing…” chat action while the model thinks.&lt;/li&gt;
&lt;li&gt;Persisted chain: The RAG chain is built once at startup and stored in bot_data for reuse across messages.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The core logic of our bot will revolve around an update to the standard message handler. When a user sends a question, the bot no longer looks for a simple command; instead, it passes the question to the RAG pipeline.&lt;/p&gt;
&lt;h4 id=&#34;try-it-out-1&#34;&gt;Try it out&lt;/h4&gt;
&lt;p&gt;To run the application, simply run&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;uv run bot.py&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Search for your bot name in telegram and send the bot a message like &lt;code&gt;What are your operating hours?&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Changes to the RAG pipeline setup are available &lt;a href=&#34;https://github.com/bimalghartimagar/telegram-rag-bot/commit/4afac21e085c2782f98fffc66bb2cca27e6c7f50&#34;&gt;here&lt;/a&gt;. The source code is available &lt;a href=&#34;https://github.com/bimalghartimagar/telegram-rag-bot&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;By integrating a RAG pipeline, we&amp;rsquo;ve leveled up our Telegram bot from a simple command processor to a knowledge-aware assistant. This approach ensures our bot&amp;rsquo;s answers are accurate, grounded in our provided faqs.json data, and remain consistent, dramatically reducing the chance of &amp;ldquo;hallucinations&amp;rdquo; from the underlying LLM.&lt;/p&gt;
&lt;p&gt;This architecture is powerful and scalable. To expand its capabilities, we only need to update the faqs.json file and re-run the indexing step—no need to retrain or modify the core LLM!&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Creating API for Invoice Generator Using C# and Minimal APIs</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2025/07/invoice-generator-api-c-sharp/"/>
      <id>https://www.endpointdev.com/blog/2025/07/invoice-generator-api-c-sharp/</id>
      <published>2025-07-02T00:00:00+00:00</published>
      <author>
        <name>Bimal Gharti Magar</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;img src=&#34;/blog/2025/07/invoice-generator-api-c-sharp/black-and-pink-flowers.webp&#34; alt=&#34;A top-down view of flowers with light pink petals and black centers.&#34;&gt;&lt;/p&gt;
&lt;!-- Photo by Seth Jensen, 2025. --&gt;
&lt;p&gt;In this blog post, we will explore how to create a robust invoice generator API using .NET 9 and &lt;a href=&#34;https://learn.microsoft.com/en-us/aspnet/core/fundamentals/minimal-apis/overview?view=aspnetcore-9.0&#34;&gt;minimal APIs&lt;/a&gt;, with a focus on integrating it with an existing Vue frontend whose implementation we covered in a &lt;a href=&#34;/blog/2025/01/learning-vue-3-composables-by-creating-an-invoice-generator/&#34;&gt;previous blog post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We will use the minimal APIs framework to create a RESTful API that can be easily used by our Vue application. Minimal APIs require less boilerplate code and configuration compared to traditional controller-based approaches. It is suited for smaller APIs, microservices, or serverless functions. You can learn more about choosing between controller-based APIs and minimal APIs &lt;a href=&#34;https://learn.microsoft.com/en-us/aspnet/core/fundamentals/apis?view=aspnetcore-9.0&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;prerequisites&#34;&gt;Prerequisites&lt;/h3&gt;
&lt;p&gt;Before going further into the code, we should make sure to have the following tools and technologies installed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;.NET 9 (the latest version of the .NET runtime)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Additionally, we already have an existing Vue frontend implementation that lacks API connectivity from our previous post. We will guide you through the process of integrating the Invoice Generator API with Vue application.&lt;/p&gt;
&lt;h3 id=&#34;setting-up-the-project&#34;&gt;Setting up the Project&lt;/h3&gt;
&lt;p&gt;We will use the &lt;code&gt;dotnet&lt;/code&gt; command to create a new .NET 9 project and set up the minimal APIs framework using the steps below:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a new .NET Core Web API project using the following command:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dotnet new webapi -n invoice-generator-api&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ol start=&#34;2&#34;&gt;
&lt;li&gt;Navigate to the newly created project directory:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd invoice-generator-api&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ol start=&#34;3&#34;&gt;
&lt;li&gt;Open the &lt;code&gt;Program.cs&lt;/code&gt; file which should look like below.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;var&lt;/span&gt; builder = WebApplication.CreateBuilder(args);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// Add services to the container.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;builder.Services.AddOpenApi();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;var&lt;/span&gt; app = builder.Build();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// Configure the HTTP request pipeline.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; (app.Environment.IsDevelopment())
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    app.MapOpenApi();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;app.UseHttpsRedirection();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;var&lt;/span&gt; summaries = &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;new&lt;/span&gt;[]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Freezing&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Bracing&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Chilly&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Cool&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Mild&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Warm&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Balmy&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Hot&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Sweltering&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Scorching&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;app.MapGet(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;/weatherforecast&amp;#34;&lt;/span&gt;, () =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;var&lt;/span&gt; forecast =  Enumerable.Range(&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;5&lt;/span&gt;).Select(index =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;new&lt;/span&gt; WeatherForecast
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            Random.Shared.Next(-&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;20&lt;/span&gt;, &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;55&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            summaries[Random.Shared.Next(summaries.Length)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        .ToArray();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; forecast;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.WithName(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;GetWeatherForecast&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;app.Run();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;record&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;WeatherForecast&lt;/span&gt;(DateOnly Date, &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;int&lt;/span&gt; TemperatureC, &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string?&lt;/span&gt; Summary)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;int&lt;/span&gt; TemperatureF =&amp;gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;32&lt;/span&gt; + (&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;int&lt;/span&gt;)(TemperatureC / &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0.5556&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ol start=&#34;4&#34;&gt;
&lt;li&gt;We will also add the following packages for Swagger UI, Entity Framework, and the Entity Framework Core provider for PostgreSQL.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dotnet add package Microsoft.Extensions.ApiDescription.Server
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dotnet add package Swashbuckle.AspNetCore.SwaggerUi
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dotnet add package Microsoft.EntityFrameworkCore
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dotnet add package Npgsql.EntityFrameworkCore.PostgreSQL
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dotnet add package Microsoft.EntityFrameworkCore.Design&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;setting-up-the-swagger-ui&#34;&gt;Setting up the Swagger UI&lt;/h3&gt;
&lt;p&gt;Update &lt;code&gt;Program.cs&lt;/code&gt; and configure Swagger UI to point to the OpenAPI JSON file.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; if (app.Environment.IsDevelopment())
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     app.MapOpenApi();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    app.UseSwaggerUI(config =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+        config.SwaggerEndpoint(&amp;#34;/openapi/v1.json&amp;#34;, &amp;#34;v1&amp;#34;);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    });
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; app.UseHttpsRedirection();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Once the application is running using &lt;code&gt;dotnet run&lt;/code&gt;, you can access Swagger UI at &lt;code&gt;http://localhost:&amp;lt;PORT&amp;gt;/swagger&lt;/code&gt; on your browser, which should look like below.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2025/07/invoice-generator-api-c-sharp/swagger.webp&#34; alt=&#34;A webpage titled &amp;ldquo;invoice-generator-api | v1&amp;rdquo;. There is a dropdown labeled &amp;ldquo;Servers&amp;rdquo; with &amp;ldquo;https://localhost:7188/&amp;rdquo; selected. Below, a section labeled &amp;ldquo;invoice-generator-api&amp;rdquo; is expanded, and within is a blue list item labeled &amp;ldquo;GET /weatherforecast&amp;rdquo;. Below, a list of schemas shows one schema labeled &amp;ldquo;WeatherForecast&amp;rdquo;&#34;&gt;&lt;/p&gt;
&lt;h3 id=&#34;setting-up-the-database-context-with-entity-framework&#34;&gt;Setting up the Database Context with Entity Framework&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Create a file, &lt;code&gt;InvoiceDbContext.cs&lt;/code&gt;, in the root of the project and add the following code.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;using&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;Microsoft.EntityFrameworkCore&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;InvoiceDbContext&lt;/span&gt; : DbContext
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; InvoiceDbContext(DbContextOptions&amp;lt;InvoiceDbContext&amp;gt; options)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     : &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;base&lt;/span&gt;(options)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Update the &lt;code&gt;Program.cs&lt;/code&gt; file to include the configuration for connecting to the PostgreSQL database using Entity Framework.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+using Microsoft.EntityFrameworkCore;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt; var builder = WebApplication.CreateBuilder(args);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+builder.Services.AddDbContext&amp;lt;InvoiceDbContext&amp;gt;(options =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    options.UseNpgsql(builder.Configuration.GetConnectionString(&amp;#34;InvoiceDbcontext&amp;#34;)));
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add the connection string &lt;code&gt;InvoiceDbcontext&lt;/code&gt; in the appsettings.json file as shown below:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &amp;#34;Microsoft.AspNetCore&amp;#34;: &amp;#34;Warning&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;-  &amp;#34;AllowedHosts&amp;#34;: &amp;#34;*&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+  &amp;#34;AllowedHosts&amp;#34;: &amp;#34;*&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+  &amp;#34;ConnectionStrings&amp;#34;: {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    &amp;#34;InvoiceDbcontext&amp;#34;: &amp;#34;Host=&amp;lt;HOSTNAME&amp;gt;;Port=&amp;lt;PORT&amp;gt;;Database=&amp;lt;DATABASE&amp;gt;;Username=&amp;lt;USERNAME&amp;gt;;Password=&amp;lt;PASSWORD&amp;gt;;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+  }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;designing-the-invoice-generator-api&#34;&gt;Designing the Invoice Generator API&lt;/h3&gt;
&lt;p&gt;The next step is to design the API endpoints required for invoice generation. We will need the following endpoints:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;GET /api/invoice&lt;/code&gt; — Get list of invoices&lt;/li&gt;
&lt;li&gt;&lt;code&gt;POST /api/invoice&lt;/code&gt; — Create a new invoice&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET /api/invoice/{id}&lt;/code&gt; — Get an invoice using ID&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PUT /api/invoice/{id}&lt;/code&gt; — Update an invoice using ID&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DELETE /api/invoice/{id}&lt;/code&gt; — Soft delete an invoice using ID&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PUT /api/invoice/{id}/upload-logo&lt;/code&gt; — upload logo to saved invoice using ID&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DELETE /api/invoice/{invoiceId}/detail/{id}&lt;/code&gt; — Soft delete invoice line item using line item ID and invoice ID&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We will also need data models and entities to represent invoices and invoice line items. Let&amp;rsquo;s create the following classes in the model folder:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;Base&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;int&lt;/span&gt; Id { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; DateTime CreatedAt { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; } = DateTime.UtcNow;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; DateTime? ModifiedAt { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;bool&lt;/span&gt; IsDeleted { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; } = &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; DateTime? DeletedAt { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;Invoice&lt;/span&gt; : Base
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string?&lt;/span&gt; Name { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string?&lt;/span&gt; logo { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string?&lt;/span&gt; Number { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string?&lt;/span&gt; PONumber { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;virtual&lt;/span&gt; List&amp;lt;InvoiceItem&amp;gt; InvoiceItems { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; } = &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;new&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; UsageAmount? DiscountAmount { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; UsageAmount? TaxAmount { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; UsageAmount? ShippingAmount { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;decimal&lt;/span&gt; TotalAmount { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;decimal&lt;/span&gt; PaidAmount { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string?&lt;/span&gt; Sender { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string?&lt;/span&gt; Buyer { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; Status? Status { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string?&lt;/span&gt; Notes { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string?&lt;/span&gt; Terms { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; DateTime? Date { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; DateTime? DueDate { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;bool&lt;/span&gt; SentToBuyer { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; } = &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;InvoiceItem&lt;/span&gt; : Base
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt; Description { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; } = &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt;.Empty;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;int&lt;/span&gt; Quantity { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;decimal&lt;/span&gt; Rate { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;decimal&lt;/span&gt; Amount { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt; =&amp;gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;this&lt;/span&gt;.Quantity * &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;this&lt;/span&gt;.Rate; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;UsageAmount&lt;/span&gt; : Base
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;bool&lt;/span&gt; IsUsed { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; } = &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;bool&lt;/span&gt; IsPercentage { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; } = &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;decimal&lt;/span&gt; Value { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; } = &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Will will now use these classes to create tables in the database and then define a &lt;code&gt;DBSet&lt;/code&gt; for each class in our &lt;code&gt;InvoiceDbContext.cs&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; public InvoiceDbContext(DbContextOptions&amp;lt;InvoiceDbContext&amp;gt; options)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  : base(options)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    public DbSet&amp;lt;Invoice&amp;gt; Invoices =&amp;gt; Set&amp;lt;Invoice&amp;gt;();
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    public DbSet&amp;lt;InvoiceItem&amp;gt; InvoiceItems =&amp;gt; Set&amp;lt;InvoiceItem&amp;gt;();
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    public DbSet&amp;lt;UsageAmount&amp;gt; UsageAmounts =&amp;gt; Set&amp;lt;UsageAmount&amp;gt;();
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Since we will be using the soft delete feature in our API, we will use &lt;a href=&#34;https://learn.microsoft.com/en-us/ef/core/querying/filters&#34;&gt;Global Query Filters&lt;/a&gt; to filter out the deleted records from our table. So, we configure the query filters in &lt;code&gt;OnModelCreating&lt;/code&gt; using the &lt;code&gt;HasQueryFilter&lt;/code&gt; API in &lt;code&gt;InvoiceDbContext.cs&lt;/code&gt;. After which, the file should look like below.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; public InvoiceDbContext(DbContextOptions&amp;lt;InvoiceDbContext&amp;gt; options)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  : base(options)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    protected override void OnModelCreating(ModelBuilder modelBuilder)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+        modelBuilder.Entity&amp;lt;Invoice&amp;gt;().HasQueryFilter(p =&amp;gt; !p.IsDeleted);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+        modelBuilder.Entity&amp;lt;InvoiceItem&amp;gt;().HasQueryFilter(p =&amp;gt; !p.IsDeleted);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+        modelBuilder.Entity&amp;lt;UsageAmount&amp;gt;().HasQueryFilter(p =&amp;gt; !p.IsDeleted);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    public DbSet&amp;lt;Invoice&amp;gt; Invoices =&amp;gt; Set&amp;lt;Invoice&amp;gt;();
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    public DbSet&amp;lt;InvoiceItem&amp;gt; InvoiceItems =&amp;gt; Set&amp;lt;InvoiceItem&amp;gt;();
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    public DbSet&amp;lt;UsageAmount&amp;gt; UsageAmounts =&amp;gt; Set&amp;lt;UsageAmount&amp;gt;();
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;creating-and-running-database-migrations&#34;&gt;Creating and running database migrations&lt;/h3&gt;
&lt;p&gt;We have defined models for our data models, but we need to create a database and tables for them. We can do this using Entity Framework tool &lt;code&gt;dotnet ef&lt;/code&gt;. On the command prompt, in the root path of project, run the following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dotnet ef migrations add &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;create table and columns&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This command will create migration files in the &lt;code&gt;Migrations&lt;/code&gt; folder. We can run this migration using the following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dotnet ef database update&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;implementing-api-endpoints&#34;&gt;Implementing API Endpoints&lt;/h3&gt;
&lt;p&gt;Now that we have designed the API endpoints and data models, let&amp;rsquo;s implement them using minimal APIs. We will create a new &lt;code&gt;endpoints&lt;/code&gt; folder and add an &lt;code&gt;InvoiceEndpoints.cs&lt;/code&gt; file in it. This file will contain the implementation for the Invoice API endpoints.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// InvoiceEndopints.cs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;using&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;Microsoft.EntityFrameworkCore&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;using&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;Microsoft.Extensions.Hosting.Internal&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;InvoiceEndpoints&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;static&lt;/span&gt; List&amp;lt;Invoice&amp;gt; Invoices = &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;new&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;static&lt;/span&gt; RouteGroupBuilder MapInvoiceEndpoints(&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;this&lt;/span&gt; RouteGroupBuilder &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;group&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#888&#34;&gt;// Return list of invoices&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;group&lt;/span&gt;.MapGet(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;async&lt;/span&gt; (InvoiceDbContext db) =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;await&lt;/span&gt; db.Invoices.Include(x =&amp;gt; x.InvoiceItems).ToListAsync();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        })
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .WithSummary(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Get list of invoices&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#888&#34;&gt;// Return an existing invoice&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;group&lt;/span&gt;.MapGet(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;/{id}&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;async&lt;/span&gt; (&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;int&lt;/span&gt; id, InvoiceDbContext db) =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;await&lt;/span&gt; db.Invoices.Include(x =&amp;gt; x.InvoiceItems).FirstOrDefaultAsync(x =&amp;gt; x.Id == id)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;is&lt;/span&gt; Invoice invoice
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                ? Results.Ok(invoice)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                : Results.NotFound();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        })
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .WithSummary(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Get an invoice using id&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#888&#34;&gt;// Create an invoice&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;group&lt;/span&gt;.MapPost(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;async&lt;/span&gt; (Invoice invoice, InvoiceDbContext db) =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            invoice.DueDate = invoice.DueDate.HasValue ? invoice.DueDate.Value.ToUniversalTime() : &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;null&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            invoice.Date = invoice.Date.HasValue ? invoice.Date.Value.ToUniversalTime() : &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;null&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            db.Invoices.Add(invoice);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;await&lt;/span&gt; db.SaveChangesAsync();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; Results.Created(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;$&amp;#34;/api/invoice/{invoice.Id}&amp;#34;&lt;/span&gt;, invoice);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        })
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .WithSummary(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Create a new invoice&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#888&#34;&gt;// Create a new line item for an existing invoice&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;group&lt;/span&gt;.MapPost(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;/{id}/items&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;async&lt;/span&gt; (&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;int&lt;/span&gt; id, List&amp;lt;InvoiceItem&amp;gt; invoiceItems, InvoiceDbContext db) =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;await&lt;/span&gt; db.Invoices.FindAsync(id)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;is&lt;/span&gt; not Invoice invoice)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; Results.NotFound();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            invoice.InvoiceItems.AddRange(invoiceItems);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;await&lt;/span&gt; db.SaveChangesAsync();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; Results.Created(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;$&amp;#34;/api/invoice/{invoice.Id}&amp;#34;&lt;/span&gt;, invoice);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        })
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .WithSummary(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Create new line items for invoice&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#888&#34;&gt;// Update an existing invoice&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;group&lt;/span&gt;.MapPut(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;/{id}&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;async&lt;/span&gt; (&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;int&lt;/span&gt; id, Invoice inputInvoice, InvoiceDbContext db) =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;var&lt;/span&gt; invoice = &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;await&lt;/span&gt; db.Invoices.AsNoTracking().FirstOrDefaultAsync(x =&amp;gt; x.Id == id);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; (invoice &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;is&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;null&lt;/span&gt;) &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; Results.NotFound();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            invoice.Id = id;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            db.Invoices.Update(inputInvoice);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;await&lt;/span&gt; db.SaveChangesAsync();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; Results.NoContent();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        })
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .WithSummary(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Update invoice&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#888&#34;&gt;// Upload invoice logo image file for an existing invoice&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;group&lt;/span&gt;.MapPut(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;/{id}/upload-logo&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;async&lt;/span&gt; (&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;int&lt;/span&gt; id, IFormFile uploadImageFile, InvoiceDbContext db) =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;var&lt;/span&gt; invoice = &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;await&lt;/span&gt; db.Invoices.AsNoTracking().FirstOrDefaultAsync(x =&amp;gt; x.Id == id);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; (invoice &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;is&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;null&lt;/span&gt;) &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; Results.NotFound();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; (uploadImageFile == &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;null&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;new&lt;/span&gt; ArgumentNullException(nameof(uploadImageFile));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;var&lt;/span&gt; contentPath = Environment.CurrentDirectory;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;var&lt;/span&gt; uploadPath = Path.Combine(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Uploads&amp;#34;&lt;/span&gt;, id.ToString());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;var&lt;/span&gt; rootPath = Path.Combine(contentPath, uploadPath);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; (!Directory.Exists(rootPath))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                Directory.CreateDirectory(rootPath);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt;[] allowedFileExtensions = [&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;.jpg&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;.jpeg&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;.png&amp;#34;&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;var&lt;/span&gt; ext = Path.GetExtension(uploadImageFile.FileName);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; (!allowedFileExtensions.Contains(ext))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;new&lt;/span&gt; ArgumentException(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;$&amp;#34;Please upload only .jpg, .jpeg, and .png images.&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#888&#34;&gt;// generate a unique filename&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;var&lt;/span&gt; fileName = &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;$&amp;#34;{Guid.NewGuid().ToString()}{ext}&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;var&lt;/span&gt; fileNameWithPath = Path.Combine(uploadPath, fileName);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;var&lt;/span&gt; rootPathWithFileName = Path.Combine(rootPath, fileName);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;using&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;var&lt;/span&gt; stream = &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;new&lt;/span&gt; FileStream(rootPathWithFileName, FileMode.Create);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;await&lt;/span&gt; uploadImageFile.CopyToAsync(stream);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            invoice.logo = fileNameWithPath;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            db.Update(invoice);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;await&lt;/span&gt; db.SaveChangesAsync();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; Results.NoContent();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          })
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          .DisableAntiforgery()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          .WithSummary(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;upload logo&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#888&#34;&gt;// soft delete an invoice&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;group&lt;/span&gt;.MapDelete(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;/{id}&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;async&lt;/span&gt; (&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;int&lt;/span&gt; id, InvoiceDbContext db) =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;await&lt;/span&gt; db.Invoices.FindAsync(id) &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;is&lt;/span&gt; Invoice todo)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                todo.IsDeleted = &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                todo.DeletedAt = DateTime.Now.ToUniversalTime();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;await&lt;/span&gt; db.SaveChangesAsync();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; Results.NoContent();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; Results.NotFound();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        })
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .WithSummary(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Soft delete an invoice&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;group&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then we will also implement &lt;code&gt;InvoiceDetailEndpoint.cs&lt;/code&gt;. We will only define a delete endpoint for soft deleting the line items. We created this also to demonstrate how to use multiple files in the &lt;code&gt;Program.cs&lt;/code&gt; to map the endpoints to a certain URL.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// InvoiceDetailEndpoint.cs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;InvoiceDetailEndpoints&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;static&lt;/span&gt; RouteGroupBuilder MapInvoiceDetailEndpoints(&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;this&lt;/span&gt; RouteGroupBuilder &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;group&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;group&lt;/span&gt;.MapDelete(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;/{id}&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;async&lt;/span&gt; (&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;int&lt;/span&gt; id, InvoiceDbContext db) =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;await&lt;/span&gt; db.InvoiceItems.FindAsync(id) &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;is&lt;/span&gt; InvoiceItem invoiceItem)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                invoiceItem.IsDeleted = &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                invoiceItem.DeletedAt = DateTime.Now.ToUniversalTime();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;await&lt;/span&gt; db.SaveChangesAsync();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; Results.NoContent();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; Results.NotFound();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }).WithSummary(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Soft delete invoice line item&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;group&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Similar to how traditional controller APIs are separated in their own files, we now have the implementation for the endpoints in two files. We will now register and map the endpoints to a preferred URL using &lt;code&gt;MapGroup&lt;/code&gt; in the &lt;code&gt;Program.cs&lt;/code&gt; file.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; // Program.cs
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+var root = app.MapGroup(&amp;#34;api&amp;#34;);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+var invoice = root.MapGroup(&amp;#34;invoice&amp;#34;).MapInvoiceEndpoints();
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+var invoiceDetail = root.MapGroup(&amp;#34;invoice/{invoiceId}/detail&amp;#34;).MapInvoiceDetailEndpoints();
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt; app.Run();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We also need to add a config to expose the &lt;code&gt;Uploads&lt;/code&gt; folder so the images can be loaded from the running API server. Also, make sure to create the &lt;code&gt;Uploads&lt;/code&gt; folder before running the application, otherwise the application wouldn&amp;rsquo;t run.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; // Program.cs
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; var invoice = root.MapGroup(&amp;#34;invoice&amp;#34;).MapInvoiceEndpoints();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; var invoiceDetail = root.MapGroup(&amp;#34;invoice/{invoiceId}/detail&amp;#34;).MapInvoiceDetailEndpoints();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+app.UseStaticFiles(new StaticFileOptions
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+{
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    FileProvider = new PhysicalFileProvider(
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+        Path.Combine(builder.Environment.ContentRootPath, &amp;#34;Uploads&amp;#34;)),
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    RequestPath = &amp;#34;/Uploads&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+});
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt; app.Run();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;adding-cors-for-development&#34;&gt;Adding CORS for development&lt;/h3&gt;
&lt;p&gt;While working locally we usually run the frontend application and the API application in different ports, so CORS is required for the frontend application to access the API. To enable CORS in development mode, we can add the following code snippet to our &lt;code&gt;Program.cs&lt;/code&gt; file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; // Program.cs
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; using Microsoft.EntityFrameworkCore;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; using Microsoft.Extensions.FileProviders;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; var builder = WebApplication.CreateBuilder(args);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+var MyAllowSpecificOrigins = &amp;#34;_myAllowSpecificOrigins&amp;#34;;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+builder.Services.AddCors(options =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+{
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    options.AddPolicy(name: MyAllowSpecificOrigins,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+                      policy =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+                      {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+                          policy.AllowAnyOrigin();
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+                          policy.AllowAnyHeader();
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+                          policy.AllowAnyMethod();
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+                      });
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+});
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; builder.Services.AddDbContext&amp;lt;InvoiceDbContext&amp;gt;(options =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     options.UseNpgsql(builder.Configuration.GetConnectionString(&amp;#34;InvoiceDbcontext&amp;#34;)));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; app.MapGet(&amp;#34;/weatherforecast&amp;#34;, () =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; var root = app.MapGroup(&amp;#34;api&amp;#34;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; var invoice = root.MapGroup(&amp;#34;invoice&amp;#34;).MapInvoiceEndpoints();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; var invoiceDetail = root.MapGroup(&amp;#34;invoice/{invoiceId}/detail&amp;#34;).MapInvoiceDetailEndpoints();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+app.UseCors(MyAllowSpecificOrigins);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt; app.UseStaticFiles(new StaticFileOptions
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     FileProvider = new PhysicalFileProvider(
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, we can start the application and test our API. When we go to &lt;code&gt;/swagger&lt;/code&gt;, we can see our API endpoints.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2025/07/invoice-generator-api-c-sharp/swagger-apis.webp&#34; alt=&#34;The same API webpage as before, but now our endpoints are visible: &amp;ldquo;GET /api/invoice&amp;rdquo;, &amp;ldquo;DELETE /api/invoice/{id}&amp;rdquo;, etc. The schemas now show &amp;ldquo;Invoice&amp;rdquo;, &amp;ldquo;InvoiceItem&amp;rdquo;, etc.&#34;&gt;&lt;/p&gt;
&lt;p&gt;The source code for the API is available &lt;a href=&#34;https://github.com/bimalghartimagar/invoice-generator-api&#34;&gt;on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;integrating-with-vue-3-application&#34;&gt;Integrating with Vue 3 Application&lt;/h3&gt;
&lt;p&gt;We already created a Vue 3 application in the &lt;a href=&#34;/blog/2025/01/learning-vue-3-composables-by-creating-an-invoice-generator/&#34;&gt;previous blog&lt;/a&gt;. Now, we will integrate our API with the Vue application.&lt;/p&gt;
&lt;p&gt;To integrate the Invoice Generator API with our Vue 3 application, we will need to configure API calls from the frontend to interact with the API. We will follow the following steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Install the &lt;code&gt;axios&lt;/code&gt; package in our Vue 3 project:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;npm install axios&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ol start=&#34;2&#34;&gt;
&lt;li&gt;Create a new file called &lt;code&gt;index.ts&lt;/code&gt; in the &lt;code&gt;services&lt;/code&gt; folder of our Vue 3 project and add the following code. Also, add &lt;code&gt;.env&lt;/code&gt; file with key &lt;code&gt;VITE_API_URL&lt;/code&gt; and value of the API URL:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-typescript&#34; data-lang=&#34;typescript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// services/index.ts
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;import&lt;/span&gt; axios &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;axios&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;export&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;default&lt;/span&gt; axios.create({
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    baseURL: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;import.meta.env.VITE_API_URL&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    timeout: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;5000&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# .env
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;VITE_API_URL=https://localhost:7041/api/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;VITE_BACKEND_URL=https://localhost:7041/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ol start=&#34;3&#34;&gt;
&lt;li&gt;Create a new file called &lt;code&gt;invoiceService.ts&lt;/code&gt; in the &lt;code&gt;services&lt;/code&gt; folder of your Vue 3 project. Add the methods that calls the API endpoints:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;import&lt;/span&gt; { Invoice, InvoiceItem } from &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;../types/index.type&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;import&lt;/span&gt; axios from &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;./&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;export&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;default&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    getInvoices: &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;async&lt;/span&gt; () =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;await&lt;/span&gt; axios.get(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;invoice&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    getInvoice: &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;async&lt;/span&gt; (id) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;await&lt;/span&gt; axios.get(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;`invoice/&lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;${&lt;/span&gt;id&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;`&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    saveInvoice: &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;async&lt;/span&gt; (data: Invoice) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;await&lt;/span&gt; axios.post(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;invoice&amp;#39;&lt;/span&gt;, data)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    deleteInvoice: &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;async&lt;/span&gt; (id: number) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;await&lt;/span&gt; axios.&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;delete&lt;/span&gt;(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;`invoice/&lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;${&lt;/span&gt;id&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;`&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    updateInvoice: &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;async&lt;/span&gt; (id: number, data: Invoice) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;await&lt;/span&gt; axios.put(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;`invoice/&lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;${&lt;/span&gt;id&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;`&lt;/span&gt;, data)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    uploadLogo: &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;async&lt;/span&gt; (invoiceId, file) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; formData = &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;new&lt;/span&gt; FormData();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        formData.append(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;imageFile&amp;#34;&lt;/span&gt;, file);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; axios.put(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;`invoice/&lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;${&lt;/span&gt;invoiceId&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;/upload-logo`&lt;/span&gt;, formData, { headers: { &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Content-Type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;multipart/form-data&amp;#34;&lt;/span&gt; } });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    addLineItem: &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;async&lt;/span&gt; (id: number, data: InvoiceItem) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;await&lt;/span&gt; axios.post(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;`invoice/&lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;${&lt;/span&gt;id&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;/detail/`&lt;/span&gt;, data);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    updateLineItem: &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;async&lt;/span&gt; (id: number, lineId: number, data: InvoiceItem) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;await&lt;/span&gt; axios.put(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;`invoice/&lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;${&lt;/span&gt;id&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;/detail/&lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;${&lt;/span&gt;lineId&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;`&lt;/span&gt;, data)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    deleteLineItem: &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;async&lt;/span&gt; (id: number, lineId: number) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;await&lt;/span&gt; axios.&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;delete&lt;/span&gt;(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;`invoice/&lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;${&lt;/span&gt;id&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;/detail/&lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;${&lt;/span&gt;lineId&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;`&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ol start=&#34;4&#34;&gt;
&lt;li&gt;We will use &lt;code&gt;invoiceService.ts&lt;/code&gt; to make API calls in our application. Normally, the API calls are usually made from Vue 3 components, but in this case we will use it to make API calls from our composable &lt;code&gt;useInvoiceStorage.ts&lt;/code&gt; where all the business logic related to invoice are handled. Below are the code changes done to integrate the API calls from &lt;code&gt;invoiceService.ts&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; // composables/useInvoiceStorage.ts
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; import { useStorage } from &amp;#39;@vueuse/core&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;-import { reactive } from &amp;#39;vue&amp;#39;;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+import { computed, ref } from &amp;#39;vue&amp;#39;;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt; import { Invoice, InvoiceStore } from &amp;#39;../types/index.type&amp;#39;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+import invoiceService from &amp;#39;../services/invoiceService&amp;#39;;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; const storage = useStorage&amp;lt;InvoiceStore&amp;gt;(&amp;#39;invoice-store&amp;#39;, {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;-    currentInvoiceNumber: 10000,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;-    invoices: {}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    currentInvoiceNumber: &amp;#34;10000&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt; }, localStorage);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+const state = ref({
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    ...storage.value,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    invoices: {},
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+});
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt; export default function useState() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;-    const state = reactive(storage);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     function saveInvoice(invoice: Invoice) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         state.value.invoices[invoice.number] = { ...invoice };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;-        state.value.currentInvoiceNumber = invoice.number + 1;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+        state.value.currentInvoiceNumber = `${+invoice.number + 1}`;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+        invoiceService.saveInvoice(invoice);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt;     }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;-    function updateInvoice(invoice: Invoice) {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    function updateInvoice(id: number, invoice: Invoice) {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt;         state.value.invoices[invoice.number] = { ...invoice };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+        invoiceService.updateInvoice(id, invoice);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt;     }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;-    function deleteInvoice(invoiceId: number) {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    async function deleteInvoice(invoiceId: number) {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt;         // delete state.value.invoices[invoiceId];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+        await invoiceService.deleteInvoice(invoiceId);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt;         state.value.invoices = Object.keys(state.value.invoices).filter(x =&amp;gt; x != invoiceId.toString()).reduce((acc, curr) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             return {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 ...acc,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666&#34;&gt;@@ -40,15 +45,33 @@ export default function useState() {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666&#34;&gt;&lt;/span&gt;         })
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             .map(x =&amp;gt; ({ ...state.value.invoices[x] }))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    async function fetchInvoices() {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+        const result = await invoiceService.getInvoices();
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+        state.value.invoices = result.data.reduce((acc, curr) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+            return { ...acc, [curr.id]: curr }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+        }, {})
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    async function fetchInvoice(id) {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+        const result = await invoiceService.getInvoice(id);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+        console.log(result);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+        state.value.invoices[result.data.id] = result.data;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+        console.log(state.value.invoices);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+        return result.data;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt;     }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     return {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         // variables
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         storage: state,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+        invoices: computed(() =&amp;gt; state.value.invoices),
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         // methods
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         saveInvoice,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         updateInvoice,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         deleteInvoice,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;-        findInvoices
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+        findInvoices,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+        fetchInvoices,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+        fetchInvoice
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt;     }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The above &lt;code&gt;fetchInvoices&lt;/code&gt; method is then used by &lt;code&gt;Invoices.vue&lt;/code&gt; to fetch the invoices. Similarly, all other endpoints are used in the application for CRUD operations.&lt;/p&gt;
&lt;p&gt;The source code for the Vue app is available &lt;a href=&#34;https://github.com/bimalghartimagar/invoice-generator&#34;&gt;on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;deployment&#34;&gt;Deployment&lt;/h3&gt;
&lt;p&gt;To deploy our API to Azure App Service, we can follow the documentation provided by Microsoft &lt;a href=&#34;https://learn.microsoft.com/en-us/aspnet/core/tutorials/publish-to-azure-api-management-using-vs?view=aspnetcore-9.0&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;In this blog post, we explored how to create a robust invoice generator API using .NET 9 and minimal APIs. We designed the API endpoints, implemented them using minimal APIs, and integrated the API with an existing Vue 3 application. This approach allowed us to leverage the power of minimal APIs while maintaining a clean and modular codebase.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Learning Vue 3 composables by creating an invoice generator</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2025/01/learning-vue-3-composables-by-creating-an-invoice-generator/"/>
      <id>https://www.endpointdev.com/blog/2025/01/learning-vue-3-composables-by-creating-an-invoice-generator/</id>
      <published>2025-01-06T00:00:00+00:00</published>
      <author>
        <name>Bimal Gharti Magar</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;img src=&#34;/blog/2025/01/learning-vue-3-composables-by-creating-an-invoice-generator/scaffolding.webp&#34; alt=&#34;Regularly spaced curved steel beams hold up a metal roof with windows. The back of the room is visible, and a wall lined with windows that have faint light peeking through.&#34;&gt;&lt;/p&gt;
&lt;!-- Photo by Seth Jensen, 2024. --&gt;
&lt;p&gt;The latest major version of Vue, Vue 3, has new features that are not present in Vue 2, such as Teleport, Suspense, and support for multiple root elements per template. Vue 3 provides smaller bundle sizes, better performance, better scalability, and better TypeScript IDE support.&lt;/p&gt;
&lt;h3 id=&#34;what-are-vue-3-composables&#34;&gt;What are Vue 3 composables?&lt;/h3&gt;
&lt;p&gt;Writing repetitive code can be a real pain in the frontend development realm. We can use Vue 3 &lt;a href=&#34;https://vuejs.org/guide/reusability/composables&#34;&gt;composables&lt;/a&gt; to encapsulate and reuse stateful logic in our components. In this blog post, we will look at how we can use composables to reuse business logic by building an invoice generator.&lt;/p&gt;
&lt;p&gt;An invoice generator, simply said, is an application that creates and manages invoices. We will focus on creating Vue 3 composables to properly separate business logic while reusing it across different features.&lt;/p&gt;
&lt;h3 id=&#34;core-functionalities-for-invoice-generator&#34;&gt;Core functionalities for invoice generator&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Adding, editing, and removing invoices and items&lt;/li&gt;
&lt;li&gt;Calculating totals with discounts, taxes, and shipping&lt;/li&gt;
&lt;li&gt;Generating PDF invoices&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To implement these functionalities, we&amp;rsquo;ll focus on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Creating composables to handle business logic&lt;/li&gt;
&lt;li&gt;Reusing this logic across features and components&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;prerequisites&#34;&gt;Prerequisites&lt;/h3&gt;
&lt;p&gt;Basic understanding of:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Vue 3 and Composition API&lt;/li&gt;
&lt;li&gt;JavaScript/​TypeScript fundamentals&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Tools:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Node.js and npm installed&lt;/li&gt;
&lt;li&gt;Vite&lt;/li&gt;
&lt;li&gt;Tailwind CSS (optional)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;setting-up-the-project&#34;&gt;Setting up the project&lt;/h3&gt;
&lt;p&gt;First, initialize the Vue 3 project:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ npm create vite@latest ep-invoice-generator
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Need to install the following packages:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;create-vite@6.0.1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Ok to proceed? (y) y
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;√ Select a framework: » Vue
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;√ Select a variant: » TypeScript
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Scaffolding project in G:\PersonalWork\blog\ep-invoice-generator...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Done. Now run:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  cd ep-invoice-generator
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  npm install
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  npm run dev&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Create folders for the project structure:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;src/components/&lt;/code&gt; for adding UI components&lt;/li&gt;
&lt;li&gt;&lt;code&gt;src/composables/&lt;/code&gt; for adding composables&lt;/li&gt;
&lt;li&gt;&lt;code&gt;src/router/&lt;/code&gt; for adding Vue Router routes&lt;/li&gt;
&lt;li&gt;&lt;code&gt;src/types/&lt;/code&gt; for adding type definitions&lt;/li&gt;
&lt;li&gt;&lt;code&gt;src/views/&lt;/code&gt; for adding pages to render based on Vue Router routes&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;create-first-composable-for-invoice-useinvoice&#34;&gt;Create first composable for invoice: &lt;code&gt;useInvoice&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The composable is named &lt;code&gt;useInvoice.ts&lt;/code&gt; and it will serve the following purposes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Handle data for invoice and invoice items&lt;/li&gt;
&lt;li&gt;Add methods for adding, editing, and removing invoice items&lt;/li&gt;
&lt;li&gt;Calculate totals automatically using item&amp;rsquo;s rate and amount as well as discount, tax, and shipping&lt;/li&gt;
&lt;li&gt;Reset invoice&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;define-interfaces-for-invoice-and-invoiceitem&#34;&gt;Define interfaces for &lt;code&gt;Invoice&lt;/code&gt; and &lt;code&gt;InvoiceItem&lt;/code&gt;&lt;/h4&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-typescript&#34; data-lang=&#34;typescript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;export&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;interface&lt;/span&gt; InvoiceItem {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    id: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;number&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    description: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    rate: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;number&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    quantity: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;number&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;export&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;interface&lt;/span&gt; Invoice {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    logo: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    name: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;number&lt;/span&gt;: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;number&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ponumber: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    date: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    duedate: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    sender: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    buyer: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    items: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;InvoiceItem&lt;/span&gt;[];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    notes: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    terms: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    discount: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        isUsed: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;boolean&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        isPercentage: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;boolean&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        value: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;number&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    tax: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        isUsed: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;boolean&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        isPercentage: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;boolean&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        value: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;number&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    shipping: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        isUsed: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;boolean&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        value: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;number&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    total: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;number&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    paid: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;number&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    sentToContact: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;boolean&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    status: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;Status&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;First we make an &lt;code&gt;Invoice&lt;/code&gt; object to create and edit an invoice. The code &lt;code&gt;state.storage.value.currentInvoiceNumber&lt;/code&gt; gets the current invoice number to use for the new invoice, we will learn more about it later.&lt;/p&gt;
&lt;p&gt;We return the object containing the required data and methods that can be used by any single-file component (SFC). We will see the implementation of computed properties and methods in the next section.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-typescript&#34; data-lang=&#34;typescript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;export&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;function&lt;/span&gt; useInvoice(invoiceId?: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;number&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; invoice = reactive&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;Invoice&lt;/span&gt;&amp;gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        logo: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        name: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;number&lt;/span&gt;: state.storage.value.currentInvoiceNumber,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ponumber: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        date: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;format&lt;/span&gt;(date, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;yyyy-MM-dd&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        duedate: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        sender: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        buyer: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        items: [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                id: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;1&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                description: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                rate: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                quantity: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        notes: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        terms: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        discount: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            isUsed: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;false&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            isPercentage: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;false&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            value: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        tax: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            isUsed: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;false&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            isPercentage: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;false&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            value: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        shipping: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            isUsed: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;false&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            value: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        total: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        paid: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        sentToContact: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;false&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        status: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;Status.Draft&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; subtotal = computed(() =&amp;gt; ...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; afterDiscount = computed(() =&amp;gt; ...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; afterTax = computed(() =&amp;gt; ...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; afterShipping = computed(() =&amp;gt; ...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; total = computed(() =&amp;gt; ...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; balance = computed(() =&amp;gt; ...);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; updateLineItem = (value: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;InvoiceItem&lt;/span&gt;, index: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;number&lt;/span&gt;) =&amp;gt; ...);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; addLineItem = () =&amp;gt; ...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; removeLineItem = (index) =&amp;gt; ...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#888&#34;&gt;// data helpers
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;        invoice,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        subtotal,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        afterDiscount,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        afterTax,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        afterShipping,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        total,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        balance,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#888&#34;&gt;// Methods
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;        addLineItem,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        updateLineItem,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        removeLineItem,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;adding-business-logic&#34;&gt;Adding business logic&lt;/h3&gt;
&lt;p&gt;Now we implement the business logic for various methods — adding an invoice item, updating an invoice item, etc. — as well as calculating the various dynamic amounts.&lt;/p&gt;
&lt;p&gt;The following methods add an invoice item to the invoice as a line item, which can be rendered on the UI. Then, the user can update the line item&amp;rsquo;s rate and quantity, which calls &lt;code&gt;updateLineItem&lt;/code&gt; to update the invoice item data.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-typescript&#34; data-lang=&#34;typescript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt; * Add a line item to the invoice line items array
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; addLineItem = () =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    invoice.items.push({
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        id: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;invoice.items.length&lt;/span&gt; + &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        description: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        rate: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        quantity: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt; * @param {invoice line item} value
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt; * @param {index of invoice line item} index
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt; * @returns
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; updateLineItem = (value: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;InvoiceItem&lt;/span&gt;, index: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;number&lt;/span&gt;) =&amp;gt; (invoice.items[index] = { ...value });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt; * Remove items from invoice items array
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt; * @param {*} index index of item to remove
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; removeLineItem = (index) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    invoice.items.splice(index, &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Based on the invoice item data, we then calculate:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;subtotal&lt;/li&gt;
&lt;li&gt;subtotal after discount, if available&lt;/li&gt;
&lt;li&gt;subtotal after tax, if available&lt;/li&gt;
&lt;li&gt;subtotal after shipping, if available&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Moreover, discount and tax can be stored as an amount or as a percentage value, so we update the logic to evaluate discount and tax based on the type of the entered values and calculate the subtotal. We can also include a previously overpaid amount and calculate the balance at the end of the calculations.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-typescript&#34; data-lang=&#34;typescript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// useInvoice.ts
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; subtotal = computed(() =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    invoice.items.reduce((prev, acc) =&amp;gt; prev + acc.rate * acc.quantity, &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt; * Compute total value after applying discount
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt; * based on `discount` percentage or value and `subtotal` value
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; afterDiscount = computed(() =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; (invoice.discount.isUsed) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; (invoice.discount.isPercentage) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; subtotal.value - (subtotal.value * invoice.discount.value) / &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;100&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        } &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; subtotal.value - invoice.discount.value;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; subtotal.value;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt; * Compute total value after applying tax
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt; * based on `tax` percentage or value and `afterDiscount` value
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; afterTax = computed(() =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; (invoice.tax.isUsed) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; (invoice.tax.isPercentage) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                afterDiscount.value + (afterDiscount.value * invoice.tax.value) / &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;100&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            );
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        } &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; afterDiscount.value + invoice.tax.value;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; afterDiscount.value;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt; * Compute total value after applying shipping
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt; * based on `shipping` value and `afterTax` value
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; afterShipping = computed(() =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; (invoice.shipping.isUsed) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; afterTax.value + invoice.shipping.value;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; afterTax.value;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; total = computed(() =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; afterShipping.value;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// later if we track the payment done for the clients, we can easily
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// come up with the balance based on the payment and invoices
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; balance = computed(() =&amp;gt; total.value - invoice.paid);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;rendering-the-invoice-with-composable-functions&#34;&gt;Rendering the invoice with composable functions&lt;/h3&gt;
&lt;p&gt;We create the &lt;code&gt;InvoiceGenerator.vue&lt;/code&gt; SFC, utilizing the &lt;code&gt;useInvoice&lt;/code&gt; composable we created. We use the &lt;code&gt;&amp;lt;script setup&amp;gt;&lt;/code&gt; syntax for importing and using the composable. &lt;code&gt;&amp;lt;script setup&amp;gt;&lt;/code&gt; help us use &lt;a href=&#34;https://vuejs.org/guide/extras/composition-api-faq.html&#34;&gt;Composition API&lt;/a&gt; inside SFCs instead of the Options API. Using the &lt;code&gt;&amp;lt;script setup&amp;gt;&lt;/code&gt; syntax removes boilerplate code while providing the ability to declare props, emitted events, and &lt;a href=&#34;https://vuejs.org/api/sfc-script-setup#script-setup&#34;&gt;many more advantages&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&amp;lt;!-- InvoiceGenerator.vue--&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;setup&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;import&lt;/span&gt; { useInvoice } from &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;../composables/useInvoice&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;// data
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;  invoice,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;// computed / read only
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;  subtotal,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  total,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  balance,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;// methods
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;  addLineItem,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  updateLineItem,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  removeLineItem,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  resetInvoice
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} = useInvoice(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I have already defined the &lt;code&gt;LineItems.vue&lt;/code&gt; component, where we render the line items which have text boxes to enter description, rate, and amount. The totals for each item are calculated using the computed property. Let&amp;rsquo;s see an example showing how we can use it with invoice items:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;items&lt;/code&gt; prop to render the invoice items&lt;/li&gt;
&lt;li&gt;Emit &lt;code&gt;update-item&lt;/code&gt; event when any value for an invoice line item changes&lt;/li&gt;
&lt;li&gt;Emit &lt;code&gt;add-item&lt;/code&gt; when user adds a new line item&lt;/li&gt;
&lt;li&gt;Emit &lt;code&gt;close&lt;/code&gt; when user removes a line item&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;LineItems&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#369&#34;&gt;:items&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;invoice.items&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;@&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;update-item&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;updateLineItem&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;@&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;close&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;removeLineItem&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;@&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;add-item&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;addLineItem&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    /&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Similarly, we use &lt;code&gt;invoice.discount&lt;/code&gt;, &lt;code&gt;invoice.tax&lt;/code&gt;, and &lt;code&gt;invoice.shipping&lt;/code&gt; properties from the composable in a text box where the user can enter the value and type of the value. All of them have helper properties named &lt;code&gt;isUsed&lt;/code&gt; and &lt;code&gt;isPercentage&lt;/code&gt;, which we use to make the input box user-friendly. The &lt;code&gt;CustomInput&lt;/code&gt;, &lt;code&gt;CustomToggleSwitch&lt;/code&gt; and &lt;code&gt;WithLabel&lt;/code&gt; are three custom components that are already created and they can be used as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;WithLabel&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;label&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Discount&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;CustomInput&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#369&#34;&gt;v-model&lt;/span&gt;&lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;number&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;invoice.discount.value&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#369&#34;&gt;is-used&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#369&#34;&gt;label&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Discount&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#369&#34;&gt;toggle&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#369&#34;&gt;:currency&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;!invoice.discount.isPercentage&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;@&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;close&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;invoice.discount.isUsed = false&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;CustomToggleSwitch&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#369&#34;&gt;v-model&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;invoice.discount.isPercentage&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#369&#34;&gt;:for-value&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&amp;#39;invoice-discount&amp;#39;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        /&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;CustomInput&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;WithLabel&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;WithLabel&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;label&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Tax&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;CustomInput&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#369&#34;&gt;v-model&lt;/span&gt;&lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;number&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;invoice.tax.value&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#369&#34;&gt;is-used&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#369&#34;&gt;label&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Tax&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#369&#34;&gt;toggle&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#369&#34;&gt;:currency&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;!invoice.tax.isPercentage&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;@&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;close&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;invoice.tax.isUsed = false&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;CustomToggleSwitch&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#369&#34;&gt;v-model&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;invoice.tax.isPercentage&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#369&#34;&gt;:for-value&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&amp;#39;invoice-tax&amp;#39;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        /&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;CustomInput&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;WithLabel&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;WithLabel&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;label&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Shipping&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;CustomInput&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#369&#34;&gt;v-model&lt;/span&gt;&lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;number&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;invoice.shipping.value&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#369&#34;&gt;label&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Shipping&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#369&#34;&gt;is-used&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#369&#34;&gt;currency&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;@&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;close&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;invoice.shipping.isUsed = false&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;CustomInput&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;WithLabel&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;All other properties can also be rendered, but we would like some input fields, like PO Number, Invoice Date, and Amount Paid to be rendered differently. Using custom components like &lt;code&gt;CustomInput&lt;/code&gt; and &lt;code&gt;CustomToggleSwitch&lt;/code&gt; can help us get more control of the visual and functional aspects of the UI component.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;WithLabel&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;label&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;PO Number&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;CustomInput&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#369&#34;&gt;v-model&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;invoice.ponumber&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#369&#34;&gt;label&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;PO Number&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#369&#34;&gt;type&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;text&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    /&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;WithLabel&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;WithLabel&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;label&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Date&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;CustomInput&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#369&#34;&gt;v-model&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;invoice.date&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#369&#34;&gt;label&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Date&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#369&#34;&gt;type&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;date&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    /&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;WithLabel&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;WithLabel&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;label&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Amount Paid&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;CustomInput&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#369&#34;&gt;v-model&lt;/span&gt;&lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;number&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;invoice.paid&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#369&#34;&gt;label&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Amount Paid&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#369&#34;&gt;currency&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    /&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;WithLabel&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;create-a-second-composable-for-using-localstorage-to-save-and-retrieve-invoice-data&#34;&gt;Create a second composable for using localStorage to save and retrieve invoice data&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;useInvoice&lt;/code&gt; composable only gives us the invoice data along with computed properties, but now we have to save it somewhere so we can use it later. We can use &lt;code&gt;localStorage&lt;/code&gt; to save the invoices. &lt;a href=&#34;https://vueuse.org/&#34;&gt;VueUse&lt;/a&gt; is a very good library that has a &lt;a href=&#34;https://vueuse.org/functions.html&#34;&gt;collection&lt;/a&gt; of Vue composition utilities that can be used with Vue 2 as well as Vue 3.&lt;/p&gt;
&lt;p&gt;For accessing localStorage reactively, we will use a composable from VueUse called &lt;code&gt;useStorage&lt;/code&gt;, which uses localStorage by default. We will define &lt;code&gt;saveInvoice&lt;/code&gt;, &lt;code&gt;updateInvoice&lt;/code&gt;, &lt;code&gt;deleteInvoice&lt;/code&gt;, and &lt;code&gt;findInvoices&lt;/code&gt; methods that use the reactive variable from &lt;code&gt;useStorage&lt;/code&gt; to perform the required operations.&lt;/p&gt;
&lt;p&gt;We will create another composable called &lt;code&gt;useInvoiceStorage.ts&lt;/code&gt;, where we initialize our storage using &lt;code&gt;useStorage&lt;/code&gt;, which also stores the current invoice number.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-typescript&#34; data-lang=&#34;typescript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// useInvoiceStorage.ts
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; storage = useStorage&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;InvoiceStore&lt;/span&gt;&amp;gt;(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;invoice-store&amp;#39;&lt;/span&gt;, {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    currentInvoiceNumber: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;10000&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    invoices: {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}, localStorage);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then we define and implement the methods discussed above for saving, updating, deleting, and finding invoices. The update of the current invoice number happens in the &lt;code&gt;saveInvoice&lt;/code&gt; method.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-typescript&#34; data-lang=&#34;typescript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// useInvoiceStorage.ts
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;export&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;default&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;function&lt;/span&gt; useState() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; state = reactive(storage);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;function&lt;/span&gt; saveInvoice(invoice: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;Invoice&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        state.value.invoices[invoice.&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;number&lt;/span&gt;] = { ...invoice };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        state.value.currentInvoiceNumber = invoice.&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;number&lt;/span&gt; + &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;function&lt;/span&gt; updateInvoice(invoice: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;Invoice&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        state.value.invoices[invoice.&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;number&lt;/span&gt;] = { ...invoice };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;function&lt;/span&gt; deleteInvoice(invoiceId: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;number&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        state.value.invoices = &lt;span style=&#34;color:#038&#34;&gt;Object&lt;/span&gt;.keys(state.value.invoices)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .filter(x =&amp;gt; x != invoiceId.toString())
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .reduce((acc, curr) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    ...acc,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    [curr]: state.value.invoices[curr]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }, {})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;function&lt;/span&gt; findInvoices(searchText: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        searchText = searchText.toLowerCase();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#038&#34;&gt;Object&lt;/span&gt;.keys(state.value.invoices).filter(x =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; invoice = state.value.invoices[x];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; invoice.&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;number&lt;/span&gt;.toString().indexOf(searchText) &amp;gt; -&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                || invoice.buyer.toString().toLowerCase().indexOf(searchText) &amp;gt; - &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                || invoice.date.toString().toLowerCase().indexOf(searchText) &amp;gt; - &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                || invoice.total.toString().indexOf(searchText) &amp;gt; - &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        })
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .map(x =&amp;gt; ({ ...state.value.invoices[x] }))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#888&#34;&gt;// variables
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;        storage: &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;state&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#888&#34;&gt;// methods
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;        saveInvoice,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        updateInvoice,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        deleteInvoice,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        findInvoices
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, we can use data and methods from the &lt;code&gt;useInvoiceStorage&lt;/code&gt; composable to show the latest invoice number as well as save, update, delete, and find invoices. The composable &lt;code&gt;useInvoice&lt;/code&gt; also uses &lt;code&gt;useInvoiceStorage&lt;/code&gt; to set the current invoice number for the new invoice. Whenever a user creates a new invoice, the current invoice number is automatically assigned to the invoice obtained from the &lt;code&gt;useInvoiceStorage&lt;/code&gt; composable.&lt;/p&gt;
&lt;p&gt;Moreover, the &lt;code&gt;useInvoice&lt;/code&gt; composable is updated to support the new invoice and edit invoice features. Support for editing an invoice is achieved by passing &lt;code&gt;invoiceId&lt;/code&gt; to the &lt;code&gt;useInvoice&lt;/code&gt; composable, the &lt;code&gt;invoiceId&lt;/code&gt; is then checked in the storage returned by &lt;code&gt;useInvoiceStorage&lt;/code&gt;, if the invoice exists, the &lt;code&gt;useInvoice&lt;/code&gt; composable returns the correct invoice data from storage.&lt;/p&gt;
&lt;p&gt;The following code checks for the invoice in the storage:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-typescript&#34; data-lang=&#34;typescript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// If the invoice is already in storage, use it
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; (invoiceId) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; invoiceToUse = state.storage.value.invoices[invoiceId];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; (invoiceToUse) &lt;span style=&#34;color:#038&#34;&gt;Object&lt;/span&gt;.assign(invoice, invoiceToUse);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;printing-invoice&#34;&gt;Printing Invoice&lt;/h3&gt;
&lt;p&gt;For printing invoices, we can simply use &lt;a href=&#34;https://tailwindcss.com/docs/hover-focus-and-other-states#print-styles&#34;&gt;print styles&lt;/a&gt; from Tailwind CSS to style the elements that we want to print. A simple example is the &lt;code&gt;CustomButton&lt;/code&gt; component in the source code. We don&amp;rsquo;t want to show any buttons on the PDF, so we use the Tailwind CSS style &lt;code&gt;print:hidden&lt;/code&gt; to hide the buttons on the print view. We then need to call the method below on the invoice page to print the current page.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-typescript&#34; data-lang=&#34;typescript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; print = () =&amp;gt; &lt;span style=&#34;color:#038&#34;&gt;window&lt;/span&gt;.print();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;bonus-create-a-third-composable-for-showing-dashboard-data&#34;&gt;Bonus: create a third composable for showing dashboard data&lt;/h3&gt;
&lt;p&gt;The dashboard is important for looking at the high-level data and is crucial to any application. So, we add a new composable called &lt;code&gt;useDashboardData.ts&lt;/code&gt; that will give us the total invoice amount, total paid amount, total due amount, and total drafted amount. It can be further expanded to include any other business logic as well. We will again use the &lt;code&gt;useInvoiceStorage&lt;/code&gt; composable to get the list of invoices.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-typescript&#34; data-lang=&#34;typescript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// useDashboardData.ts
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;import&lt;/span&gt; useState &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;./useInvoiceStorage&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;import&lt;/span&gt; { Status } &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;../types/index.type&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;export&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;function&lt;/span&gt; useDashboardData() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; state = useState();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; totalInvoiceAmount = computed(() =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; invoices = state.storage.value.invoices;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; amount = &lt;span style=&#34;color:#038&#34;&gt;Object&lt;/span&gt;.keys(invoices).reduce((acc, item) =&amp;gt; acc + invoices[item].total, &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; amount.toFixed(&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;2&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    })
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; totalPaid = computed(() =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; invoices = state.storage.value.invoices;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; amount = &lt;span style=&#34;color:#038&#34;&gt;Object&lt;/span&gt;.keys(invoices).reduce((acc, item) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; (invoices[item].status === Status.Paid) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; acc + invoices[item].total
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; acc;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }, &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; amount.toFixed(&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;2&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    })
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; totalDue = computed(() =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; invoices = state.storage.value.invoices;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; amount = &lt;span style=&#34;color:#038&#34;&gt;Object&lt;/span&gt;.keys(invoices).reduce((acc, item) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; (invoices[item].status === Status.Overdue) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; acc + invoices[item].total
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; acc;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }, &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; amount.toFixed(&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;2&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    })
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; totalDrafted = computed(() =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; invoices = state.storage.value.invoices;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; amount = &lt;span style=&#34;color:#038&#34;&gt;Object&lt;/span&gt;.keys(invoices).reduce((acc, item) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; (invoices[item].status === Status.Draft) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; acc + invoices[item].total
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; acc;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }, &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; amount.toFixed(&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;2&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    })
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#888&#34;&gt;// variables
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;        totalInvoiceAmount,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        totalPaid,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        totalDue,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        totalDrafted
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;After that we create the &lt;code&gt;Dashboard.vue&lt;/code&gt; component to use data from &lt;code&gt;useDashboardData.ts&lt;/code&gt; and display the data on the dashboard. We can keep adding business logic to &lt;code&gt;useDashboardData.ts&lt;/code&gt; to display data on the dashboard, and we can use it elsewhere to support other business logic.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&amp;lt;!-- Dashboard.vue --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;template&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;section&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;max-w-[1800px] mx-auto&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;grid grid-cols-4 gap-x-4 mt-4&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;Card&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;template&lt;/span&gt; &lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;#&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;header&lt;/span&gt;&amp;gt;Total Amount&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;template&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;span&lt;/span&gt;&amp;gt;${{ totalInvoiceAmount }}&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;span&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;template&lt;/span&gt; &lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;#&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;footer&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;template&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;Card&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;Card&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;template&lt;/span&gt; &lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;#&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;header&lt;/span&gt;&amp;gt;Paid Amount&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;template&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;span&lt;/span&gt;&amp;gt;${{ totalPaid }}&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;span&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;template&lt;/span&gt; &lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;#&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;footer&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;template&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;Card&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;Card&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;template&lt;/span&gt; &lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;#&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;header&lt;/span&gt;&amp;gt;Due Amount&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;template&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;span&lt;/span&gt;&amp;gt;${{ totalDue }}&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;span&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;template&lt;/span&gt; &lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;#&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;footer&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;template&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;Card&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;Card&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;template&lt;/span&gt; &lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;#&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;header&lt;/span&gt;&amp;gt;Drafted Amount&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;template&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;span&lt;/span&gt;&amp;gt;${{ totalDrafted }}&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;span&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;template&lt;/span&gt; &lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;#&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;footer&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;template&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;Card&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;Invoices&lt;/span&gt; /&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;section&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;template&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;setup&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;lang&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;ts&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;import&lt;/span&gt; Card from &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;../components/shared/Card.vue&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;import&lt;/span&gt; { useDashboardData } from &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;../composables/useDashboardData&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;import&lt;/span&gt; Invoices from &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;./Invoices.vue&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; { totalInvoiceAmount, totalPaid, totalDue, totalDrafted } = useDashboardData();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The source code is available at &lt;a href=&#34;https://github.com/bimalghartimagar/invoice-generator&#34;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;An application &lt;a href=&#34;https://invoice-generator-iota.vercel.app/&#34;&gt;demo&lt;/a&gt; is also available.&lt;/p&gt;
&lt;h3 id=&#34;next-steps&#34;&gt;Next Steps&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Use a REST API for saving the invoices to the database&lt;/li&gt;
&lt;li&gt;Use &lt;a href=&#34;https://pinia.vuejs.org/&#34;&gt;Pinia&lt;/a&gt; to store the retrieved invoices so we can easily use the invoices&lt;/li&gt;
&lt;li&gt;Add a composable to switch between different types of templates for printing PDFs&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;We learned about Vue 3 composables and how to use Composition API to create composables. We saw how composable functions are a game changer for building complex, maintainable, and scalable applications by encapsulating the business logic, organizing the code, and making it reusable. It helps to simplify the process and boost productivity.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Passing Data Between Components in Vue.js: An Overview</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2024/04/passing-data-between-components-vue/"/>
      <id>https://www.endpointdev.com/blog/2024/04/passing-data-between-components-vue/</id>
      <published>2024-04-03T00:00:00+00:00</published>
      <author>
        <name>Tuğrul Gökbel</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;img src=&#34;/blog/2024/04/passing-data-between-components-vue/still_life_with_artichokes_and_a_parrot_1998.23.2.webp&#34; alt=&#34;A still life painting. One the left side of the image, a parrot stays perched on a table; to the right the table is covered in artichokes, cherries, and light blue, red, and white flowers. The scene is lit from the top left with a gentle diagonal of light, contrasted with deep shadow.&#34;&gt;&lt;br&gt;
&lt;a href=&#34;https://www.nga.gov/collection/art-object-page.102987.html&#34;&gt;Artwork&lt;/a&gt;: Still Life with Artichokes and a Parrot, 17th century, Italian. CC0.&lt;/p&gt;
&lt;p&gt;Vue.js, with its simplicity and flexibility, is one of the most popular JavaScript frameworks on the web. One of the key aspects of building dynamic and interactive web applications with Vue is efficiently passing data between components. In this blog post, we will explore methods and good practices for data communication between Vue components.&lt;/p&gt;
&lt;h3 id=&#34;props&#34;&gt;Props&lt;/h3&gt;
&lt;h4 id=&#34;usage&#34;&gt;Usage&lt;/h4&gt;
&lt;p&gt;Directional data flow: Props are primarily used for establishing a unidirectional flow of data from parent components to child components — they allow parents to pass data down to their children.&lt;/p&gt;
&lt;h4 id=&#34;pros&#34;&gt;Pros:&lt;/h4&gt;
&lt;p&gt;Simplicity: Props provide a simple and straightforward mechanism for passing data.&lt;/p&gt;
&lt;h4 id=&#34;cons&#34;&gt;Cons:&lt;/h4&gt;
&lt;p&gt;One-Way Binding: It&amp;rsquo;s a one-way data binding mechanism, meaning that data flows from parent to child only, not from child to parent.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;// ParentComponent.vue
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;template&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;ChildComponent&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;:data-prop&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;parentData&amp;#34;&lt;/span&gt; /&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;template&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;export&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;default&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  data() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      parentData: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Hello from parent!&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;// ChildComponent.vue
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;template&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt;&amp;gt;{{ dataProp }}&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;template&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;export&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;default&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  props: [&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;dataProp&amp;#39;&lt;/span&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;custom-events-emitting-changes-from-child-to-parent&#34;&gt;Custom Events: Emitting Changes from Child to Parent&lt;/h3&gt;
&lt;h4 id=&#34;usage-1&#34;&gt;Usage:&lt;/h4&gt;
&lt;p&gt;Child to Parent Communication: Custom events are useful when a child component needs to communicate changes or send data back to its parent component.&lt;/p&gt;
&lt;h4 id=&#34;pros-1&#34;&gt;Pros:&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Bidirectional Communication: Enables two-way communication between parent and child components.&lt;/li&gt;
&lt;li&gt;Flexibility: Allows children to notify parents about specific events or changes.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;cons-1&#34;&gt;Cons:&lt;/h4&gt;
&lt;p&gt;Limited Scope: Best suited for parent-child relationships; might become cumbersome in complex component hierarchies.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;// ChildComponent.vue
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;template&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;button&lt;/span&gt; &lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;@&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;click&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;emitData&amp;#34;&lt;/span&gt;&amp;gt;Send Data to Parent&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;button&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;template&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;export&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;default&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  methods: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    emitData() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;this&lt;/span&gt;.$emit(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;child-event&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;Data from child!&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;// ParentComponent.vue
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;template&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;ChildComponent&lt;/span&gt; &lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;@&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;child-event&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;handleChildEvent&amp;#34;&lt;/span&gt; /&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;template&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;export&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;default&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  methods: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    handleChildEvent(data) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      console.log(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;Received data from child:&amp;#39;&lt;/span&gt;, data);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;eventbus-a-centralized-event-hub&#34;&gt;EventBus: A Centralized Event Hub&lt;/h3&gt;
&lt;h4 id=&#34;usage-2&#34;&gt;Usage:&lt;/h4&gt;
&lt;p&gt;Non-Parent-Child Communication: EventBus provides a centralized event hub that allows components not directly related in a parent-child hierarchy to communicate.&lt;/p&gt;
&lt;h4 id=&#34;pros-2&#34;&gt;Pros:&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Flexibility and Decoupling: Components can emit and listen for events without tight coupling, enhancing flexibility.&lt;/li&gt;
&lt;li&gt;Global Communication: Suitable for scenarios where communication needs to happen across various components.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;cons-2&#34;&gt;Cons:&lt;/h4&gt;
&lt;p&gt;Global Scope: Might lead to unintended side effects if events are not managed carefully.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// EventBus.js
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;import&lt;/span&gt; Vue from &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;vue&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;export&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; bus = &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;new&lt;/span&gt; Vue();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;// ChildComponent.vue
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;template&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;button&lt;/span&gt; &lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;@&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;click&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;emitData&amp;#34;&lt;/span&gt;&amp;gt;Send Data to Anywhere!&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;button&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;template&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;import&lt;/span&gt; { bus } from &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;../EventBus&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;export&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;default&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  methods: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    emitData() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      bus.$emit(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;customEvent&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;Data from child!&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;// AnyComponent.vue
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;template&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt;&amp;gt;{{ receivedData }}&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;template&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;import&lt;/span&gt; { bus } from &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;../EventBus&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;export&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;default&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  data() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      receivedData: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  created() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    bus.$on(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;customEvent&amp;#39;&lt;/span&gt;, (data) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;this&lt;/span&gt;.receivedData = data;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;vuex-state-management-for-larger-applications&#34;&gt;Vuex: State Management for Larger Applications&lt;/h3&gt;
&lt;p&gt;For more complex applications, especially those with multiple components sharing state, Vuex is the recommended solution. Vuex is Vue&amp;rsquo;s official state management library, providing a centralized store for managing application-level state.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// store.js
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;import&lt;/span&gt; Vue from &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;vue&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;import&lt;/span&gt; Vuex from &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;vuex&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Vue.use(Vuex);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;export&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;default&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;new&lt;/span&gt; Vuex.Store({
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  state: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    sharedData: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;Shared state data!&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  mutations: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    updateData(state, newData) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      state.sharedData = newData;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;// AnyComponent.vue
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;template&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt;&amp;gt;{{ sharedData }}&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;template&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;import&lt;/span&gt; { mapState } from &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;vuex&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;export&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;default&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  computed: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ...mapState([&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;sharedData&amp;#39;&lt;/span&gt;]),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;While Vuex is a powerful state management solution, it&amp;rsquo;s not always necessary for every Vue.js application. Here are some scenarios where you should consider using Vuex:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Large and Complex Applications: Vuex becomes more valuable as your Vue.js application grows in size and complexity. If your application has numerous components that need to share and synchronize state, managing the state centrally with Vuex can greatly simplify the development process.&lt;/li&gt;
&lt;li&gt;Shared State Between Components: When multiple components need access to the same state data, prop drilling (passing data through multiple layers of components) can become unwieldy. Vuex provides a centralized store, eliminating the need for complex and deep prop chains.&lt;/li&gt;
&lt;li&gt;Predictable State Management: If you require a clear and predictable pattern for managing state changes, mutations in Vuex provide a straightforward and traceable way to update the state. This is especially beneficial in applications where understanding and debugging state changes are crucial.&lt;/li&gt;
&lt;li&gt;Asynchronous Operations: If your application involves asynchronous operations, such as fetching data from an API or handling complex workflows, Vuex actions provide a structured way to handle these operations and update the state accordingly.&lt;/li&gt;
&lt;li&gt;Reusable and Composable Code: If you want to create modular and reusable code, Vuex allows you to define actions, mutations, and getters in a centralized store. This makes it easier to maintain and extend your application as new features are added.&lt;/li&gt;
&lt;li&gt;Consistent State Across Components: In scenarios where maintaining consistent state across multiple components is crucial, using Vuex ensures that modifications to the state are handled in a controlled and synchronized manner.&lt;/li&gt;
&lt;li&gt;Testing Requirements: If your application requires extensive unit testing for state-related logic, Vuex provides a structured architecture that makes it easier to test mutations, actions, and getters in isolation.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By understanding and utilizing props, custom events, EventBus, and Vuex, you can effectively manage and communicate data in your Vue.js applications. Choose the approach that best fits your project&amp;rsquo;s requirements, keeping in mind the scalability and maintainability of your code.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Key Takeaways from Practical Object-Oriented Design by Sandi Metz</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2024/02/key-takeaways-from-poodr/"/>
      <id>https://www.endpointdev.com/blog/2024/02/key-takeaways-from-poodr/</id>
      <published>2024-02-27T00:00:00+00:00</published>
      <author>
        <name>Kevin Campusano</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;img src=&#34;/blog/2024/02/key-takeaways-from-poodr/well-trimmed-trees.webp&#34; alt=&#34;View upward at a bright sky, with lines drawn down at an angle toward the left center by a tree trimmed into a rectangular prism and one trimmed into a vague cone. The lens is imperfect, leaving the corner of the square tree in focus while the rest of the green foliage and blue and bright white sky is somewhat distorted by the lens.&#34;&gt;&lt;/p&gt;
&lt;!-- Photo by Seth Jensen, 2022 --&gt;
&lt;p&gt;&lt;a href=&#34;https://www.poodr.com/&#34;&gt;Practical Object-Oriented Design: An Agile Primer Using Ruby&lt;/a&gt; by &lt;a href=&#34;https://sandimetz.com/&#34;&gt;Sandi Metz&lt;/a&gt; is one of those books that everybody who writes or aspires to write object-oriented code should read. Indeed, reading through this book will be valuable for seasoned practitioners and inexperienced novices alike. Whether it be to discover new concepts, remember why they are important, or articulate the reasons behind that warm fuzzy feeling you get in your stomach when you read well designed code, POODR can help.&lt;/p&gt;
&lt;p&gt;I personally really like this book, and here at End Point it does have quite a following as well; it was the subject of a &lt;a href=&#34;/blog/2016/08/ruby-fight-club/&#34;&gt;study group that we ran back in 2016&lt;/a&gt;. I like to dust it off every now and then to give it a re-read. To help with that, I&amp;rsquo;ve come up with a list of key takeaways from the book, with some of my own interpretations sprinkled in. For me, it serves as a sort of summary to help commit the book&amp;rsquo;s contents to memory. I thought I&amp;rsquo;d share it with you today.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;While this book uses the Ruby language for its examples and discussions, the concepts it describes are equally applicable to any classical object-oriented language. Dynamically typed language users do get a little more mileage than users of statically typed ones. But still, something like 90% of the content is relevant to both. For this summary, I&amp;rsquo;ve taken care not to tie the discussion to Ruby too much and be as language agnostic as possible. I&amp;rsquo;ve chosen to write the code examples in C#.&lt;/p&gt;&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Images taken from the book. Code taken from the book&amp;rsquo;s examples in Ruby and translated to C#.&lt;/p&gt;&lt;/blockquote&gt;
&lt;h3 id=&#34;chapter-1-object-oriented-design&#34;&gt;Chapter 1: Object-Oriented Design&lt;/h3&gt;
&lt;h4 id=&#34;about-design&#34;&gt;About design&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;Following the principles and patterns of object-oriented design produces code that is both cost-effective and a joy to work with. &amp;ldquo;Cost effective&amp;rdquo; means that it doesn&amp;rsquo;t take more effort than necessary to evolve, to change.&lt;/li&gt;
&lt;li&gt;The reason design is important is because software changes. A good design is one that makes software easy to change.&lt;/li&gt;
&lt;li&gt;Object-oriented design sees the world as a collection of parts that interact with each other. The parts we call &amp;ldquo;objects&amp;rdquo;, and the interactions we call &amp;ldquo;messages&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;In order to send messages to each other, objects need to have some knowledge about one another. This knowledge produces &amp;ldquo;dependencies&amp;rdquo; between them.&lt;/li&gt;
&lt;li&gt;Managing these dependencies is a big part of object-oriented design. OOD aims to create dependencies in such a way that they don&amp;rsquo;t make the process of changing objects too difficult.&lt;/li&gt;
&lt;li&gt;Design is important no matter the size of the application. Because both small and large applications change. And change is what design allows. A badly designed small application will eventually become a badly designed large one.&lt;/li&gt;
&lt;li&gt;Design is the way in which code is arranged. Good design is an arrangement of code that makes change easy.&lt;/li&gt;
&lt;li&gt;Our job as developers is to take our application&amp;rsquo;s requirements and our knowledge of design principles and use them to produce code that is cost effective today and tomorrow: code that is easy to change.&lt;/li&gt;
&lt;li&gt;The idea is not to predict future changes. Instead, we have to accept that change will come and prepare for it. We prepare for it by writing code that leaves our options open for the future.&lt;/li&gt;
&lt;li&gt;&amp;ldquo;The purpose of design is to allow you to design later, and its primary goal is to reduce the cost of change.&amp;rdquo;&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&#34;failures-of-design&#34;&gt;Failures of design&lt;/h4&gt;
&lt;ol start=&#34;11&#34;&gt;
&lt;li&gt;&lt;strong&gt;Design fails when you don&amp;rsquo;t do it.&lt;/strong&gt; Code bases that lack in design will eventually evolve into unmaintainable messes, where change becomes increasingly hard even for the most minor new requirements. &amp;ldquo;Throwing everything away and beginning from scratch&amp;rdquo; becomes a viable alternative.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Design fails when you overdesign.&lt;/strong&gt; Armed with basic design skills, it&amp;rsquo;s easy to fall into the trap of developing wrong abstractions, applying principles incorrectly, seeing the wrong pattern in the wrong context. Applications that suffer from overdesign become gigantic castles of code full of indirection that become hard to change.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Design fails when you separate it from programming.&lt;/strong&gt; Design is best executed as an iterative and incremental process with a quick feedback loop. The design needs to be adjusted frequently, as understanding of the domain changes. Design that is dictated to programmers from on high as part of a &amp;ldquo;&lt;a href=&#34;https://en.wikipedia.org/wiki/Big_design_up_front&#34;&gt;Big Up Front Design&lt;/a&gt;&amp;rdquo; is doomed to failure. Such arrangements are not agile enough to be resilient to requirement changes.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&#34;agile-and-design&#34;&gt;Agile and design&lt;/h4&gt;
&lt;ol start=&#34;14&#34;&gt;
&lt;li&gt;Agile development says: &amp;ldquo;Avoid Big Up Front Design because you can&amp;rsquo;t know what the application will end up being because requirements always change and they do so often.&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Agile also says: &amp;ldquo;Good design is essential. Because change comes often, your code needs to be ready to accommodate those changes in an efficient and cost effective way.&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Design is not a &amp;ldquo;one time at the beginning of the project&amp;rdquo; type of task. It is an ongoing, iterative and incremental task that happens as requirements change, and as our domain knowledge and skills increase.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&#34;metrics&#34;&gt;Metrics&lt;/h4&gt;
&lt;ol start=&#34;17&#34;&gt;
&lt;li&gt;Bad object-oriented design metrics are an indicator of a bad design. But good metrics are not an indicator of good design. A code base with bad metrics will most likely be hard to change.&lt;/li&gt;
&lt;li&gt;The ideal software metric would be &amp;ldquo;&lt;strong&gt;cost per feature per time interval&lt;/strong&gt;&amp;rdquo;. But this is nigh on impossible to calculate because &amp;ldquo;cost&amp;rdquo;, &amp;ldquo;feature&amp;rdquo;, and &amp;ldquo;time interval&amp;rdquo; are in most cases nebulous concepts.&lt;/li&gt;
&lt;li&gt;Still, &amp;ldquo;cost per feature per time interval&amp;rdquo; tells us that our goal should always be to write code with a low cost per feature. Making sure that it is also low cost to evolve in the future.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&#34;technical-debt&#34;&gt;Technical debt&lt;/h4&gt;
&lt;ol start=&#34;20&#34;&gt;
&lt;li&gt;&lt;strong&gt;Technical debt&lt;/strong&gt; is borrowing time from the future. That is, putting out a bad design today in order to release a feature quickly. Tomorrow, when change comes, the bad design will prevent cost effective change. So time will have to be spent refactoring, turning the bad design into a good one. If refactoring doesn&amp;rsquo;t happen, the debt increases, making future changes more and more expensive.&lt;/li&gt;
&lt;li&gt;How much design you do depends on your skill and your time frame. You can&amp;rsquo;t do so much design that it prevents you from delivering on time. Design is an investment, and for an investment to be good, it needs to return some profit. Good design&amp;rsquo;s returns are quick and plentiful.&lt;/li&gt;
&lt;li&gt;&amp;ldquo;The trick to getting the most bang for your design buck is to acquire an understanding of the theories of design and to apply them appropriately, at the right time, and in the right amounts.&amp;rdquo;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;chapter-2-designing-classes-with-a-single-responsibility&#34;&gt;Chapter 2: Designing Classes with a Single Responsibility&lt;/h3&gt;
&lt;h4 id=&#34;about-classes&#34;&gt;About classes&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Classes&lt;/strong&gt; are the most basic organizational structure of object-oriented systems written with class-based object-oriented languages. As such, that&amp;rsquo;s the first thing that we focus on when designing such systems.&lt;/li&gt;
&lt;li&gt;Your first instinct should be to keep things simple. Use classes to model only the features that your application needs today and make sure that they are easy to change tomorrow.&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Design is more the art of preserving changeability than it is the act of achieving perfection.&amp;rdquo;&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&#34;write-code-that-is-true&#34;&gt;Write code that is TRUE&lt;/h4&gt;
&lt;ol start=&#34;4&#34;&gt;
&lt;li&gt;In order to be easy to change, code should be &lt;strong&gt;TRUE&lt;/strong&gt;:&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Code should be &amp;ldquo;Transparent&amp;rdquo;.&lt;/strong&gt; It should be easy to tell what will be the consequences of changing the code.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Code should be &amp;ldquo;Reasonable&amp;rdquo;.&lt;/strong&gt; The cost of a change should be proportional to the size of the requirement that provoked the change.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Code should be &amp;ldquo;Usable&amp;rdquo;.&lt;/strong&gt; The code should be easy to reuse in situations other than the one it&amp;rsquo;s currently being used in.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Code should be &amp;ldquo;Exemplary&amp;rdquo;.&lt;/strong&gt; The code should exhibit qualities that guide and/or encourage those who change it to keep and replicate those qualities.&lt;/li&gt;
&lt;li&gt;The &lt;a href=&#34;https://en.wikipedia.org/wiki/Single_responsibility_principle&#34;&gt;Single Responsibility Principle&lt;/a&gt; is a prerequisite to creating code that is TRUE.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&#34;single-responsibility&#34;&gt;Single Responsibility&lt;/h4&gt;
&lt;ol start=&#34;10&#34;&gt;
&lt;li&gt;A class should have one single responsibility. That means that it needs to do one thing and do it well. It needs to be as small as possible and fulfill a single purpose. It needs to have only one reason to change.&lt;/li&gt;
&lt;li&gt;A good way to identify what classes your system needs is to read through your user stories or problem descriptions and identify &lt;strong&gt;nouns&lt;/strong&gt;. Those nouns are good candidates for classes.&lt;/li&gt;
&lt;li&gt;If there are &lt;strong&gt;verbs&lt;/strong&gt; and &lt;strong&gt;properties&lt;/strong&gt; associated with those nouns, then it is most likely a class. Because classes represent bundles of both data (attributes) and behavior (methods).&lt;/li&gt;
&lt;li&gt;Classes that have many responsibilities are hard to reuse. And because they are not &amp;ldquo;Usable&amp;rdquo;, they are not easy to change.&lt;/li&gt;
&lt;li&gt;A class that has many responsibilities usually has unrelated code tangled together within it. This makes the class hard to reason about, and hard to reuse.&lt;/li&gt;
&lt;li&gt;In order to reuse the behavior defined within a class with multiple tangled responsibilities, you either need to duplicate code or use the entire class, even the parts that you don&amp;rsquo;t need.&lt;/li&gt;
&lt;li&gt;If you use a class that has many reasons to change, when something unrelated to your use case changes, you will still have to change your code. This is unexpected and surprising. This is not &amp;ldquo;Transparent&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;Depending on classes that have many responsibilities increases the chances of your application breaking.&lt;/li&gt;
&lt;li&gt;A good way to determine whether a class has a single responsibility is to try to enunciate what it does in a single sentence. That sentence should be simple, because classes should be simple. Look out for the words &amp;ldquo;and&amp;rdquo; and &amp;ldquo;or&amp;rdquo; in this sentence, as they point to it having more than one responsibility.&lt;/li&gt;
&lt;li&gt;Another good way to determine whether a class has a single responsibility is thinking about every one of its methods as a question that the class would be able to respond to if it were a sentient being. For example: &amp;ldquo;Array, what is your length?&amp;rdquo; If the question doesn&amp;rsquo;t make sense, then maybe the method does not belong in the class.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cohesion&lt;/strong&gt; is the measure of how related to their core purpose the elements of a component are. Classes that have a single responsibility are highly cohesive because all of their parts work towards a single goal.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&#34;when-to-make-design-decisions&#34;&gt;When to make design decisions&lt;/h4&gt;
&lt;ol start=&#34;21&#34;&gt;
&lt;li&gt;Only design as much as you need to for right now. Don&amp;rsquo;t make design decisions prematurely. Sometimes waiting for more information before committing to a design is the way to go. More information in the future will often reveal a better design.&lt;/li&gt;
&lt;li&gt;Consider postponing design decisions when the information available to you today does not point clearly to a good design. Also, when the cost of not doing it now does not considerably make tomorrow&amp;rsquo;s change more expensive.&lt;/li&gt;
&lt;li&gt;On the other hand, consider that a class that&amp;rsquo;s left in a &amp;ldquo;bad state&amp;rdquo; may be reused by others, making their code depend on badly designed code. The application will suffer as a result.&lt;/li&gt;
&lt;li&gt;The structure of a class is supposed to reveal your design&amp;rsquo;s intention to other developers. When it doesn&amp;rsquo;t, when it is not &amp;ldquo;Exemplary&amp;rdquo;, then future maintenance costs increase.&lt;/li&gt;
&lt;li&gt;The tension between &amp;ldquo;improve it now&amp;rdquo; and &amp;ldquo;improve it later&amp;rdquo; is always present. Our job as designers is to strike a good balance &amp;ldquo;between the needs of the present and the possibilities of the future&amp;rdquo; so that the costs of change are kept low.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&#34;techniques-for-writing-code-thats-easy-to-change&#34;&gt;Techniques for writing code that&amp;rsquo;s easy to change&lt;/h4&gt;
&lt;ol start=&#34;26&#34;&gt;
&lt;li&gt;&lt;strong&gt;Depend on behavior, not data: hide instance variables.&lt;/strong&gt; Instead of accessing instance variables directly, use accessor methods. Even from within the class that owns them. &amp;ldquo;Always send messages to access data.&amp;rdquo;&lt;/li&gt;
&lt;li&gt;That way you consolidate the knowledge of what the data represents in a single place. That&amp;rsquo;s the Single Responsibility Principle in action. Changing it becomes easy as a result because instead of changing references to a variable in potentially multiple places; you only need to change the definition of a method, in a single location.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Depend on behavior, not data: hide data structures.&lt;/strong&gt; When code depends on or receives as input a complex data structure like a big array or hash, encapsulate the data structure in a class with a clear interface, instead of accessing and manipulating the structure directly.&lt;/li&gt;
&lt;li&gt;Directly manipulating complex data structures is a style of coding that tends to propagate. If the incoming data structure changes, even slightly, then a lot of your code also needs to change because it depends on its very particular structure.&lt;/li&gt;
&lt;li&gt;Handling complex raw data structures through classes and messages with clear, intention-revealing names demystifies the structure and gives it meaning within the context of the application domain.&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;For example, instead of this&amp;hellip;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;ObscuringReferences&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;int&lt;/span&gt;[][] data;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; ObscuringReferences(&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;int&lt;/span&gt;[][] data)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;this&lt;/span&gt;.data = data;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; IEnumerable&amp;lt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;int&lt;/span&gt;&amp;gt; GetDiameters()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; data.Select(cell =&amp;gt; cell[&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt;] + (cell[&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt;] * &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;2&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&amp;hellip;do this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;RevealingReferences&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    IEnumerable&amp;lt;Wheel&amp;gt; Wheels { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; RevealingReferences(&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;int&lt;/span&gt;[][] data)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Wheels = Wheelify(data);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;// This method is now more readable.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; IEnumerable&amp;lt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;int&lt;/span&gt;&amp;gt; GetDiameters()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; Wheels.Select(wheel =&amp;gt; wheel.Rim + (wheel.Tire * &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;2&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;// Now everyone can send rim/tire to wheel.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;record&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;Wheel&lt;/span&gt;(&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;int&lt;/span&gt; Rim, &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;int&lt;/span&gt; Tire);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;private&lt;/span&gt; IEnumerable&amp;lt;Wheel&amp;gt; Wheelify(&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;int&lt;/span&gt;[][] data)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; data.Select(cell =&amp;gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;new&lt;/span&gt; Wheel(cell[&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt;], cell[&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt;]));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/blockquote&gt;
&lt;ol start=&#34;31&#34;&gt;
&lt;li&gt;&lt;strong&gt;Enforce single responsibility everywhere: extract extra responsibilities from methods.&lt;/strong&gt; Methods should also have a single responsibility. Just like classes, that makes them easy to reuse, change, and understand.&lt;/li&gt;
&lt;li&gt;To determine if a method has a single responsibility, the same techniques that work for classes apply. Try to enunciate their purpose in a single sentence, and ask them what they do.&lt;/li&gt;
&lt;li&gt;Methods that iterate on items and act upon them too are a common case of multiple responsibilities. Separating iteration and action into two methods is a common refactoring to correct it.&lt;/li&gt;
&lt;li&gt;Complex calculations embedded within methods are also good candidates to be separated into other methods. It gives them a name and makes them reusable.&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;For example, instead of this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;IEnumerable&amp;lt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;int&lt;/span&gt;&amp;gt; GetDiameters()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; Wheels.Select(wheel =&amp;gt; wheel.Rim + (wheel.Tire * &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;2&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&amp;hellip;do this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// First - iterate over the collection.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;IEnumerable&amp;lt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;int&lt;/span&gt;&amp;gt; _GetDiameters()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; Wheels.Select(wheel =&amp;gt; GetDiameter(wheel));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// Second - calculate diameter of ONE wheel.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;int&lt;/span&gt; GetDiameter(Wheel wheel)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; wheel.Rim + (wheel.Tire * &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;2&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/blockquote&gt;
&lt;ol start=&#34;35&#34;&gt;
&lt;li&gt;These refactorings are useful and necessary even when you don&amp;rsquo;t know what the final design will look like. In fact, these refactorings (and good practices like these) will often reveal the final design.&lt;/li&gt;
&lt;li&gt;Small methods with a single responsibility have many benefits. They make a class&amp;rsquo;s details, features, and components more obvious, they are self-documenting, encourage reuse, establish a style of programming that is self-perpetuating, become easy to move to another class when and if that time comes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Enforce single responsibility everywhere: isolate extra responsibilities in classes.&lt;/strong&gt; Move the responsibilities that are extraneous to a class into another class. If you can afford it, create a separate class to hold them. If not, at least encapsulate them in an embedded class so that they are contained and don&amp;rsquo;t leak.&lt;/li&gt;
&lt;li&gt;Embedded classes say: This class only has meaning and value when thought about within the context of this other class.&lt;/li&gt;
&lt;li&gt;Embedded classes can be easily promoted to independent classes later if the need arises.&lt;/li&gt;
&lt;li&gt;Once all methods inside a class have a single responsibility and are each doing the smallest useful thing, it becomes easier to identify the features that may belong to another class.&lt;/li&gt;
&lt;li&gt;The purpose of design is not to produce &amp;ldquo;perfect&amp;rdquo; code but instead to produce code that&amp;rsquo;s &amp;ldquo;good enough&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;The Single Responsibility Principle &amp;ldquo;allows change without consequence and reuse without duplication&amp;rdquo;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;chapter-3-managing-dependencies&#34;&gt;Chapter 3: Managing Dependencies&lt;/h3&gt;
&lt;h4 id=&#34;about-dependencies&#34;&gt;About dependencies&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;Objects should have a single responsibility and do the smallest useful thing. This means that, in order to fulfill complex application requirements, objects need to collaborate with one another.&lt;/li&gt;
&lt;li&gt;Objects collaborate by knowing things about and sending messages to each other. That creates &lt;strong&gt;dependencies&lt;/strong&gt;. A good design manages these dependencies, making sure they don&amp;rsquo;t couple objects so much that change becomes painful.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Coupling&lt;/strong&gt; measures how much interdependency exists between software components. High coupling makes things hard to change.&lt;/li&gt;
&lt;li&gt;An object has a dependency when it knows &lt;strong&gt;the name of another class&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;An object has a dependency when it knows &lt;strong&gt;the name of a method from another class&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;An object has a dependency when it knows &lt;strong&gt;the arguments of that method&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;An object has a dependency when it knows &lt;strong&gt;the order of those arguments&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Dependencies create a situation where if an object changes, then other objects that depend on it may be forced to change as well.&lt;/li&gt;
&lt;li&gt;Dependencies couple objects to each other. Highly coupled objects behave as if they were a unit. It becomes hard to reuse one without the other. If not managed properly, dependencies will disseminate and entangle the entire code base.&lt;/li&gt;
&lt;li&gt;Some dependencies are unavoidable. So the purpose of design is to reduce and contain dependencies. Ensure objects only have the minimum number of dependencies that they need to do their jobs. Keep the essential ones, remove the rest.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&#34;techniques-for-writing-loosely-coupled-code&#34;&gt;Techniques for writing loosely coupled code&lt;/h4&gt;
&lt;ol start=&#34;11&#34;&gt;
&lt;li&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Dependency_injection&#34;&gt;&lt;strong&gt;Dependency injection&lt;/strong&gt;&lt;/a&gt;. It can help eliminate dependencies on concrete classes. Instead of instantiating new objects of another class inside your object, let the object receive it as a constructor or method parameter. The object&amp;rsquo;s users can do the instantiation.&lt;/li&gt;
&lt;li&gt;An object that knows less can often times do more. The knowledge of how to instantiate a particular object limits its potential. Object creation and utilization don&amp;rsquo;t need to be contained within the same unit of code.&lt;/li&gt;
&lt;li&gt;When an object hard-codes the reference to a class, it advertises that it can&amp;rsquo;t work with any other type. Replace the reference to the concrete class with an abstraction (e.g. an &lt;a href=&#34;https://en.wikipedia.org/wiki/Interface_(object-oriented_programming)&#34;&gt;interface&lt;/a&gt; or &lt;a href=&#34;https://en.wikipedia.org/wiki/Duck_typing&#34;&gt;duck type&lt;/a&gt;). That gives it the flexibility to be able to collaborate with other objects that respond to the same messages.&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;With dependency injection you can turn this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;Gear&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;float&lt;/span&gt; Ratio { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;int&lt;/span&gt; Rim { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;int&lt;/span&gt; Tire { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; Gear(&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;float&lt;/span&gt; ratio, &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;int&lt;/span&gt; rim, &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;int&lt;/span&gt; tire)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Ratio = ratio;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Rim = rim;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Tire = tire;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;float&lt;/span&gt; GetGearInches()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; Ratio * &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;new&lt;/span&gt; Wheel(Rim, Tire).GetDiameter();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Into this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;Gear&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;float&lt;/span&gt; Ratio { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Wheel Wheel { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;// Instead of rim and tire, Gear&amp;#39;s constructor now receives a wheel.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; Gear(&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;float&lt;/span&gt; ratio, Wheel wheel)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Ratio = ratio;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Wheel = wheel;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;float&lt;/span&gt; GetGearInches()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#888&#34;&gt;// Instead of creating a new wheel, it uses the one that&amp;#39;s been injected.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; Ratio * Wheel.GetDiameter();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/blockquote&gt;
&lt;ol start=&#34;14&#34;&gt;
&lt;li&gt;Sometimes it is not possible to remove a dependency from an object. In those cases, your best bet is to isolate it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Isolate dependencies: isolate instance creation&lt;/strong&gt;. Sometimes it is not possible to apply dependency injection. In those cases, the next best thing is to encapsulate instantiation of external classes into their own methods.&lt;/li&gt;
&lt;li&gt;An instantiation encapsulated in a method allows the code to clearly and explicitly communicate that there&amp;rsquo;s an extraneous dependency here. One that we&amp;rsquo;d like to remove but for now cannot. We also protect the class from that dependency propagating through it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Isolate dependencies: isolate vulnerable external messages&lt;/strong&gt;. The same technique can be applied to invocations of methods on external classes. Encapsulate such calls into their own methods in order to contain the dependency.&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;Here&amp;rsquo;s what isolating some dependencies could look like. From this&amp;hellip;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;float&lt;/span&gt; GetGearInches()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; Ratio * &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;new&lt;/span&gt; Wheel(Rim, Tire).GetDiameter();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&amp;hellip;to this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;float&lt;/span&gt; GetGearInches()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; Ratio * GetWheelDiameter();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// The dependency on the Wheel class is isolated in this method.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;int&lt;/span&gt; GetWheelDiameter()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;new&lt;/span&gt; Wheel(Rim, Tire).GetDiameter();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/blockquote&gt;
&lt;ol start=&#34;18&#34;&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Reduce argument dependencies: use keyword arguments&lt;/strong&gt;. If your language supports them, keyword arguments are a great way of reducing the dependency incurred via method invocations. They allow the parameters to be sent in any order, which means that changes to the method&amp;rsquo;s definition and signature are less likely to cause the callers to have to also change. Also, they have a self-documenting property on both caller and callee. (See &lt;a href=&#34;https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/named-and-optional-arguments&#34;&gt;named arguments in C#&lt;/a&gt; and &lt;a href=&#34;https://thoughtbot.com/blog/ruby-2-keyword-arguments&#34;&gt;keyword arguments in Ruby&lt;/a&gt;).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Reduce argument dependencies: explicitly define defaults&lt;/strong&gt;. If your language has the feature, parameter defaults are a great way of reducing dependencies to method parameters, as establishing a default for a parameter makes it optional.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Reduce argument dependencies: isolate multiparameter initialization&lt;/strong&gt;. If you don&amp;rsquo;t own the code for a complex object initialization or method invocation, you can always encapsulate it in an object or method of your own. It can be done with a thin wrapper that exposes an interface that follows the techniques we&amp;rsquo;ve discussed and that uses the language of your application.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Classes should depend on things that change less often than they do.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;There are three truths about code related to change and dependencies:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&amp;ldquo;Some classes are more likely to change than others&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Concrete classes are more likely to change than abstract classes&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Changing a class that has many dependents will have many consequences&amp;rdquo;.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;It&amp;rsquo;s OK to depend on classes with a low likelihood of change. For example, classes in the built-in library of your language generally will change less than your own custom classes. Framework classes commonly change less often too, but that may not always be the case if you framework is new or rapidly evolving.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Abstractions are generally much more stable than concretions. Because of this, &lt;strong&gt;it is safer to depend on abstract classes&lt;/strong&gt; (e.g. interfaces and duck types) than on concrete ones.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Avoid classes that have lots of dependencies. Any changes done to them produce a ripple effect of changes throughout the code base. Also, because of that, people will go through great lengths to try to avoid changing them.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;When thinking about dependents and likelihood of change, &lt;strong&gt;the following are harmless&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Classes with few dependents and low likelihood of change (e.g. specialized infrastructure interaction classes).&lt;/li&gt;
&lt;li&gt;Classes with few dependents and high likelihood of change (e.g. concrete classes that implement your app&amp;rsquo;s domain logic).&lt;/li&gt;
&lt;li&gt;Classes with many dependents and low likelihood of change (e.g. interfaces and other abstractions).&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;When thinking about dependents and likelihood of change, &lt;strong&gt;the following is harmful&lt;/strong&gt;: Classes with many dependents and high likelihood of change (e.g. concrete classes that are used throughout the code base).&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2024/02/key-takeaways-from-poodr/likelihood-of-change-versus-number-of-dependents.webp&#34; alt=&#34;A graph divided into four cells. The y axis is labeled &amp;ldquo;dependents&amp;rdquo;, from Few to Many. The x axis is labeled &amp;ldquo;Likelihood of requirements change&amp;rdquo;, from Less to More. The cell with less likelihood of requirements change and many dependents reads &amp;ldquo;Abstract Zone: Changes are unlikely but, if they occur, will have broad effects.&amp;rdquo; The cell with less likelihood of requirements change and fewer dependents reads &amp;ldquo;Neutral Zone: Changes are unlikely and have few side effects.&amp;rdquo; The cell with more likelihood of requirements change and few dependents reads &amp;ldquo;Neutral Zone: Changes are likely but they have few side effects.&amp;rdquo; The cell with more likelihood of requirements change and many dependents reads &amp;ldquo;Danger Zone: These classes WILL change and the changes will cascade into dependents.&amp;rdquo;&#34;&gt;&lt;/p&gt;
&lt;h3 id=&#34;chapter-4-creating-flexible-interfaces&#34;&gt;Chapter 4: Creating Flexible Interfaces&lt;/h3&gt;
&lt;h4 id=&#34;about-interfaces&#34;&gt;About interfaces&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;The messages that objects pass between each other are a big concern for design. In addition to what objects know (responsibilities), and who they know (dependencies), design cares about how they talk to one another. Messages pass between objects through their interfaces.&lt;/li&gt;
&lt;li&gt;In a well designed application, the messages that pass between objects follow a pattern that&amp;rsquo;s closer to the diagram on the right than that of the diagram on the left:&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2024/02/key-takeaways-from-poodr/communication-patterns.webp&#34; alt=&#34;On the left, many dots are connected by a complex network of single-direction arrows. Dots have several arrows pointing to and from them. On the right, the same dots are connected by a single arrow to each. Each dot either has one or more arrows pointing away from it, or a single arrow pointing to it.&#34;&gt;&lt;/p&gt;
&lt;ol start=&#34;3&#34;&gt;
&lt;li&gt;
&lt;p&gt;Objects that expose too much of themselves and know too much about others are hard to reuse and make systems hard to change.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Objects that minimize what they expose of themselves and know little about others are easily reusable and changeable.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;An object&amp;rsquo;s &lt;strong&gt;public interface&lt;/strong&gt; is the set of messages that it responds to. That is, the set of methods that other objects are welcome to invoke. Good design calls for objects with clear and concise public interfaces.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Classes should have one responsibility, but they will likely have many methods. Some methods are more general and expose the main features of a class; they are the services that the class offers its callers. These should make up the class&amp;rsquo;s public interface. Other methods are more specific, serve to support those features, and contain implementation details internal to the class and uninteresting to callers. These make up the class&amp;rsquo;s private interface.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The methods in a class&amp;rsquo;s public interface&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&amp;ldquo;Reveal its primary responsibility&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Are expected to be invoked by others&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Are not likely to change&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Are safe for others to depend on&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Are directly covered by tests&amp;rdquo;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The methods in a class&amp;rsquo;s private interface&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&amp;ldquo;Handle implementation details&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Are not expected to be invoked by other objects&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Are likely to change&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Are unsafe for others to depend on&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;May not even be referenced in the tests&amp;rdquo;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Public methods list the specific features of a class that allow it to fulfill its responsibility. They advertise to the world what the purpose of the class they belong to is.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Public methods are stable and are expected to not change often, so others are welcome to depend on them.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Private methods are not stable at all. They are hidden from others so nobody should depend on them.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&#34;discovering-less-obvious-objects-and-messages&#34;&gt;Discovering less obvious objects and messages&lt;/h4&gt;
&lt;ol start=&#34;12&#34;&gt;
&lt;li&gt;When analyzing a problem domain, the nouns in the narrative usually become your first classes. These are called &amp;ldquo;&lt;strong&gt;domain objects&lt;/strong&gt;&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;Don&amp;rsquo;t let domain objects be your only classes, though. Shift your focus toward messages and away from classes to discover new, less obvious objects that will implement key functionality. Not doing so will risk overloading your domain objects with more responsibility than what they can handle.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Sequence_diagram&#34;&gt;UML sequence diagrams&lt;/a&gt; are an excellent way to explore design alternatives. You can use them to draft objects and their interactions, i.e. the messages they send each other. They are quick, low cost, and allow easy communication of ideas between team members. Here&amp;rsquo;s an online tool that generates them based on plain text: &lt;a href=&#34;https://sequencediagram.org/&#34;&gt;sequencediagram.org&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;The transition from class-based design to message-based design is one that yields more flexible applications. It means asking &amp;ldquo;I need to send this message, who should respond to it?&amp;rdquo; instead of &amp;ldquo;I know I need this class, what should it do?&amp;rdquo;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&#34;focusing-on-what-instead-of-how&#34;&gt;Focusing on &amp;ldquo;what&amp;rdquo; instead of &amp;ldquo;how&amp;rdquo;&lt;/h4&gt;
&lt;ol start=&#34;16&#34;&gt;
&lt;li&gt;Public methods should focus on &amp;ldquo;what&amp;rdquo; instead of &amp;ldquo;how&amp;rdquo;. That is, they should express what the caller wants instead of how the callee must behave.&lt;/li&gt;
&lt;li&gt;If you&amp;rsquo;re in a situation where an object calls many methods on another in succession, try to refactor so that all the logic is executed as a result of a single message. This consolidation reduces the size of the second object&amp;rsquo;s public interface, which reduces what callers need to know about it, which reduces dependency, which makes change easier. The caller only knows &amp;ldquo;what&amp;rdquo; it needs, not &amp;ldquo;how&amp;rdquo; to make the callee deliver.&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;When focusing on &amp;ldquo;what&amp;rdquo; instead of &amp;ldquo;how&amp;rdquo;, code like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;Trip&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    IEnumerable&amp;lt;Bicycle&amp;gt; Bicycles { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Mechanic Mechanic { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;void&lt;/span&gt; Prepare()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;foreach&lt;/span&gt; (&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;var&lt;/span&gt; bike &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;in&lt;/span&gt; Bicycles)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            Mechanic.CleanBicyble(bike);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            Mechanic.PumpTires(bike);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            Mechanic.LubeChain(bike);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            Mechanic.CheckBrakes(bike);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;Mechanic&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;void&lt;/span&gt; CheckBrakes(Bicycle bike) { }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;void&lt;/span&gt; CleanBicyble(Bicycle bike) { }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;void&lt;/span&gt; LubeChain(Bicycle bike) { }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;void&lt;/span&gt; PumpTires(Bicycle bike) { }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Can be transformed into code like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;Trip&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    IEnumerable&amp;lt;Bicycle&amp;gt; Bicycles { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Mechanic Mechanic { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;// This method was greatly simplified and its dependencies were reduced.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;void&lt;/span&gt; Prepare()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;foreach&lt;/span&gt; (&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;var&lt;/span&gt; bike &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;in&lt;/span&gt; Bicycles)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            Mechanic.PrepareBicycle(bike);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;Mechanic&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;void&lt;/span&gt; PrepareBicycle(Bicycle bike)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        CleanBicyble(bike);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        PumpTires(bike);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        LubeChain(bike);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        CheckBrakes(bike);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;// Notice how Mechanic&amp;#39;s public interface was reduced considerably.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;// All of these methods are private now.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;void&lt;/span&gt; CheckBrakes(Bicycle bike) { }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;void&lt;/span&gt; CleanBicyble(Bicycle bike) { }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;void&lt;/span&gt; LubeChain(Bicycle bike) { }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;void&lt;/span&gt; PumpTires(Bicycle bike) { }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/blockquote&gt;
&lt;h4 id=&#34;liberate-objects-from-their-context&#34;&gt;Liberate objects from their context&lt;/h4&gt;
&lt;ol start=&#34;18&#34;&gt;
&lt;li&gt;An object&amp;rsquo;s context is made up of the things that an object knows about others. What other objects it calls and how. What it needs in order to be able to work.&lt;/li&gt;
&lt;li&gt;A good design tries to allow objects to work with minimal context. &amp;ldquo;Objects that have a simple context are easy to use and easy to test; they expect few things from their surroundings. Objects that have a complicated context are hard to use and hard to test; they require complicated setup before they can do anything&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;In order to reduce context, we need to reduce the knowledge that callers have about the other components they call. A simple public interface helps with that. In practical terms that means fewer and less verbose methods, fewer parameters, fewer dependencies.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Objects need to trust their collaborators to do their part&lt;/strong&gt;. Focusing on what the caller wants instead of what the callee does is a way of keeping context in check. This allows objects to collaborate with others regardless of what type they are and what they do.&lt;/li&gt;
&lt;li&gt;Dependency injection is a mechanism through which objects can collaborate with others when they don&amp;rsquo;t know their type. A dependency injected via parameter (declared as an interface or duck type) hides its identity from its user.&lt;/li&gt;
&lt;li&gt;Naming the methods of this injected dependency from the perspective of the caller reveals a generic interface that offers the features that the caller wants in the vocabulary that it understands. The caller does not need to know what the injected dependency does, only what it needs it to do.&lt;/li&gt;
&lt;li&gt;Highly coupled objects with verbose public interfaces say to their collaborators: &amp;ldquo;I know what I want, and I know how you do it&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;More decoupled objects with concise public interfaces say to their collaborators: &amp;ldquo;I know what I want, and I know what you do&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;Highly decoupled objects with concise public interface and minimal required context say to their collaborators: &amp;ldquo;I know what I want, and I trust you to do your part&amp;rdquo;.&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;When objects trust their collaborators, and focus on what they want instead of what others do, the previous Trip/​Mechanic example can become like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;Trip&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; IEnumerable&amp;lt;Bicycle&amp;gt; Bicycles { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Mechanic Mechanic { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;void&lt;/span&gt; Prepare()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#888&#34;&gt;// Trip now fully trusts Mechanic, and doesn&amp;#39;t even know what it does.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Mechanic.PrepareTrip(&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;this&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;Mechanic&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;// The knowledge of &amp;#34;how a mechanic prepares a trip&amp;#34; now completely lives&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;// within Mechanic.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;void&lt;/span&gt; PrepareTrip(Trip trip)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;foreach&lt;/span&gt; (&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;var&lt;/span&gt; bike &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;in&lt;/span&gt; trip.Bicycles)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            PrepareBicycle(bike);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;void&lt;/span&gt; PrepareBicycle(Bicycle bike)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        CleanBicyble(bike);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        PumpTires(bike);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        LubeChain(bike);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        CheckBrakes(bike);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;void&lt;/span&gt; CheckBrakes(Bicycle bike) { }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;void&lt;/span&gt; CleanBicyble(Bicycle bike) { }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;void&lt;/span&gt; LubeChain(Bicycle bike) { }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;void&lt;/span&gt; PumpTires(Bicycle bike) { }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/blockquote&gt;
&lt;h4 id=&#34;rules-of-thumb-for-writing-code-with-good-interfaces&#34;&gt;Rules of thumb for writing code with good interfaces&lt;/h4&gt;
&lt;ol start=&#34;27&#34;&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Create explicit interfaces&lt;/strong&gt;. Be intentional and obvious when defining public and private methods. Use your language access modifiers (i.e. public, private, protected, etc). Your public methods should:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Be explicitly identified as such&lt;/li&gt;
&lt;li&gt;Be more about what than how&lt;/li&gt;
&lt;li&gt;Have names that are unlikely to change&lt;/li&gt;
&lt;li&gt;Use keyword arguments&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Respect the public interface of others&lt;/strong&gt;. Invoke only public methods on the classes that you use. Avoid circumventing their public interfaces and directly calling private members. Depending on the private interface of framework and library classes is like a ticking time bomb. The reason they are private is because they are expected to change or disappear entirely.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Minimize context&lt;/strong&gt;. Focus on &amp;ldquo;what&amp;rdquo; instead of &amp;ldquo;how&amp;rdquo; when designing public interfaces. Favor public methods that allow callers to access your classes&amp;rsquo; functionality without having to know how they do it. Use interface and duck types to name methods from the perspective of and with the vocabulary of the callers.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If you have to interact with a class that does not have a clean interface, and you don&amp;rsquo;t own it or otherwise can&amp;rsquo;t refactor it so that it does, isolate it. Use the same techniques for dependency isolation mentioned in Chapter 3. Wrap the invocation in a new class or method to contain it and give that wrapper a clean public interface.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Follow the law of Demeter&lt;/strong&gt;. The law of Demeter states that you shouldn&amp;rsquo;t chain multiple method calls that navigate across many different types of objects. In other words &amp;ldquo;talk only to your close neighbors&amp;rdquo; or &amp;ldquo;use only one dot&amp;rdquo;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;Violations ot the law of Demeter look like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;customer.GetBicycle().Wheel.Rotate();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/blockquote&gt;
&lt;ol start=&#34;32&#34;&gt;
&lt;li&gt;Violations of the law of Demeter make for code that&amp;rsquo;s not TRUE. Changes in the object at the end of the chain ripple through the entire chain. This is unexpected and laborious, making the code neither Transparent nor Reasonable. The class that uses the chain depends on all the objects in the chain, making it non-Usable. These chains are easy to replicate and harm changeability, making the code not Exemplary.&lt;/li&gt;
&lt;li&gt;Always evaluate the cost of violating the law of Demeter versus the cost of abiding by it. Method chains that ultimately read an attribute are generally less harmful. Also, method chains on really stable classes like those of your language library or framework have low impact.&lt;/li&gt;
&lt;li&gt;Delegation can appear to be a solution to law of Demeter violations. Unfortunately, all it does is remove the evidence that it&amp;rsquo;s there.&lt;/li&gt;
&lt;li&gt;In reality, a violation to the law of Demeter indicates that there&amp;rsquo;s an object missing or that the public interface of an object is lacking. Find the object, and its interface, by thinking more about messages and less about classes. Define the interface by thinking about what the object needs of its collaborators, and not about how it can get it by itself.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;chapter-5-reducing-costs-with-duck-typing&#34;&gt;Chapter 5: Reducing Costs with Duck Typing&lt;/h3&gt;
&lt;h4 id=&#34;about-duck-types&#34;&gt;About duck types&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Duck types&lt;/strong&gt; are public interfaces that manifest themselves across classes. When multiple classes accept the same messages (i.e. define methods with the same signature), they are said to be of the same duck type.&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Duck type&amp;rdquo; is a dynamic language concept. Static languages offer equivalent features via &amp;ldquo;&lt;a href=&#34;https://en.wikipedia.org/wiki/Interface_(object-oriented_programming)&#34;&gt;interfaces&lt;/a&gt;&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;The difference is that, in statically typed languages, interfaces need to be explicitly defined in code and concrete classes need to explicitly implement them. On the other hand, duck types in dynamically typed languages need only be acknowledged in an abstract sense. They don&amp;rsquo;t have to be explicitly defined in code.&lt;/li&gt;
&lt;li&gt;Duck types and interfaces establish a contract. A set of messages that a given object is expected to be able to receive. A protocol that users of these objects can be confident that they will adhere to.&lt;/li&gt;
&lt;li&gt;Just as a class can implement multiple interfaces, an object can be of many duck types. That&amp;rsquo;s because interfaces and duck types materialize depending on the situation in which objects that implement them are used. The same object can be used in different places for different things. Each user will see the object from their own perspective, and each can expect it conform to a different interface. See the &lt;a href=&#34;https://en.wikipedia.org/wiki/Interface_segregation_principle&#34;&gt;interface segregation principle&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Moreover, code that depends on an interface or duck type is flexible enough to collaborate with any concrete class that implements that interface or duck type. See the &lt;a href=&#34;https://en.wikipedia.org/wiki/Liskov_substitution_principle&#34;&gt;Liskov substitution principle&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;As we&amp;rsquo;ve established, it&amp;rsquo;s better to depend on abstractions than to depend on concretions. So, users of an object should not care what its type is, only what it does. Behavior over identity. In other words, they should focus on messages and public interfaces, instead of specific classes. Duck types and interfaces bring to the forefront what an object does and abstracts away what it is.&lt;/li&gt;
&lt;li&gt;Applying duck types to a situation makes the code more abstract and less concrete. Concrete code is easier to understand but harder to extend. Abstract code is harder to understand at the beginning but easier to change. In the long run, abstract code tends to reduce maintenance costs.&lt;/li&gt;
&lt;li&gt;When an object invokes methods on multiple objects in order to achieve a single purpose, that&amp;rsquo;s a situation where a duck type may be helpful. Think from the perspective of the caller and what it needs to come up with a message that makes sense for it to send its many collaborators. That method should be part of the public interface of each of its collaborators. To the caller&amp;rsquo;s eyes, each of its collaborators belong in the same duck type.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&#34;writing-code-that-leverages-duck-types&#34;&gt;Writing code that leverages duck types&lt;/h4&gt;
&lt;ol start=&#34;10&#34;&gt;
&lt;li&gt;Whenever you see conditional logic that sends a different message depending on the concrete class of a given object, that&amp;rsquo;s the code telling you that it needs a duck type or interface.&lt;/li&gt;
&lt;li&gt;Come up with a message that makes sense from the perspective of the caller and add it to each of the classes expected by your code in the conditional. These classes now share the same public interface, they are of the same duck type. Then remove the conditional and just call that method. Replace conditional logic with &lt;a href=&#34;https://en.wikipedia.org/wiki/Polymorphism_(computer_science)&#34;&gt;polymorphism&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;In general, try to avoid code that explicitly mentions concrete classes or checks for the existence of particular methods in order to determine further behavior. Instead, come up with a shared interface and send those messages to the collaborators regardless of their actual type.&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;Higly conditional and concrete logic like this&amp;hellip;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;Trip&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; IEnumerable&amp;lt;Bicycle&amp;gt; Bicycles { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; IEnumerable&amp;lt;Customer&amp;gt; Customers { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; Vehicle Vehicle { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;void&lt;/span&gt; Prepare(IEnumerable preparers)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;foreach&lt;/span&gt; (&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;var&lt;/span&gt; preparer &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;in&lt;/span&gt; preparers)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; (preparer &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;is&lt;/span&gt; Mechanic)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                ((Mechanic)preparer).PrepareBicycles(Bicycles);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; (preparer &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;is&lt;/span&gt; TripCoordinator)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                ((TripCoordinator)preparer).BuyFood(Customers);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; (preparer &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;is&lt;/span&gt; Driver)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                ((Driver)preparer).GasUp(Vehicle);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                ((Driver)preparer).FillWaterTank(Vehicle);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;Mechanic&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;void&lt;/span&gt; PrepareBicycles(IEnumerable&amp;lt;Bicycle&amp;gt; bicycles) { }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;TripCoordinator&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;void&lt;/span&gt; BuyFood(IEnumerable&amp;lt;Customer&amp;gt; customers) { }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;Driver&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;void&lt;/span&gt; FillWaterTank(Vehicle vehicle) { }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;void&lt;/span&gt; GasUp(Vehicle vehicle) { }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&amp;hellip;can be rewritten to be more abstract if we leverage polymorphism. Like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;Trip&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; IEnumerable&amp;lt;Bicycle&amp;gt; Bicycles { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; IEnumerable&amp;lt;Customer&amp;gt; Customers { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; Vehicle Vehicle { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;// This method can be much simpler now, and abstract.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;// Ready to collaborate with any &amp;#34;TripPreparer&amp;#34;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;// The conditional logic has been replaced with polymorphism.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;void&lt;/span&gt; Prepare(IEnumerable&amp;lt;ITripPreparer&amp;gt; preparers)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;foreach&lt;/span&gt; (&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;var&lt;/span&gt; preparer &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;in&lt;/span&gt; preparers)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            preparer.PrepareTrip(&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;this&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// New interface that all preparers implement. It has a single method.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// It greatly simplifies the communication between Trip and its many&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// possible preparers.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;interface&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;ITripPreparer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;void&lt;/span&gt; PrepareTrip(Trip trip);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;Mechanic&lt;/span&gt; : ITripPreparer
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;void&lt;/span&gt; PrepareTrip(Trip trip)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        PrepareBicycles(trip.Bicycles);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;void&lt;/span&gt; PrepareBicycles(IEnumerable&amp;lt;Bicycle&amp;gt; bicycles) { }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;TripCoordinator&lt;/span&gt; : ITripPreparer
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;void&lt;/span&gt; PrepareTrip(Trip trip)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        BuyFood(trip.Customers);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;void&lt;/span&gt; BuyFood(IEnumerable&amp;lt;Customer&amp;gt; customers) { }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;Driver&lt;/span&gt; : ITripPreparer
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;void&lt;/span&gt; PrepareTrip(Trip trip)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        FillWaterTank(trip.Vehicle);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        GasUp(trip.Vehicle);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;void&lt;/span&gt; FillWaterTank(Vehicle vehicle) { }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;void&lt;/span&gt; GasUp(Vehicle vehicle) { }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/blockquote&gt;
&lt;ol start=&#34;13&#34;&gt;
&lt;li&gt;The one exception to this rule is when dealing with exceptionally stable classes. Like those in your language libraries, where the introduction of duck types would mean modifying core language libraries. Explicit type checks against these classes are usually low cost.&lt;/li&gt;
&lt;li&gt;Duck types are abstract and less obvious in the code. That&amp;rsquo;s why they need to be well documented and tested.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;chapter-6-acquiring-behavior-through-inheritance&#34;&gt;Chapter 6: Acquiring Behavior through Inheritance&lt;/h3&gt;
&lt;h4 id=&#34;about-inheritance&#34;&gt;About inheritance&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Inheritance&lt;/strong&gt; establishes a relationship between two classes where it is said that a subclass B &amp;ldquo;is a&amp;rdquo; superclass A. Subclass and superclass are also referred to as derived class and base class, respectively.&lt;/li&gt;
&lt;li&gt;Inheritance can be more technically defined as an &amp;ldquo;automatic message forwarding mechanism&amp;rdquo;. That is, when a subclass receives a message that it cannot respond to directly (i.e. a method that it does not implement), the language runtime takes care of automatically sending the message to the superclass.&lt;/li&gt;
&lt;li&gt;That is, inheritance establishes a hierarchy where superclasses share their code with their subclasses.&lt;/li&gt;
&lt;li&gt;Subclasses are meant to be specialized versions of their superclass. Subclasses should be &amp;ldquo;the same, plus more&amp;rdquo; when compared to their superclass. They should offer the same public interface.&lt;/li&gt;
&lt;li&gt;Inheritance is ideal to solve the problem where you need a series of slightly different classes that share a lot of behavior.&lt;/li&gt;
&lt;li&gt;A telltale sign that inheritance needs to be applied is when code contains an &amp;ldquo;if&amp;rdquo; statement checking an attribute that contains the &amp;ldquo;category&amp;rdquo; of the object, and based on that determines what code to execute. Watch out for this anti-pattern and for variables with names like &amp;ldquo;type&amp;rdquo;, &amp;ldquo;category&amp;rdquo;, &amp;ldquo;style&amp;rdquo; that control branches in behavior.&lt;/li&gt;
&lt;li&gt;This is an anti-pattern that reveals that the object knows too much and needs to be broken down into smaller pieces. It increases the costs of change.&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;Here&amp;rsquo;s what the anti-pattern looks like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;Bicycle&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt; Style { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt; TapeColor { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt; FrontShock { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; Bicycle(Dictionary&amp;lt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt;, &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt;&amp;gt; options)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Style = options[&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;style&amp;#34;&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        TapeColor  = options[&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;tape_color&amp;#34;&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        FrontShock = options[&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;front_shock&amp;#34;&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;// Checking &amp;#39;style&amp;#39; starts down a slippery slope.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; Dictionary&amp;lt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt;, &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt;&amp;gt; GetSpares()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; (Style == &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;road&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;new&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;                [&amp;#34;chain&amp;#34;]&lt;/span&gt; = &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;11-speed&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;                [&amp;#34;tire_size&amp;#34;]&lt;/span&gt; = &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;23&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;                [&amp;#34;tape_color&amp;#34;]&lt;/span&gt; = TapeColor
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; (Style == &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;mountain&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;new&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;                [&amp;#34;chain&amp;#34;]&lt;/span&gt; = &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;11-speed&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;                [&amp;#34;tire_size&amp;#34;]&lt;/span&gt; = &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;2.1&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;                [&amp;#34;front_shock&amp;#34;]&lt;/span&gt; = FrontShock
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/blockquote&gt;
&lt;h4 id=&#34;applying-inheritance&#34;&gt;Applying inheritance&lt;/h4&gt;
&lt;ol start=&#34;8&#34;&gt;
&lt;li&gt;Be on the lookout for existing classes that may lead you down the wrong path when it comes to inheritance. More often than not, classes that already exist in the code base are not good candidates for extension via inheritance. They are not good candidates to be superclasses.&lt;/li&gt;
&lt;li&gt;The path forward is likely to be a new class to serve as the base, and then update your existing class to be a subclass. Then add other subclasses as peers of it.&lt;/li&gt;
&lt;li&gt;For inheritance to work, the objects being modeled need to truly share a generalization-specialization relationship.&lt;/li&gt;
&lt;li&gt;The superclass needs to define the common behavior that is shared among subclasses. The subclasses define the specializations.&lt;/li&gt;
&lt;li&gt;In many cases, the superclass should be &lt;strong&gt;abstract&lt;/strong&gt;, meaning that they are not supposed to be instantiated. They represent an incomplete object which only becomes whole when looked at in the context of each of its subclasses.&lt;/li&gt;
&lt;li&gt;It almost never makes sense to create a superclass with only a single subclass. In fact, creating an inheritance hierarchy with two subclasses is often risky. You risk coming up with the wrong abstraction.&lt;/li&gt;
&lt;li&gt;Three subclasses is the sweet spot to commit to inheritance. Put off the decision to implement inheritance until that point, if you can. That&amp;rsquo;s the point when there&amp;rsquo;s enough information available to confidently determine an abstraction that will be useful and cost effective.&lt;/li&gt;
&lt;li&gt;If you put off implementing an inheritance hierarchy, then you won&amp;rsquo;t be able to share code between the highly related classes. That will likely lead to code repetition, which is also costly. Consider what costs more: having the repetition for the time being; or doing nothing and waiting for more information to avoid making the wrong decision.&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Every decision you make includes two costs: one to implement it and another to change it when you discover that you were wrong&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;When refactoring towards an inheritance hierarchy, consider that &amp;ldquo;promoting&amp;rdquo; code from the concrete subclass up into the abstract superclass is often easier and less error prone.&lt;/li&gt;
&lt;li&gt;Errors in promoting are easy to identify and fix. All that can happen if you miss a promotion is that a subclass that was meant to inherit some behavior won&amp;rsquo;t have it.&lt;/li&gt;
&lt;li&gt;Going in the opposite direction and missing a &amp;ldquo;demotion&amp;rdquo; will produce design errors that are harder to spot and have dire consequences if left alone.&lt;/li&gt;
&lt;li&gt;That would mean that concrete behavior, which does not apply to all subclasses, stays incorrectly in the abstract base class. That&amp;rsquo;ll throw a wrench in the works and the whole inheritance hierarchy will be on shaky grounds. The abstract base class won&amp;rsquo;t be generic enough and subclasses will be tempted to circumvent it.&lt;/li&gt;
&lt;li&gt;&amp;ldquo;The general rule for refactoring into a new inheritance hierarchy is to arrange code so that you can promote abstractions rather than demote concretions&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;The &lt;a href=&#34;https://en.wikipedia.org/wiki/Template_method_pattern&#34;&gt;template method pattern&lt;/a&gt; provides a clean way of defining a common basic algorithm in the superclass and allowing subclasses to supply specializations for it. Superclasses can define an algorithm, and call certain methods in key points within it. These are extension points. These methods can then be implemented by subclasses, letting them control part of the overall logic.&lt;/li&gt;
&lt;li&gt;When promoting concrete code to the more abstract superclass, consider using the template method when methods cannot be promoted wholesale, and have to be broken up instead. The parts that can be promoted become the template method; the parts that can&amp;rsquo;t be become the specialization methods that each concrete subclass implements.&lt;/li&gt;
&lt;li&gt;To avoid future bugs, superclasses should provide default implementations for the specialization methods that it expects its subclasses to implement. These can be no-ops or, even better, raise errors. These errors let developers know that extending this inheritance hierarchy requires these methods to be implemented.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.geeksforgeeks.org/ruby-hook-methods/&#34;&gt;Hook methods&lt;/a&gt; are a slightly lighter iteration of the template method concept that helps alleviate superclass-subclass coupling. Same principle: let the superclass send a message that the subclass implements in order to provide a specialization.&lt;/li&gt;
&lt;li&gt;A hook method need not be a part of a common abstract algorithm, hence the slight distinction from the full fledged template method design pattern.&lt;/li&gt;
&lt;li&gt;Beware of subclasses explicitly invoking functionality on their superclasses. Languages often offer keywords such as &amp;ldquo;&lt;a href=&#34;https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/base&#34;&gt;base&lt;/a&gt;&amp;rdquo; or &amp;ldquo;&lt;a href=&#34;https://www.rubyguides.com/2018/09/ruby-super-keyword/&#34;&gt;super&lt;/a&gt;&amp;rdquo; that allow easily sending messages to superclasses. These are dangerous because they couple subclasses with their superclasses. They reveal that subclasses know the general algorithm.&lt;/li&gt;
&lt;li&gt;The template method pattern and hook methods invert this dependency, allowing the superclass to call the subclass. Allowing the subclass to provide specializations without knowing too much about the superclass.&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;Here&amp;rsquo;s an example of a properly factored inheritance hierarchy:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// The main purpose of the base class is to establish a basic functionality&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// that can be easily extended by subclasses.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// This class cannot be instantiated, as given by the &amp;#34;abstract&amp;#34; modifier.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// This means that our application has no need of holding onto pure Bicycle&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// instances, only the concrete subclasses are to be used.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// This abstract class is just a vehicle for sharing code between other classes.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;abstract&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;Bicycle&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt; Size { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt; Chain { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt; TireSize { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;// Notice how this constructor implements the template method pattern&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;// in order to allow subclasses to make changes to the overall algorithm.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;// Specifically, it allows them to provide default values for the Chain and&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;// TireSize attributes as well as run any additional logic after&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;// initialization.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; Bicycle(Dictionary&amp;lt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt;, &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt;&amp;gt; options)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Size = options.GetValueOrDefault(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;size&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Chain  = options.GetValueOrDefault(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;chain&amp;#34;&lt;/span&gt;) ?? GetDefaultChain();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        TireSize = options.GetValueOrDefault(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;tire_size&amp;#34;&lt;/span&gt;) ?? GetDefaultTireSize();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        AfterInitialize(options);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;// This method establishes the basic spares information and allows&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;// subclasses to supply more by calling the GetLocalSpares hook method.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; Dictionary&amp;lt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt;, &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt;&amp;gt; GetSpares()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;var&lt;/span&gt; defaultSpares = &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;new&lt;/span&gt; Dictionary&amp;lt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt;, &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt;&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;            [&amp;#34;tire_size&amp;#34;]&lt;/span&gt; = &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;23&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;            [&amp;#34;chain&amp;#34;]&lt;/span&gt; = &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;11-speed&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;new&lt;/span&gt;(defaultSpares.Concat(GetLocalSpares()));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;// This method, which is marked as abstract, has to be implemented by&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;// subclasses. It allows subclasses to contribute specializations.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;protected&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;abstract&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt; GetDefaultTireSize();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;// These methods, marked as virtual, all have default implementations of&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;// varying complexity but the important aspect is that they can be&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;// overridden by subclasses. They also allow subclasses to contribute&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;// specializations.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;protected&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;virtual&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;void&lt;/span&gt; AfterInitialize(Dictionary&amp;lt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt;, &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt;&amp;gt; options) { }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;protected&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;virtual&lt;/span&gt; Dictionary&amp;lt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt;, &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt;&amp;gt; GetLocalSpares() =&amp;gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;new&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;protected&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;virtual&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt; GetDefaultChain() =&amp;gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;11-speed&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// Notice how the following concrete subclasses are very simple.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// Extending this kind of code is easy, because creating new subclasses is easy.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// They leverage their abstract base class to implement most of their features.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// Their job is to supply specializations on the core logic defined in the base&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// class. To do so, they override the hook methods defined by the base class.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;RoadBike&lt;/span&gt; : Bicycle
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt; TapeColor { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; RoadBike(Dictionary&amp;lt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt;, &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt;&amp;gt; options) : &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;base&lt;/span&gt;(options) { }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;protected&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;void&lt;/span&gt; AfterInitialize(Dictionary&amp;lt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt;, &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt;&amp;gt; options) =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        TapeColor = options.GetValueOrDefault(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;tape_color&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;protected&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;override&lt;/span&gt; Dictionary&amp;lt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt;, &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt;&amp;gt; GetLocalSpares() =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;new&lt;/span&gt;() { [&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;tape_color&amp;#34;&lt;/span&gt;] = TapeColor };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;protected&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt; GetDefaultTireSize() =&amp;gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;23&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;MountainBike&lt;/span&gt; : Bicycle
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt; FrontShock { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt; RearShock { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; MountainBike(Dictionary&amp;lt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt;, &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt;&amp;gt; options) : &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;base&lt;/span&gt;(options) { }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;protected&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;void&lt;/span&gt; AfterInitialize(Dictionary&amp;lt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt;, &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt;&amp;gt; options)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        FrontShock = options.GetValueOrDefault(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;front_shock&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        RearShock = options.GetValueOrDefault(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;rear_shock&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;protected&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;override&lt;/span&gt; Dictionary&amp;lt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt;, &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt;&amp;gt; GetLocalSpares() =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;new&lt;/span&gt;() { [&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;front_shock&amp;#34;&lt;/span&gt;] = FrontShock };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;protected&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt; GetDefaultTireSize() =&amp;gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;2.1&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;RecumbentBike&lt;/span&gt; : Bicycle
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt; Flag { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; RecumbentBike(Dictionary&amp;lt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt;, &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt;&amp;gt; options) : &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;base&lt;/span&gt;(options) { }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;protected&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;void&lt;/span&gt; AfterInitialize(Dictionary&amp;lt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt;, &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt;&amp;gt; options) =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Flag = options.GetValueOrDefault(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;flag&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;protected&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;override&lt;/span&gt; Dictionary&amp;lt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt;, &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt;&amp;gt; GetLocalSpares() =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;new&lt;/span&gt;() { [&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;flag&amp;#34;&lt;/span&gt;] = Flag };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;protected&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt; GetDefaultChain() =&amp;gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;10-speed&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;protected&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;string&lt;/span&gt; GetDefaultTireSize() =&amp;gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;28&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/blockquote&gt;
&lt;h3 id=&#34;chapter-7-sharing-role-behavior-with-modules&#34;&gt;Chapter 7: Sharing Role Behavior with Modules&lt;/h3&gt;
&lt;h4 id=&#34;about-roles&#34;&gt;About roles&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;Using classical inheritance is always optional. Every situation that calls for inheritance could be solved using another technique that allows for sharing code between otherwise unrelated classes.&lt;/li&gt;
&lt;li&gt;The concept of &amp;ldquo;&lt;strong&gt;roles&lt;/strong&gt;&amp;rdquo; is an alternative to classical inheritance. This concept emerges from the need of multiple classes to be used in a particular context to do the same thing. So they themselves need to share behavior.&lt;/li&gt;
&lt;li&gt;Think of a role as an augmented form of a duck type. A group of classes are said to play the same role when they belong in the same duck type or implement the same interface. In addition to exposing the same public interface, roles allow them to share internal behavior.&lt;/li&gt;
&lt;li&gt;Roles are ideal for storing responsibilities that are orthogonal to classes. It allows classes that are otherwise unrelated to share behavior. They establish a &amp;ldquo;behaves like&amp;rdquo; type of relationship between objects, as opposed to the &amp;ldquo;is a&amp;rdquo; relationship that is established with inheritance.&lt;/li&gt;
&lt;li&gt;When you include a module into an existing class, all the methods defined in the module become available to the class. This is the same thing that happens when a subclass inherits from a superclass.&lt;/li&gt;
&lt;li&gt;Many languages offer native features to allow for this kind of relationship between objects. In Ruby, we use &lt;a href=&#34;http://ruby-for-beginners.rubymonstas.org/advanced/modules.html&#34;&gt;Modules&lt;/a&gt;. Other languages use &lt;a href=&#34;https://www.pythontutorial.net/python-oop/python-mixin/&#34;&gt;Mixins&lt;/a&gt;, &lt;a href=&#34;https://www.php.net/manual/en/language.oop5.traits.php&#34;&gt;Traits&lt;/a&gt;, &lt;a href=&#34;https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html&#34;&gt;Default Methods&lt;/a&gt;. Simply put, all these are ways of bundling together a group of methods that can be easily plugged into existing classes.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&#34;writing-inheritable-code&#34;&gt;Writing inheritable code&lt;/h4&gt;
&lt;ol start=&#34;7&#34;&gt;
&lt;li&gt;The same principles, techniques, and anti patterns that apply to the design of duck types and inheritance hierarchies also apply to roles.&lt;/li&gt;
&lt;li&gt;Beware of objects that use a variable with a name like &amp;ldquo;type&amp;rdquo;, &amp;ldquo;category&amp;rdquo; or &amp;ldquo;kind&amp;rdquo; to determine what code to execute. The object is likely concealing (and acting like) two or more types. These would be subclasses or module includers.&lt;/li&gt;
&lt;li&gt;When code is checking the type of an object to decide which message to send it, that&amp;rsquo;s a signal that there&amp;rsquo;s a missing abstraction. There&amp;rsquo;s a duck type or role in there that needs to be explicitly brought to light. A public interface needs to be defined for it. If there is a need to share behavior, put it in a module, mixin, etc.&lt;/li&gt;
&lt;li&gt;&amp;ldquo;All of the code in the abstract superclass should apply to every class that inherits it&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;Beware of subclasses or module includers that override a superclass/​module method just to raise a &amp;ldquo;not implemented&amp;rdquo; error. Chances are that if only part of the superclass applies to it, then it doesn&amp;rsquo;t belong in the hierarchy. Or maybe the whole hierarchy needs a redesign.&lt;/li&gt;
&lt;li&gt;Subclasses agree to the contract specified by their superclasses. They must respond to every message in the superclass&amp;rsquo;s public interface, accept the same types of inputs and return the same types outputs.&lt;/li&gt;
&lt;li&gt;Put in other words, &amp;ldquo;subtypes must be substitutable for their supertype&amp;rdquo;. That is, all subclasses should act like their superclass. This means that any code that expects a superclass should be able to work, without change, with all its subclasses as well. That&amp;rsquo;s the Liskov substitution principle.&lt;/li&gt;
&lt;li&gt;Through the concept of &lt;a href=&#34;https://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)&#34;&gt;variance&lt;/a&gt;, subclasses have a slightly higher degree of freedom. Subclasses can accept inputs of more abstract types and can return outputs of more concrete types than those specified in the superclass&amp;rsquo;s public interface while still being substitutable for their superclass.&lt;/li&gt;
&lt;li&gt;For example, given a class &amp;ldquo;Object&amp;rdquo; that is a superclass of a class &amp;ldquo;String&amp;rdquo;; if a method in a superclass &amp;ldquo;MyClass&amp;rdquo; accepts a String parameter, a subclass of MyClass could override that same method and accept Object and still be compliant. Likewise, if a method in a superclass returns an Object result, the subclass could return a String for that same method, and still be compliant. Still be substitutable.&lt;/li&gt;
&lt;li&gt;In other words, some code that sends a message with a String parameter can send the same message to a receiver that accepts Object. Likewise, some code that expects an Object as a result of sending a message can send the same message to a receiver that returns a String. Because a String &amp;ldquo;is an&amp;rdquo; Object, any code that works with an Object can work with a String, it&amp;rsquo;ll just treat it like an Object and only access Object&amp;rsquo;s public interface, which String fully supports.&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;This is what variance allows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;Superclass&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;virtual&lt;/span&gt; Object DoSomething(String parameter) =&amp;gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;new&lt;/span&gt; Object();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;Subclass&lt;/span&gt; : Superclass
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;override&lt;/span&gt; String DoSomething(Object parameter) =&amp;gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;the result&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Be aware that C# currently does not support variance in parameters, only in return types. So this code would not actually work as it is, since the parameter types are different.&lt;/p&gt;&lt;/blockquote&gt;
&lt;ol start=&#34;17&#34;&gt;
&lt;li&gt;The template method pattern is the ideal technique for creating superclasses that are easy to inherit from. It allows clean separation of an abstract algorithm from the concrete specializations.&lt;/li&gt;
&lt;li&gt;Be on the lookout for code that directly invokes superclass behavior with keywords like &amp;ldquo;super&amp;rdquo; or &amp;ldquo;base&amp;rdquo; etc. Instead, use hook methods to allow subclasses to contribute to parts of the common algorithm.&lt;/li&gt;
&lt;li&gt;Favor shallow hierarchies instead of deep ones. Narrow is also preferable to wide. Wide ones are easier to live with as long as they are shallow. But deep and wide ones are a maintenance nightmare. That is, keep the vertical levels of inheritance as low as you can. Hierarchies with many layers of superclasses are hard to understand and maintain.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2024/02/key-takeaways-from-poodr/hierarchies-come-in-different-shapes.webp&#34; alt=&#34;Four diagrams show hierarchies of boxes. The top left is labeled &amp;ldquo;Shallow, Narrow&amp;rdquo; and has one box on top, with two boxes beneath, each connected to the top one by a line. The bottom left is labeled &amp;ldquo;Deep, Narrow&amp;rdquo; and shows the same diagram, but the box on the bottom left has two boxes of its own beneath it, one of which has its own boxes, et cetera, for a total of five layers, each with two boxes. The top right is labeled &amp;ldquo;Shallow, Wide&amp;rdquo;, and shows one box on top, with a single line connecting to each of five boxes directly beneath it. The bottom right is labeled &amp;ldquo;Deep, Wide&amp;rdquo;, and shows a 5-layer box diagram, with anywhere from 3 to 7 boxes on each level, connected by single lines. Different boxes have their own hierarchy, so boxes on the same level are not always direct siblings.&#34;&gt;&lt;/p&gt;
&lt;h3 id=&#34;chapter-8-combining-objects-with-composition&#34;&gt;Chapter 8: Combining Objects with Composition&lt;/h3&gt;
&lt;h4 id=&#34;about-composition&#34;&gt;About composition&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Composition&lt;/strong&gt; establishes a &amp;ldquo;has a&amp;rdquo; relationship between objects. It is a technique where you combine simple, independent objects to turn them into larger, more complex ones. Composition combines distinct parts so that the resulting entity is more than the sum of its parts.&lt;/li&gt;
&lt;li&gt;In composition, the container object (or composed object) &amp;ldquo;has a&amp;rdquo; contained component (or part). Mechanically, this usually means that the container&amp;rsquo;s class has an attribute which holds a reference to the part object. It&amp;rsquo;s a dependency that&amp;rsquo;s usually injected via constructor parameter.&lt;/li&gt;
&lt;li&gt;The container communicates with the part via its public interface. The part plays a role, and the container collaborates with it. This means that containers generally interact with their parts through interfaces or duck types.&lt;/li&gt;
&lt;li&gt;Composition is generally a cheaper alternative to code sharing when compared to inheritance.&lt;/li&gt;
&lt;li&gt;When refactoring from inheritance into composition, the parts sometimes need to share some code, in addition to sharing the same public interface. This is because all possible parts play the same role for the container. In these cases, an inheritance hierarchy of parts may be what&amp;rsquo;s needed. Or, they could share behavior via modules or mixins.&lt;/li&gt;
&lt;li&gt;In technical terms, the technique of composition takes two forms: &lt;strong&gt;aggregation&lt;/strong&gt; and, well, &lt;strong&gt;composition&lt;/strong&gt;. Under composition, parts don&amp;rsquo;t have any use or value outside of their container objects. Under aggregation, on the other hand, parts can live on their own.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&#34;factories&#34;&gt;Factories&lt;/h4&gt;
&lt;ol start=&#34;7&#34;&gt;
&lt;li&gt;When creating certain objects becomes complex, encapsulate that complexity into a factory. That way the knowledge is stored in a single place in the code base. In principle, factories are simple: They are objects that create other objects.&lt;/li&gt;
&lt;li&gt;An advantage of factories is that they make the process of turning complex data structures into objects easy. You can have a &amp;ldquo;specification&amp;rdquo;, stored as pure data in a file or database. The factory can then implement the logic that understands the meaning of the data structure and how to create living objects based on it.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&#34;deciding-between-inheritance-and-composition&#34;&gt;Deciding between inheritance and composition&lt;/h4&gt;
&lt;ol start=&#34;9&#34;&gt;
&lt;li&gt;Inheritance and composition are fundamentally code arrangement techniques where logic is distributed among various objects. With inheritance, objects are organized into a strict hierarchical structure and get automatic message delegation. With composition, objects are independent from each other but messages need to be manually delegated.&lt;/li&gt;
&lt;li&gt;In general, &amp;ldquo;&lt;a href=&#34;https://en.wikipedia.org/wiki/Composition_over_inheritance&#34;&gt;favor composition over inheritance&lt;/a&gt;&amp;rdquo;. Composition is lower cost (i.e. fewer dependencies) than inheritance in most circumstances where both could be used to solve a problem.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&#34;pros-and-cons-of-inheritance&#34;&gt;Pros and cons of inheritance&lt;/h4&gt;
&lt;ol start=&#34;11&#34;&gt;
&lt;li&gt;When properly applied, inheritance is excellent at producing code that is Reasonable, Usable and Exemplary.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inheritable code is Reasonable&lt;/strong&gt; because small changes in code can produce great changes in behavior. This is because code near the top of the hierarchy is defined once but used by all subclasses. Changing such code allows to alter the behavior of many subclasses.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inheritable code is Usable&lt;/strong&gt; because superclasses are literally designed to be easy to reuse. Inheritance hierarchies adhere to the &lt;a href=&#34;https://en.wikipedia.org/wiki/Open%E2%80%93closed_principle&#34;&gt;open-closed principle&lt;/a&gt;. It&amp;rsquo;s easy to extend the hierarchy by creating new subclasses without having to touch existing code, thus, reusing it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inheritable code is Exemplary&lt;/strong&gt; because it intrinsically provides a clear path to extend it. Even novice programmers won&amp;rsquo;t have a hard time creating new subclasses when the superclasses implement template methods and hooks which guide any extension efforts.&lt;/li&gt;
&lt;li&gt;One important disadvantage of inheritance is that the cost of mistakes is considerably high. Incorrect applications of inheritance are costly, whether it be that the wrong abstraction was created or that inheritance was just the wrong tool for the job altogether.&lt;/li&gt;
&lt;li&gt;Another disadvantage is that, for other contexts outside of the hierarchy, the ways in which it&amp;rsquo;s possible to interact with the hierarchy are limited. If the behavior defined within the hierarchy needs to be used, a subclass needs to be created. Other use cases may be incapable of tolerating that dependency.&lt;/li&gt;
&lt;li&gt;If you&amp;rsquo;re writing a framework or a library, this aspect becomes even more important. You can&amp;rsquo;t know all the scenarios in which your library will be used, and forcing users to create subclasses in order to reuse the logic defined in the hierarchy may be more than what they can afford.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&#34;pros-and-cons-of-composition&#34;&gt;Pros and cons of composition&lt;/h4&gt;
&lt;ol start=&#34;18&#34;&gt;
&lt;li&gt;&amp;ldquo;When using composition, the natural tendency is to create many small objects that contain straightforward responsibilities that are accessible through clearly defined interfaces&amp;rdquo;. &amp;ldquo;Composition results in applications built of simple, pluggable objects that are easy to extend and have a high tolerance for change&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;When properly applied, composition is excellent at producing code that is Transparent, Reasonable and Usable.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Composable code is Transparent&lt;/strong&gt; because small objects are easy to understand and changes have obvious effects. These objects also don&amp;rsquo;t necessarily form part of hierarchies, which means they are not susceptible to changes in superclasses.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Composable code is Reasonable&lt;/strong&gt; because its behavior is easy to extend by just implementing new objects that play the role of parts. All new parts need to do is implement the public interface that the container object already expects.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Composable code is Usable&lt;/strong&gt; because it&amp;rsquo;s made up of small independent objects. They don&amp;rsquo;t have any structural dependencies preventing them from being reused in different contexts, completely unrelated to the container or even the part role.&lt;/li&gt;
&lt;li&gt;One disadvantage of composition is the fact that it may be more difficult to understand how the whole application works. While the individual objects may be small and simple, how they come together to solve problems may not be.&lt;/li&gt;
&lt;li&gt;Another disadvantage is that objects need to delegate messages to each other manually, as opposed to inheritance where this happens automatically. This means that there is the explicit dependency of the container object having to know which messages to call on its parts.&lt;/li&gt;
&lt;li&gt;Composition excels at separating containers from parts and assembling such objects. However, it doesn&amp;rsquo;t have an answer for the scenario where it is necessary to handle a collection of types of parts that are very similar to each other. That&amp;rsquo;s where inheritance comes in.&lt;/li&gt;
&lt;li&gt;Use inheritance for &amp;ldquo;is a&amp;rdquo; relationships. Use duck types, interfaces, and behavior sharing via modules or mixins for &amp;ldquo;behaves like a&amp;rdquo; relationships. Use composition for &amp;ldquo;has a&amp;rdquo; relationships.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;chapter-9-designing-cost-effective-tests&#34;&gt;Chapter 9: Designing Cost-Effective Tests&lt;/h3&gt;
&lt;h4 id=&#34;the-benefits-of-testing&#34;&gt;The benefits of testing&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;The goal of design is to write code that is easy to change. In order to do that, we need good object-oriented design skills, good refactoring skills and good testing skills.&lt;/li&gt;
&lt;li&gt;Good object-oriented design skills are needed because badly designed code, by definition, is hard to change.&lt;/li&gt;
&lt;li&gt;Good refactoring skills are needed because design needs to be evolving constantly. As new requirements and new information about the domain become available, the code needs to adapt.&lt;/li&gt;
&lt;li&gt;Good testing skills are needed because high value, solid tests enable continuous refactoring without fear of breaking the code.&lt;/li&gt;
&lt;li&gt;Just like design, the true purpose of testing is to reduce costs. Tests do help reduce bugs, provide documentation, and improve the design; but those are only the means through which tests achieve their ultimate goal of reducing the cost of change.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tests help by finding bugs&lt;/strong&gt;: Test help expose bugs early in the process. Bugs are easier to find and cheaper to correct the closer in time we are to their introduction. Testing at the same time a feature is being implemented catches bugs before they go out the door. Bugs caught early are not given the chance to cause problems or have code depend on them.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tests help by supplying documentation&lt;/strong&gt;: Tests represent the best and most reliable documentation of the design. When static documents and memories get outdated and/or disappear, tests remain. Write tests that tell the story of how the code works.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tests help by deferring design decisions&lt;/strong&gt;: As a code base evolves, there will be spots in the code that are less than stellar. Spots which we&amp;rsquo;re not confident enough in to commit to a particular design. So we postpone making a decision and hack together a solution that works today. However, we know that it will need to be refactored to handle the requirements of tomorrow. These spots represent a lack of knowledge. Knowledge that the design is waiting for in order to improve. While waiting for that knowledge to come, we put the hack behind a clear, stable public interface and write our tests against that. In doing so, we&amp;rsquo;ll be free to refactor into a good design when the missing information arrives. Knowing that the tests have our backs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tests help by supporting abstractions&lt;/strong&gt;: &amp;ldquo;Good design naturally progresses toward small independent objects that rely on abstractions&amp;rdquo;. One disadvantage to this is that, while small independent objects are easy to understand by themselves, the behavior of the whole application, with all the little objects working together, becomes obscured. Tests solve that problem by highlighting the abstractions, their interfaces, how to work with them, and how they work together.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tests help by exposing design flaws&lt;/strong&gt;: If tests are hard to write, that&amp;rsquo;s the perfect indicator that the code under test is hard to reuse. Which indicates high coupling, which indicates increased costs of change. If testing an object requires a lot of setup and a lot of other objects, then it requires too much context and has too many dependencies.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&#34;what-when-and-how-to-test&#34;&gt;What, when and how to test&lt;/h4&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2024/02/key-takeaways-from-poodr/object-under-test-are-like-space-capsules.webp&#34; alt=&#34;A legend at the bottom shows solid blue and green lines labeled &amp;ldquo;depended upon by others&amp;rdquo;, and dashed green and red lines labeled &amp;ldquo;no dependents&amp;rdquo;. The main image is labeled &amp;ldquo;Origins of messages&amp;rdquo;. The left side is labeled &amp;ldquo;A. Received from others&amp;rdquo;, with three solid blue lines moving to the right, terminating at a conical object at the center. The cone is labeled &amp;ldquo;object under test&amp;rdquo;, and has a dotted gray line halfway up around the perimeter, with three dotted red lines branching off, looping around, and pointing back to the grey line. This is labeled &amp;ldquo;B. Sent to self&amp;rdquo;. Extending from the right side of the cone are three green lines, two solid and one dotted. They are labeled &amp;ldquo;C. Sent to others&amp;rdquo;.&#34;&gt;&lt;/p&gt;
&lt;ol start=&#34;11&#34;&gt;
&lt;li&gt;&amp;ldquo;One simple way to get better value from tests is to write fewer of them. The safest way to accomplish this is to test everything just once and in the proper place&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tests should focus only on the incoming messages&lt;/strong&gt; that are defined in each object&amp;rsquo;s public interface (&amp;ldquo;A&amp;rdquo; in the picture above). That is, the public methods. Public interfaces expose the services that a class offers its users. They are also stable, so depending on them is safe. Tests that cover public methods are resilient to refactorings and add value because they exercise objects in the same way that their users in application code do.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Never test private methods&lt;/strong&gt; (&amp;ldquo;B&amp;rdquo; in the picture above). They are meant to be used by the object internally. They change often and other objects should not depend on them because they will have to change with them. The same applies to tests. Tests that exercise private code break on every refactoring.&lt;/li&gt;
&lt;li&gt;An object&amp;rsquo;s test suite should &lt;strong&gt;never assert the return value of outgoing messages&lt;/strong&gt; that it sends to other objects (&amp;ldquo;C&amp;rdquo; in the picture above). These messages are part of the public interface of the receiver object, so the receiver&amp;rsquo;s test suite should be the one testing it.&lt;/li&gt;
&lt;li&gt;On the other hand, an object&amp;rsquo;s test suite should &lt;strong&gt;always assert that necessary outgoing messages are sent&lt;/strong&gt;, and with the correct parameters (&amp;ldquo;C&amp;rdquo; in the picture above).&lt;/li&gt;
&lt;li&gt;A &amp;ldquo;test of state&amp;rdquo; is a test that asserts the return value of a method.&lt;/li&gt;
&lt;li&gt;A &amp;ldquo;test of behavior&amp;rdquo; is a test that asserts whether the object under test calls a particular method on another object, how many times, and with what parameters.&lt;/li&gt;
&lt;li&gt;A &amp;ldquo;query&amp;rdquo; is a method call with no side effects that is only made to get some value back.&lt;/li&gt;
&lt;li&gt;A &amp;ldquo;command&amp;rdquo; is a method call that has side effects that are important to the overall application.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;All public methods should be covered by tests of state&lt;/strong&gt;. A test suite should only cover the public methods of its own object under test.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Queries should not be tested for state or behavior&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Commands should be tested for behavior&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Write tests first when it makes sense to do so. Writing tests before implementing the feature establishes an intention for the design from the beginning. Since tests are reused, they make sure the code to be written will have the bare minimum of reusability.&lt;/li&gt;
&lt;li&gt;Testing first is no silver bullet, though. Even though it helps steer the design in the right direction, by itself it won&amp;rsquo;t produce a well-designed application. Fundamental object-oriented design techniques still need to be applied.&lt;/li&gt;
&lt;li&gt;Well-designed applications are easy to change. Well-designed tests may never have to change. This is because they depend on abstractions and public interfaces, which are stable.&lt;/li&gt;
&lt;li&gt;Two major styles of testing exist: Behavior Driven Development and Test Driven Development.&lt;/li&gt;
&lt;li&gt;&amp;ldquo;BDD takes an outside-in approach, creating objects at the boundary of an application and working its way inward, mocking as necessary to supply as-yet-unwritten objects&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;&amp;ldquo;TDD takes an inside-out approach, usually starting with tests of domain objects and then reusing these newly created domain objects in the tests of adjacent layers of code&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Both styles can be followed to produce valuable tests&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2024/02/key-takeaways-from-poodr/bdd-and-tdd-should-be-viewed-as-on-a-continuum.webp&#34; alt=&#34;A blue spectrum line has two objects on either side. At the left end, labeled &amp;ldquo;More outside in BDD&amp;rdquo;, are three concentric green circles, with the outermost labeled &amp;ldquo;1&amp;rdquo;, the middle labeled &amp;ldquo;2&amp;rdquo;, and the innermost labeled &amp;ldquo;3&amp;rdquo;. Each label is outside of its circle, with an arrow pointing to the corresponding circle. At the right end, labeled &amp;ldquo;More inside out TDD&amp;rdquo;, are three identical concentric green circles, this time with the innermost labeled 1, the middle labeled 2, and the outer labeled 3. Each number label lies in the circle and points outward.&#34;&gt;&lt;/p&gt;
&lt;h4 id=&#34;writing-valuable-tests&#34;&gt;Writing valuable tests&lt;/h4&gt;
&lt;ol start=&#34;30&#34;&gt;
&lt;li&gt;&lt;strong&gt;Incoming messages (i.e. public methods) need to be covered by tests of state&lt;/strong&gt;. That is, the values that they return must be validated.&lt;/li&gt;
&lt;li&gt;Be on the lookout for public methods that don&amp;rsquo;t receive any calls. These are good candidates for deletion. If no other object calls it, then it needs to be private.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Objects should be tested in isolation&lt;/strong&gt;. When that&amp;rsquo;s not possible, there&amp;rsquo;s a problem with the design. It means that the object is too coupled to its collaborators and can&amp;rsquo;t be reused on its own. It needs to be refactored.&lt;/li&gt;
&lt;li&gt;It&amp;rsquo;s important that objects are tested in isolation because a test suite should care only about the one object that its testing. The other objects will be tested by their own test suites. Changes in an object should affect its own test suite, not that of other objects.&lt;/li&gt;
&lt;li&gt;When the object under test depends on another object in order to work properly, refactor into dependency injection and have the test provide the dependency that way.&lt;/li&gt;
&lt;li&gt;When using dependency injection, don&amp;rsquo;t pass in a concrete, &amp;ldquo;real&amp;rdquo; object in your tests. Instead, inject a &lt;strong&gt;test double&lt;/strong&gt; or &lt;strong&gt;mock&lt;/strong&gt; into the object under test.&lt;/li&gt;
&lt;li&gt;Dependency injection also hints at the emergence of a role, interface, or duck type. Instead of depending on a concrete class, refactor the object under test to depend on a role. The double or mock in the test suite will be one of the objects that play the collaborator role that the object under test expects.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Private methods and query method calls need not be tested at all&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Testing private methods is redundant because they are internal to the object under test and invoked by public methods, which already have tests.&lt;/li&gt;
&lt;li&gt;Private methods are also unstable. Not meant to be depended on because they change often. That will make for brittle tests.&lt;/li&gt;
&lt;li&gt;Private methods covered by tests may mislead others in thinking that the method is stable and, thus, dependable.&lt;/li&gt;
&lt;li&gt;Query method call results are not relevant to the overall application, only to the object under test. They are hidden within it. Also, the receiver of the query already includes tests for it, given that it is part of its public interface. So, they should be ignored by the test suite.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Command method calls do need to be covered by tests&lt;/strong&gt; in order to prove that they were called with the correct parameters. In other words, it is the responsibility of the object under test to send that message, so its test suite needs to prove it.&lt;/li&gt;
&lt;li&gt;Mocks are the way to test that command messages get sent. They help with tests of behavior. Using mocks injected into the object under test, a test case can validate that the method is called properly.&lt;/li&gt;
&lt;li&gt;Commands should be tested for behavior, not state. So, mocks should not be used for tests of state. That is, tests should not be concerned with asserting what they return. However, they can be configured to return some value, if the operation requires it.&lt;/li&gt;
&lt;li&gt;In dynamically typed languages that don&amp;rsquo;t have a compiler to do type checks, it is important to test objects for conformance with the public interfaces of their roles, and for proper integration with their inheritance hierarchies.&lt;/li&gt;
&lt;li&gt;&amp;ldquo;&lt;strong&gt;Tests should document the existence of roles, prove that each of their players behave correctly, and show that dependents interact with them appropriately&lt;/strong&gt;&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;Pragmatically, this means writing test cases that assert whether objects implement the specific messages defined in their roles&amp;rsquo; public interface and those that their superclasses expect from them.&lt;/li&gt;
&lt;li&gt;Multiple subclasses will undoubtedly share many of the same tests. In those cases, try to encapsulate the test cases into reusable components that every subclass&amp;rsquo;s test suite can invoke. Just like in application code, it&amp;rsquo;s better to avoid repetition.&lt;/li&gt;
&lt;li&gt;Testing abstract base classes can sometimes be challenging because they are not supposed to be instantiated. In some languages, it is downright impossible to instantiate classes marked as abstract. For these scenarios, a test-specific subclass can be created with minimal implementation that allows tests to exercise the base class.&lt;/li&gt;
&lt;li&gt;To avoid test brittleness, test doubles that play certain roles and inherit from superclasses should also be tested for conformance.&lt;/li&gt;
&lt;/ol&gt;

      </content>
    </entry>
  
    <entry>
      <title>Getting started with Java development using Visual Studio Code</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2023/03/getting-started-with-java-using-vscode/"/>
      <id>https://www.endpointdev.com/blog/2023/03/getting-started-with-java-using-vscode/</id>
      <published>2023-03-17T00:00:00+00:00</published>
      <author>
        <name>Trevor Slocum</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;img src=&#34;/blog/2023/03/getting-started-with-java-using-vscode/farm-sunset.webp&#34; alt=&#34;A fall sunset above an open plain: The yellow sun sets behind snowy mountains, casting orange glow on the left side of the sky, while the right side of the sky is dominated by dark storm clouds rising up and to the right in a dramatic diagonal. From the edge of the mountain towards the viewer spans a large brown plain. On it is a small shack and in the center of the image is a small, run-down tractor.&#34;&gt;&lt;br&gt;
Photo by Garrett Skinner, 2022&lt;/p&gt;
&lt;p&gt;Visual Studio Code is a free source-code editor available for Windows, macOS, and Linux. While it includes a lot of features out of the box, you will likely need to extend its functionality to suit your purpose for using it. There are many extensions available, each providing their own set of features and functions.&lt;/p&gt;
&lt;p&gt;In this guide we will install the &lt;a href=&#34;https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-pack&#34;&gt;Extension Pack for Java&lt;/a&gt;, which is a bundle of several extensions. Installing this extension pack will add the following features to Visual Studio Code:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Java language support&lt;/strong&gt; for parsing and highlighting our code&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Java test runner&lt;/strong&gt; for testing our code&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Java debugger&lt;/strong&gt; for debugging our code&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Java project manager&lt;/strong&gt; for managing resources related to our code&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Maven support&lt;/strong&gt; for building and packaging our code&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Note: This guide assumes you have already installed a Java Development Kit. If you haven&amp;rsquo;t done that yet, &lt;a href=&#34;https://openjdk.org&#34;&gt;OpenJDK&lt;/a&gt; is a great option.&lt;/p&gt;
&lt;h3 id=&#34;step-1-install-visual-studio-code&#34;&gt;Step 1: Install Visual Studio Code&lt;/h3&gt;
&lt;p&gt;If you haven&amp;rsquo;t yet, &lt;a href=&#34;https://code.visualstudio.com/download&#34;&gt;download Visual Studio Code&lt;/a&gt; and install it. If you need more help with this step, review the installation instructions linked on &lt;a href=&#34;https://code.visualstudio.com/docs/setup/setup-overview#_cross-platform&#34;&gt;this page&lt;/a&gt;. Click the link that applies to your operating system to access the installation instructions.&lt;/p&gt;
&lt;h3 id=&#34;step-2-install-the-extension-pack&#34;&gt;Step 2: Install the extension pack&lt;/h3&gt;
&lt;p&gt;Open Visual Studio Code and click on the extensions icon in the left sidebar, which looks like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2023/03/getting-started-with-java-using-vscode/vscode-extensions-icon.png&#34; alt=&#34;Three boxes stacked in an L shape, with a fourth box above and to the right of the empty space.&#34;&gt;&lt;/p&gt;
&lt;p&gt;This will take you to the extensions marketplace. Type &amp;ldquo;Extension Pack for Java&amp;rdquo; into the search bar and press enter. The extension we are looking for is authored by Microsoft. Once you find the extension pack in this list, click the &lt;strong&gt;Install&lt;/strong&gt; button.&lt;/p&gt;
&lt;h3 id=&#34;step-3-use-the-extension-pack&#34;&gt;Step 3: Use the extension pack&lt;/h3&gt;
&lt;p&gt;Once the installation is complete, a &amp;ldquo;Get Started with Java Development&amp;rdquo; screen is displayed. The first item on this screen is &amp;ldquo;Get your runtime ready&amp;rdquo; with an &amp;ldquo;Install JDK&amp;rdquo; button. We already have a JDK installed, so we can skip this. The remaining items on the screen are helpful to review, as they give a brief overview of the features we have just added to our editor.&lt;/p&gt;
&lt;p&gt;To ensure our JDK and extension pack are working together correctly, click &lt;strong&gt;File &amp;gt; New file&amp;hellip;&lt;/strong&gt;. You will be prompted to choose a file type. Enter &amp;ldquo;Java&amp;rdquo; and select &amp;ldquo;Java Class&amp;rdquo;. You will be prompted for a file name. Enter &lt;code&gt;HelloWorld.java&lt;/code&gt;. You will then be prompted to choose where to save the file. Create a new directory somewhere, and save the file inside of the newly created directory.&lt;/p&gt;
&lt;p&gt;The file &lt;code&gt;HelloWorld.java&lt;/code&gt; is now open in our editor. Add the following text to the file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;HelloWorld&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;{&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;static&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;void&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;main&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;(String&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;args[])&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;    &lt;/span&gt;{&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;        &lt;/span&gt;System.&lt;span style=&#34;color:#369&#34;&gt;out&lt;/span&gt;.&lt;span style=&#34;color:#369&#34;&gt;println&lt;/span&gt;(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Hello, world!&amp;#34;&lt;/span&gt;);&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;    &lt;/span&gt;}&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Save the file, then click the play icon at the top right of the window. This is the &lt;strong&gt;Run&lt;/strong&gt; button. By default, it will run your Java application normally.  You can also click the dropdown next to the icon and select &lt;strong&gt;Debug&lt;/strong&gt; to run your Java application with the debugger attached, which is very helpful when problem-solving.&lt;/p&gt;
&lt;p&gt;When you click the &lt;strong&gt;Run&lt;/strong&gt; button, assuming everything is set up properly, your code will be compiled and executed. A terminal window will be opened, where your program may take in user input and/or write output. In this terminal window, the text &amp;ldquo;Hello, world!&amp;rdquo; will be written by the program.&lt;/p&gt;
&lt;p&gt;If you are seeing the expected behavior, then congratulations are in order! You have just finished setting up Visual Studio Code for Java development.&lt;/p&gt;
&lt;p&gt;If you are not seeing the expected behavior, restart from the beginning and confirm that you have followed each step correctly.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;For more guides and a deeper dive on the content in this one, see VS Code&amp;rsquo;s &lt;a href=&#34;https://code.visualstudio.com/docs/java/java-tutorial&#34;&gt;Java docs&lt;/a&gt;.&lt;/p&gt;&lt;/blockquote&gt;

      </content>
    </entry>
  
    <entry>
      <title>Programming the Intel NDP in 1983</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2023/03/programming-the-intel-ndp-in-1983/"/>
      <id>https://www.endpointdev.com/blog/2023/03/programming-the-intel-ndp-in-1983/</id>
      <published>2023-03-12T00:00:00+00:00</published>
      <author>
        <name>Jeremy Freeman</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;img src=&#34;/blog/2023/03/programming-the-intel-ndp-in-1983/20230205-163937-sm.webp&#34; alt=&#34;Photograph of brick building fronted by a metal staircase leading to the roof, gated by a full-size metal door that would be trivially easy to climb around&#34;&gt;&lt;/p&gt;
&lt;!-- Photo by Jon Jensen --&gt;
&lt;h3 id=&#34;the-beginning&#34;&gt;The Beginning&lt;/h3&gt;
&lt;p&gt;I graduated from St. John’s College in Annapolis in 1980. It was an intensive four-year education in math, science, language, poetry, and philosophy. Two years later, I took four computer classes at a community college, and got my first IT job in 1983 at the beginning of the personal computer revolution.&lt;/p&gt;
&lt;p&gt;There were two of us: Steve, the owner of the company, and I, working literally in his garage. I was just a fledgling, uncertain and doubtful of my own ability. The IBM PC had come out the summer before, a device IBM seemed to regard as little more than a toy. Steve was by profession a physicist.&lt;/p&gt;
&lt;p&gt;Steve noticed the PC had an empty socket on the motherboard, next to the Intel 8088 CPU. He guessed it was for Intel’s 8087 Numeric Data Processor (NDP), also known as a math co-processor, that was designed as a companion to Intel’s 8088/86.&lt;/p&gt;
&lt;p&gt;The CPU could operate perfectly well on its own, but if the NDP was installed, they would both read the same code stream. The CPU would ignore NDP instructions and let the NDP execute them. The NDP would ignore non-NDP instructions and let the CPU execute them. While the 8088/86 is running code, it can’t do anything else. With the NDP, true parallel processing is possible.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2023/03/programming-the-intel-ndp-in-1983/8087_with_Nickel_003.webp&#34; alt=&#34;Intel 8087 chip imprinted with part numbers and &amp;ldquo;© Intel &amp;lsquo;80 &amp;lsquo;81&amp;rdquo; alongside a U.S. 5¢ piece (nickel) for scale&#34;&gt;&lt;/p&gt;
&lt;h3 id=&#34;the-plan&#34;&gt;The Plan&lt;/h3&gt;
&lt;p&gt;IBM selected Microsoft to produce its systems software: operating system, compilers, linkers, libraries, macro assembler, etc. Microsoft not only ignored the 8087, it devised a floating-point format incompatible with it. Steve had signed a contract with Intel to be the exclusive distributor of the NDP for a period of years—Intel wasn’t selling any to speak of, so why not?&lt;/p&gt;
&lt;p&gt;Steve’s business plan was to sell a package: an 8087 chip and modifications to IBM (Microsoft) systems software that builds programs (BASIC compiler, FORTRAN compiler, Pascal compiler, and Macro Assembler) so they can generate code for it, and libraries in which the math routines use the 8087 instead of complex, slow math routines in the CPU.&lt;/p&gt;
&lt;p&gt;With the package we created, math-intensive applications would be sped up by anywhere from 2–3 times up to 40 times. The financial advantage to those who wrote their own applications in, say, BASIC, and used our package was compelling.&lt;/p&gt;
&lt;h3 id=&#34;the-platform&#34;&gt;The Platform&lt;/h3&gt;
&lt;p&gt;The computer I was given was a standard IBM PC of early 1983: an Intel 8088 microprocessor running at 4.77 MHz, two 360 KB 5¼-inch full-height floppy disks, 640 KB of RAM, a monochrome monitor, five expansion slots, and PC-DOS 1.1.&lt;/p&gt;
&lt;p&gt;The 8088&amp;rsquo;s 16-bit architecture internally was essentially the same as the 8086, with the difference that it used an 8-bit bus and was cheaper.&lt;/p&gt;
&lt;p&gt;IBM designed an open architecture. In other words, it designed the PC to use all off-the-shelf equipment from other manufacturers, not IBM: chips from Intel, systems software from Microsoft, other chips from elsewhere. This was to be my saving grace, as we shall see below.&lt;/p&gt;
&lt;h3 id=&#34;two-problems-two-solutions-one-package&#34;&gt;Two Problems, Two Solutions, one Package&lt;/h3&gt;
&lt;p&gt;Our guiding design idea was that our users could develop programs in the way they were accustomed to. They could, for example, use the BASIC Interpreter that came as part of the PC ROM BIOS for an iterative, live mode of development. When satisfied, they could save the resulting text file, build it with our patched version of the BASIC compiler and link it with our libraries. They would have bought an 8087 from us, plugged it into the coprocessor slot, and then could launch their executable.&lt;/p&gt;
&lt;p&gt;One customer, for example, was in Kansas. They were commodity traders who had an algorithm written in BASIC. It would take data from all commodity trades during the day and at the end of the day, run the data through their algorithm, and use the result to place trades first thing the next morning. It took 5–6 hours to run, and they got home to their families at 10 or 11 o&amp;rsquo;clock at night.&lt;/p&gt;
&lt;p&gt;With our software modifications and the 8087, it took only about 2 hours to run, so they were home in time for dinner.&lt;/p&gt;
&lt;h3 id=&#34;too-naive-to-fail&#34;&gt;Too Naive To Fail&lt;/h3&gt;
&lt;p&gt;When I first sat down at my PC to work, I didn&amp;rsquo;t know how to turn it on.&lt;/p&gt;
&lt;p&gt;To do my job I had to program in Intel 16-bit assembly language. I not only had never seen any assembly language, I had never seen any computer language before besides FORTRAN and PL/I.&lt;/p&gt;
&lt;p&gt;I was somewhat like the bumblebee. Mathematics has proven that the bumblebee is aerodynamically unable to fly. The bee, however, does not know math, so it flies anyway.&lt;/p&gt;
&lt;p&gt;I sat at my desk and grappled with the complexity before me. At the end of the first week, I felt so hopeless and lost that I thought I would speak to Steve and say, &amp;ldquo;Steve, when we interviewed I misled you. I pretended I am not an idiot. Let&amp;rsquo;s say no more about it. I will slink away silently. You don&amp;rsquo;t even have to pay me.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Then I thought, &amp;ldquo;Steve is a pretty smart man. I will leave it up to him. If he thinks I should leave, he can fire me. Meanwhile, I will stay here and give it everything I&amp;rsquo;ve got.&amp;rdquo;&lt;/p&gt;
&lt;h3 id=&#34;my-tasks&#34;&gt;My Tasks&lt;/h3&gt;
&lt;p&gt;The 8087 had a stack of eight ten-byte floating point registers. It could load and save either four-byte (single) or eight-byte (double) floating point. Steve had written a disassembler using the BASIC interpreter, so I had a printout of the code in the BASIC library. It did not show the source code, but it did show labels of routines and variables.&lt;/p&gt;
&lt;p&gt;Steve had a list of the names of all the math routines in the library. I had to edit each math routine so that it would perform the same functionality as the original, but using the 8087.&lt;/p&gt;
&lt;p&gt;A second requirement had to do with the floating-point format of constants in the source code. The Microsoft compilers generated them in MS-Binary floating point, in the structure &lt;em&gt;exponent + sign bit + mantissa&lt;/em&gt; (or significand). The 8087 used IEEE floating-point, which was structured &lt;em&gt;sign bit + exponent + mantissa&lt;/em&gt;. We patched the compilers so that at the place they would generate floating-point constants, they would generate IEEE-format constants instead.&lt;/p&gt;
&lt;h3 id=&#34;my-advantages&#34;&gt;My Advantages&lt;/h3&gt;
&lt;p&gt;IBM shipped each PC with two ring binders. One explained the BASIC language as implemented in the ROM BIOS. The other was a handbook for the PC, which told everything a person could possibly want to know about the machine, including a printout of the ROM BIOS assembly language source code at the end of the manual: page after page of working code in Intel 8088/86 assembly language.&lt;/p&gt;
&lt;p&gt;I also had an Intel product manual on the 8088/86, including a section on the 8087. That was some of the most dense specifications on the planet, but it contained all the operations and registers, both for the CPU and the NDP.&lt;/p&gt;
&lt;p&gt;Another advantage I had was the debugger, &lt;code&gt;DEBUG.COM&lt;/code&gt;. I would edit a math routine to replace the operations in the CPU with a few simple opcodes for the NDP, since it did all its operations internally, allowing the programmer to use a few NDP instructions to carry out the functionality. I would then use the librarian to replace the given routine in the library with my routine, write a test program in BASIC and build it. Then I would load the executable in the debugger and step through the code. That had two big advantages: One, I got to see the assembly language in action, learning more than a book could ever teach me. Two, I verified that the code actually did what I thought it did. The code we shipped rarely had a bug in it and those were usually minor. Except one.&lt;/p&gt;
&lt;h3 id=&#34;whoops&#34;&gt;Whoops!&lt;/h3&gt;
&lt;p&gt;There was one major bug: error handling. I became aware of it when a customer called in about the failure of our code to catch a division by zero. Some research showed that the first 1024 bytes of RAM contained the Interrupt Vector Table (IVT), 256 four-byte entries containing the segment (two bytes) and offset (two bytes) of the Interrupt Service Routine (ISR). Interrupt INT 0 contained the address of the CPU divide by zero ISR.&lt;/p&gt;
&lt;p&gt;Our software, since it did not use the CPU for division, did not catch a division by zero. This error would generate an IRQ (interrupt request) 13 which Intel had reserved for the math coprocessor. In Intel&amp;rsquo;s product spec, they marked IRQ 13 as Reserved. The IBM engineers, however, had always seen the word &amp;ldquo;Reserved&amp;rdquo; used for things reserved by IBM, so they used IRQ 13 for something else. So I had to write an ISR that would take over the IRQ 13 entry in the IVT, check to see if there was an error in the NDP, and if so, handle it. Otherwise, pass control onto the original ISR.&lt;/p&gt;
&lt;p&gt;Eventually there was a DOS routine to create a chain of ISRs, each of which would determine if the interrupt was something it should handle or else pass it on to the next ISR in the chain. Good cyber-citizens would play nice, and use the DOS routine to get their place in the chain.&lt;/p&gt;
&lt;h3 id=&#34;they-think-they-didnt-get-the-right-test&#34;&gt;They Think They Didn&amp;rsquo;t Get the Right Test&lt;/h3&gt;
&lt;p&gt;The company expanded, leaving the garage far behind and moving into a brick-and-mortar building, one of many at a defunct rope-factory. It employed by this time 40–50 people.&lt;/p&gt;
&lt;p&gt;Intel had marched forward, producing the 80286 (with its companion 80287) and the 80386 (with its companion 80387).&lt;/p&gt;
&lt;p&gt;Steve asked me to write a test for the math chips. I wrote it in C and Intel 16-bit Assembler. The test performed the four standard arithmetic operations—add, subtract, multiply, divide—and also special operations the NDP was capable of, like exponents, logarithms, square roots, trigonometric functions, etc.&lt;/p&gt;
&lt;p&gt;The code tested whether the answers calculated by the chip came out within a narrow range, since it is not possible to test for an exact result with floating-point numbers that can be &amp;ldquo;right&amp;rdquo; but differ in the least significant bits of the mantissa. I named it 87TEST.EXE. It shipped with every NDP we sold: 8087, 80287, 80387.&lt;/p&gt;
&lt;p&gt;We began getting calls from customers who had bought an 80287 or 80387, complaining that they had received the wrong test. Someone would have to explain that the same executable with the same code tested all variants of the NDP. These calls were costing the company money to reassure the customers, so I wrote a new version of the test which determined which CPU and which NDP it was running on.&lt;/p&gt;
&lt;p&gt;The OS was MS-DOS, a character-based system. I used the advanced ROM-BIOS character set to &amp;ldquo;draw&amp;rdquo; images representing both chips, each casting a &amp;ldquo;shadow&amp;rdquo; to seem three-dimensional, and each labeled with the number of the chip. For example, one &amp;ldquo;image&amp;rdquo; could be labeled 80286 and the other 80287.&lt;/p&gt;
&lt;p&gt;In order to gain customer confidence these had to be accurate. Later models of these chips had instructions whereby you could ask the chip, &amp;ldquo;What are you?&amp;rdquo; and it would return its version number. Earlier variants did not have these instructions, but for the most part I found characteristics I could test for to determine the version.&lt;/p&gt;
&lt;p&gt;With the 8088 and 8086, however, they both used exactly the same instruction set. I racked my brain to find a difference and could not. I turned to my dog-eared copy of the 8088/86 Intel product manual and pored through it. Finally, I found a difference: the 8088 had a four-byte prefetch queue and the 8086 had a six-byte one.&lt;/p&gt;
&lt;p&gt;I solved the problem by writing self-modifying code, which was a huge no-no according to Intel. It used 6 bytes in the code segment, with a constant defined in the 6th byte. I cleared the prefetch queue by doing a jump to the lead instruction. Thus, the prefetch queue would contain four bytes and the sixth byte would still be in memory (8088) or all six bytes would be in the pre-fetch queue (8086). The first instruction moved a different constant into the 6th byte. In an 8088, the 6th byte in memory would be changed and in the 8086 the 6th byte would be modified in the prefetch queue and remain untouched in memory. Then I would test that 6th byte: changed = 8088 and unchanged = 8086.&lt;/p&gt;
&lt;p&gt;At last my search to correctly identify the CPU and its companion NDP was over. The test program was complete.&lt;/p&gt;
&lt;h3 id=&#34;summary&#34;&gt;Summary&lt;/h3&gt;
&lt;p&gt;I had to make do with the Intel product manual, the IBM PC manual, the IBM debugger, and tools my own company had created. Google did not exist, and for that matter, the Internet as we know it today did not exist. There was no plethora of instructional videos, as are widely available today.&lt;/p&gt;
&lt;p&gt;Success required above all persistence and resourcefulness. I do not deny that native ability and education are important, but problem-solving in the IT world succeeds when we accept a challenge and strive to achieve what we never thought possible.&lt;/p&gt;
&lt;p&gt;We adapt, we improvise, we overcome. Failure is not an option!&lt;/p&gt;
&lt;h3 id=&#34;references&#34;&gt;References&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/IBM_Personal_Computer&#34;&gt;IBM PC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://philipstorr.id.au/pcbook/book2/irq.htm&#34;&gt;PC Hardware&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

      </content>
    </entry>
  
    <entry>
      <title>Fun with Rational Numbers</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2022/02/fun-with-rational-numbers/"/>
      <id>https://www.endpointdev.com/blog/2022/02/fun-with-rational-numbers/</id>
      <published>2022-02-11T00:00:00+00:00</published>
      <author>
        <name>Darius Clynes</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;img src=&#34;/blog/2022/02/fun-with-rational-numbers/20210428_210604-sm.webp&#34; alt=&#34;Rock hillside with trees&#34;&gt;&lt;/p&gt;
&lt;!-- Photo by Zed Jensen --&gt;
&lt;p&gt;So, you say you adored learning long division in elementary school? Well here we are revisiting that wonderful activity we have missed so much: fabulous magical moments like dividing 1.0 by 7. The especially tedious exercise of dragging over one more of the endless 0’s and seeing how many 7’s would fit into that woefully large remainder. Soon the delight mounts as you desperately hope the next digit will be the last and you discover that beautiful 1 as a remainder.&lt;/p&gt;
&lt;p&gt;Undoubtedly you have wondered, like I have, what would happen if you divided 1.0 by 19? Would it repeat after only 8 digits? How many digits would it really take before it repeats?&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s exactly how I stumbled into the wonderful world of rational numbers. There I was, wondering and wandering along the gloomy Belgian beach — the tide way out as far as you could see — in the winter wind, and I couldn’t stop thinking how long it would take for that mantissa to repeat. I had actually already tried 1.0 over 19. Finally, on that miserable day, I got the courage to divide 1 by 23.&lt;/p&gt;
&lt;p&gt;Fortunately for me, I wasn’t alone, and I was able to enlist, coax, oblige, implore the help of baffled little Susan, my daughter who was 7 years old at the time. Her job would be to write out the digits in the sand as I discovered them, yelling them out to her, getting farther and farther away from her as the calculation got longer and longer. Finally, shrieking in the wind with delight as I hit 1 as the remainder, Susan seemed confused but amused.&lt;/p&gt;
&lt;p&gt;Well, it was so much fun I decided to share my excitement and enthusiasm while at the same time bringing attention to these often overlooked treasure chests of digits.&lt;/p&gt;
&lt;p&gt;After my satisfaction in coming up with the answer, the pleasure of which clearly eluded my daughter who was overjoyed that this exercise was over, I decided to write a computer program to discover how these numbers might turn out as the values became larger.&lt;/p&gt;
&lt;h3 id=&#34;numbers-as-music&#34;&gt;Numbers as music&lt;/h3&gt;
&lt;p&gt;As a composer, I thought it might be nice to portray the results in a sound representation. My first attempt was to use a fundamental sine wave and have each digit represent the number of overtones in the resulting sound. So the fundamental stayed constant, while the overtones quivered above not unlike Mongolian, Sardinian, or Tibetan Buddhist monk throat singing.&lt;/p&gt;
&lt;p&gt;The digit 0 became the lonely fundamental, the digit 1 became the first harmonic an octave above, 2 was an octave and a fifth, and so on, until 9 the 10th harmonic. For timing I added varying amounts of delay between the sound events proportional to the digits calculated.&lt;/p&gt;
&lt;p&gt;The first incarnation of my computer program was in 1999 in the programming language C, creating a sound wave file as an output. It created an interesting harmonic whistling kind of wind chime not unlike serrated plastic tubes that you swing around your head — the faster you swing, the higher the harmonics generated.&lt;/p&gt;
&lt;p&gt;Later, I thought of applying the repeating nature of the calculated series of numbers to create a periodic waveform itself, instead of using sine waves. Seems like an obvious path to explore, doesn&amp;rsquo;t it? I still have to try that sound experiment some day.&lt;/p&gt;
&lt;h3 id=&#34;visualizing-numbers&#34;&gt;Visualizing numbers&lt;/h3&gt;
&lt;p&gt;However, before continuing with sound, I did create a simple visual representation in JavaScript by making gradient-filled colored rectangles overlaid by arcs and line segments.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s look at my program showing results for some interesting numbers.&lt;/p&gt;
&lt;p&gt;For example, here is a screenshot of what the reciprocal of 7 (1 divided by 7) looks like in my little program:&lt;/p&gt;
&lt;h4 id=&#34;17&#34;&gt;1/7&lt;/h4&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2022/02/fun-with-rational-numbers/7.webp&#34; alt=&#34;Visual representation of 1 divided by 7&#34;&gt;&lt;/p&gt;
&lt;h4 id=&#34;113&#34;&gt;1/13&lt;/h4&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2022/02/fun-with-rational-numbers/13.webp&#34; alt=&#34;Visual representation of 1 divided by 13&#34;&gt;&lt;/p&gt;
&lt;h4 id=&#34;1523&#34;&gt;1/523&lt;/h4&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2022/02/fun-with-rational-numbers/523.webp&#34; alt=&#34;Visual representation of 1 divided by 523&#34;&gt;&lt;/p&gt;
&lt;h3 id=&#34;a-demo&#34;&gt;A demo&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;/blog/2022/02/fun-with-rational-numbers/demo/&#34; target=&#34;_blank&#34;&gt;Click here to try it out for yourself!&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And make sure your sound is turned up a bit.&lt;/p&gt;
&lt;p&gt;Two types of sounds are generated: one, by ‘subtractive’ synthesis, using filtered white noise, and the second, by just using a sampled plucked string sound. The first one, whistle-like, starts with white noise bandpass filtered with the center frequency set at the notes of a piano and the bandwidth or Q of each filter set at one semitone. This produces airy, whispery, wind-like flute sounds.&lt;/p&gt;
&lt;h3 id=&#34;repeating-digits&#34;&gt;Repeating digits&lt;/h3&gt;
&lt;p&gt;By the way, it turns out that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1/19 produces 18 digits before repeating&lt;/li&gt;
&lt;li&gt;1/23 produces 22&lt;/li&gt;
&lt;li&gt;1/29 ⇒ 28&lt;/li&gt;
&lt;li&gt;1/263 ⇒ 262 repeating digits, etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Nice pattern, right? Seems like you can safely say that a reciprocal will never have a mantissa with more digits than the number itself.&lt;/p&gt;
&lt;h3 id=&#34;related-resources&#34;&gt;Related resources&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API#guides_and_tutorials&#34;&gt;Web Audio API&lt;/a&gt; components allow you to construct ‘circuits’ like you would with wires on an analog synthesizer, plugging outputs of one component into another, by ‘connecting’ modules.&lt;/li&gt;
&lt;li&gt;Olivia Jack&amp;rsquo;s work:
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://ojack.xyz/PIXELSYNTH/&#34;&gt;PIXELSYNTH&lt;/a&gt; is a very nice version of this concept.&lt;/li&gt;
&lt;li&gt;Her &lt;a href=&#34;https://hydra.ojack.xyz/&#34;&gt;main website&lt;/a&gt; has other very nice visual coding experiments.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

      </content>
    </entry>
  
    <entry>
      <title>On the Importance of Explicitly Converting Strings to Numbers</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2022/01/string-number-conversion/"/>
      <id>https://www.endpointdev.com/blog/2022/01/string-number-conversion/</id>
      <published>2022-01-11T00:00:00+00:00</published>
      <author>
        <name>Jeff Laughlin</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;img src=&#34;/blog/2022/01/string-number-conversion/20220111-024957-sm.jpg&#34; alt=&#34;Wall with tiles of 4 colors in a pattern&#34;&gt;&lt;/p&gt;
&lt;!-- Photo by Jon Jensen --&gt;
&lt;p&gt;Recently a valued colleague approached me with a JavaScript problem. This individual is new to programming and is working on a self-taught course.&lt;/p&gt;
&lt;p&gt;The assignment was fairly simple: Take a list of space-delimited integers and find the maximum and minimum values. If you are an experienced developer you can probably already guess where this is going. His code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;function&lt;/span&gt; highAndLow(numbers) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; myArr = numbers.split(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;let&lt;/span&gt; lowNum = myArr[&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;let&lt;/span&gt; highNum = myArr[&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;let&lt;/span&gt; i = &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt;; i &amp;lt; myArr.length; i++) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; (myArr[i] &amp;gt; highNum) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      highNum = myArr[i];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    } &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; (myArr[i] &amp;lt; lowNum) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      lowNum = myArr[i];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; highNum + &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39; &amp;#39;&lt;/span&gt; + lowNum;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;console.log(highAndLow(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;8 3 -5 42 -1 0 0 -9 4 7 4 -4&amp;#34;&lt;/span&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This produced the output:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;8 -1&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;These are clearly not the maximum or minimum values.&lt;/p&gt;
&lt;p&gt;After looking at it for a few moments I recognized a classic JavaScript pitfall: failure to explicitly convert stringy numbers to actual number types.&lt;/p&gt;
&lt;p&gt;You see, JavaScript tries to be clever. JavaScript tries to get it right. JavaScript tries to say “the thing you are doing looks like something that you would do with numbers so I’m going to automatically convert these stringy numbers to number-numbers for you.”&lt;/p&gt;
&lt;p&gt;The problem is that JavaScript is &lt;em&gt;not&lt;/em&gt; clever; it is in fact very dumb about this. The further problem is when developers come to trust and rely on automatic conversion. Careers have been ruined that way.&lt;/p&gt;
&lt;p&gt;In this case the naive programmer would say “Well, I’m comparing the things with a mathematical operator (&lt;code&gt;&amp;lt;&lt;/code&gt; and &lt;code&gt;&amp;gt;&lt;/code&gt;) so JavaScript should treat the values as numbers, right?” Wrong. JavaScript compares them alphabetically, &lt;strong&gt;not&lt;/strong&gt; numerically. Except that even the “alphabetical” comparison kind of sucks but that’s another topic. JavaScript doesn&amp;rsquo;t even attempt to convert to numbers in this case.&lt;/p&gt;
&lt;p&gt;Repeat after me:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Always explicitly convert stringy numbers to actual numbers even if the language claims to do it automatically.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I don’t care if it’s JavaScript, Perl, some fancy Python package, it doesn’t matter.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Do not trust automatic type conversion.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You will get it wrong. It will get it wrong. There will be tears.&lt;/p&gt;
&lt;p&gt;Fixing this program is as simple as changing one line to explicitly convert the numbers from strings.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; myArr = numbers.split(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;).map(n =&amp;gt; &lt;span style=&#34;color:#038&#34;&gt;Number&lt;/span&gt;.&lt;span style=&#34;color:#038&#34;&gt;parseInt&lt;/span&gt;(n, &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;10&lt;/span&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;Number.parseInt(n, 10)&lt;/code&gt; is the “one true way” to turn a string-number into a number-number in JavaScript. &lt;strong&gt;Never&lt;/strong&gt; omit the &lt;code&gt;10&lt;/code&gt;; it is technically optional but you will regret it if you omit it, trust me. If you are reading base 10 numbers, tell JavaScript so explicitly. Otherwise it will again try to be clever but be not-clever and probably screw up the conversion by guessing the wrong radix.&lt;/p&gt;
&lt;p&gt;It’s good that the developer caught this error visually, also, because they did not include a unit test. Errors like this slip through the cracks all. the. time.&lt;/p&gt;
&lt;p&gt;Even TypeScript would not catch this. This function is perfectly legal TypeScript. There’s nothing illegal about comparing strings with &lt;code&gt;&amp;lt;&lt;/code&gt; or &lt;code&gt;&amp;gt;&lt;/code&gt;. TypeScript could only catch this if the developer provided additional type information up front, for example:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2022/01/string-number-conversion/string-number-conversion-1.png&#34; alt=&#34;TypeScript example of mismatched string and number types&#34;&gt;&lt;/p&gt;
&lt;p&gt;Now that we’ve &lt;em&gt;told&lt;/em&gt; the compiler “This is a string” and “This is a number”, now it can helpfully tell us “Hey, you’re trying to mix strings and numbers in a not-good way”.&lt;/p&gt;
&lt;p&gt;So it all comes back to the mantra of “Always explicitly convert strings to numbers. Always.” And if you&amp;rsquo;re bothering to use TypeScript, go the extra step and actually tell it what the types are. Don&amp;rsquo;t make it guess; it might guess wrong. Explicit is better than implicit.&lt;/p&gt;
&lt;p&gt;Some things never change.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Engineering Is Not Just About the Cool Stacks</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2021/05/engineering-is-not-just-about-the-cool-stacks/"/>
      <id>https://www.endpointdev.com/blog/2021/05/engineering-is-not-just-about-the-cool-stacks/</id>
      <published>2021-05-25T00:00:00+00:00</published>
      <author>
        <name>Afif Sohaili</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;img src=&#34;/blog/2021/05/engineering-is-not-just-about-the-cool-stacks/scaffolding.jpg&#34; alt=&#34;&#34;&gt;
&lt;a href=&#34;https://unsplash.com/photos/P6bOdzRk7TY&#34;&gt;Photo&lt;/a&gt; by &lt;a href=&#34;https://unsplash.com/@gett_urban&#34;&gt;Di&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;As a developer, I love finding new shiny pieces of tech that can help me develop web applications better. To me, it is one of the best parts of the job: Pick up a new programming language, a new database, a new standard, etc., and build cool things with it. But recently, I had the chance to reflect on my experience working on a boring stack at one of my previous workplaces, and it was actually a lot better than I expected.&lt;/p&gt;
&lt;h3 id=&#34;my-journey&#34;&gt;My journey&lt;/h3&gt;
&lt;p&gt;I used to work at a company where the teams are free to decide the tech stacks that best fit their requirements, so a wide range of modern tools were used there to solve the problems at hand. Within just 2 years of joining the company, I switched teams four times and touched everything from Java, Scala, Akka, Terraform, AWS ECS, Serverless, API Gateway, AWS Lambda, AWS DynamoDB, React, Gatsby, Vue, Nuxt, TypeScript, Flowtype, and many other tools that really helped advance my technical skills.&lt;/p&gt;
&lt;p&gt;But in late 2018, my manager invited me to assist a “less popular” team in the company. The team handled a myriad of complex products that are quite old. The team’s tech stack was not the shiniest compared to the other teams in the company; the products are developed using Java, a language I generally do not prefer due to its verbosity. We just shipped JAR files to the platform’s marketplace, so there were no web services to maintain and hence it didn’t challenge or sharpen our operations skills. The frontend JavaScript code was largely built with jQuery as it came bundled with the platform we are building on top of.&lt;/p&gt;
&lt;p&gt;As a developer who loves shiny tools, this team should have been a dreadful one to be in. But to my surprise, as I reflect upon it, it was actually the team that gave me the highest work satisfaction. It was satisfying because there were a lot of problems to solve, and most of the time the harder problems to solve are not the tech stack: &lt;strong&gt;the apps work, and customers are paying&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Instead of talking about moving from Java to Kotlin or from jQuery to React, our team spent the time brainstorming ideas on how to increase code quality, how to ensure discipline and follow good principles when crafting software, how to improve our developers’ workflow and processes, and how to best share knowledge and contexts that we had just acquired for future team members. Each problem solved gave me that dopamine boost that made me feel good.&lt;/p&gt;
&lt;p&gt;Below are some of the things we did to solve these problems.&lt;/p&gt;
&lt;h3 id=&#34;problem-1-code-quality&#34;&gt;Problem #1: Code quality&lt;/h3&gt;
&lt;p&gt;The products the team were handling had been suffering from some quality degradations in recent years, and these ultimately led to more bugs and regressions, which then leads to an increase in customer complaints, and that leads to us working under pressure, which then leads to even more quality degradations, and the vicious cycle repeats.&lt;/p&gt;
&lt;p&gt;When this started to happen, what did we do?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;We slowed things down.&lt;/strong&gt; Instead of having individual engineers work on multiple tickets in parallel, we held more pair programming sessions and reduced the number of tickets in progress to help incorporate collaboration earlier and gain feedbacks on the implementation strategy sooner. At the same time, pairing sessions also helped get the newer engineers up to speed faster. We introduced more quality gates for pull requests to be able to be merged into &lt;code&gt;main&lt;/code&gt;. We agreed as a team to scrutinize them harder, e.g. if you do not have tests among the changes, just consider the pull request rejected. We also required all team members to approve the changes. We worked with product managers to slow down shipping new features and instead having more bugs fixed. Hence, the health of the codebases got better and better and the products got more and more stable each day.&lt;/p&gt;
&lt;p&gt;We also held a brown-bag meeting reinforcing SOLID design principles to everyone in the team. Knowledge sharing like this helps bring everyone onto the same page while pairing and reduce the long discussion threads on pull requests.&lt;/p&gt;
&lt;h3 id=&#34;problem-2-context-sharing&#34;&gt;Problem #2: Context-sharing&lt;/h3&gt;
&lt;p&gt;Members of a team come and go, and that is true for all teams. Complex apps like the ones we were maintaining are usually full of legacy decisions that the newer team members will not have the knowledge of if no deliberate efforts were made to ensure that those contexts get shared. So, we took steps to mitigate this by including the contexts in commit messages. We also encouraged writing our findings in the Jira tickets and in the pull request descriptions on GitHub, but we preferred Git commit messages for documenting decisions related to the commit, because Git is the system that is least likely to change. We might switch from Jira or from GitHub to some similar services, so contexts would be lost when that happens, but it is very unlikely that we would switch from Git for version control.&lt;/p&gt;
&lt;p&gt;We also started a knowledgebase to contain information that should be shared within the team, including onboarding instructions, development gotchas, legacy contexts, etc. This helps distribute the knowledge to everyone and reduce blockers on specific team members. We also made a habit of documenting a discussion that happens offline, often in our internal communication channels or in our internal knowledgebase.&lt;/p&gt;
&lt;h3 id=&#34;problem-3-developers-workflow&#34;&gt;Problem #3: Developers’ workflow&lt;/h3&gt;
&lt;p&gt;Improving our process was also a focus. One of the first things we did was rewrite our Jenkins CI/CD pipeline to adopt multibranch pipeline, allowing us to build and test feature branches before they were merged into the &lt;code&gt;main&lt;/code&gt; branch.&lt;/p&gt;
&lt;p&gt;We also automated several tasks that we identified as repetitive, from as small as notifying everyone that there is a new pull request open on GitHub, to automatically running compatibility checks for all of our products once the platform we were building on released a new beta version. We constantly looked for areas we could automate better and discussed them in our weekly retrospectives.&lt;/p&gt;
&lt;p&gt;We also tuned our workflow to better organize our capacity around all the demands that we are getting: from our customers, our roadmaps, and our improvements bucket. We adopted Classes of Service (CoS) to achieve that. CoS is an approach in which you decide different treatments to different types of work. This means the capacity we have is flexible depending on the demand of each type of work.&lt;/p&gt;
&lt;p&gt;For example, we introduced a collapsible task buffer called Intangible that holds work whose value customers do not experience directly, such as upgrading Node.js version, etc. It is collapsible in the sense that the developers in this CoS can be reassigned to other CoS should we deem more capacity is required there. Note that CoS (or any other system for that matter) is not without its pros and cons, so be sure to tweak it to fit your circumstances should you consider adopting it.&lt;/p&gt;
&lt;h3 id=&#34;not-all-problems-are-tech-but-all-tech-has-problems&#34;&gt;Not all problems are tech, but all tech has problems.&lt;/h3&gt;
&lt;p&gt;Sometimes, we identify ourselves through our favorite tech stack.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Hey, I’m a JavaScript developer.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Hey, I’m a Ruby developer.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;And that is not wrong per se, but this particular experience of mine serves as a reminder that the essence of software engineering goes deeper than just the tech — it is to solve problems through software. And that is what we do at End Point.&lt;/p&gt;
&lt;h3 id=&#34;reference&#34;&gt;Reference&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://devopedia.org/solid-design-principles&#34;&gt;SOLID Design Principles&lt;/a&gt; at Devopedia&lt;/li&gt;
&lt;li&gt;Classes of Service:
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://medium.com/servicerocket-eng/on-classes-of-service-cos-a-more-pragmatic-approach-towards-squad-formation-ec93e3a80dfb&#34;&gt;On Classes of Service (CoS), a more pragmatic approach towards “squad formation”&lt;/a&gt; by Yuen-Chi Lian at ServiceRocket&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.thoughtworks.com/insights/blog/predictability-and-classes-service&#34;&gt;Predictability and Classes of Service&lt;/a&gt; by Leonardo Campos at ThoughtWorks&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

      </content>
    </entry>
  
    <entry>
      <title>Demonstrating the HotSwap JVM</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2020/11/java-hotswap/"/>
      <id>https://www.endpointdev.com/blog/2020/11/java-hotswap/</id>
      <published>2020-11-25T00:00:00+00:00</published>
      <author>
        <name>Josh Tolley</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;img src=&#34;/blog/2020/11/java-hotswap/zebras-scale-crush.jpg&#34; alt=&#34;zebras&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://unsplash.com/photos/dgH8NSdEDv0&#34;&gt;Photo&lt;/a&gt; by &lt;a href=&#34;https://unsplash.com/@valenciascott&#34;&gt;Neil and Zulma Scott&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;For a recent Java development project I spent a while setting up an environment to take advantage of the HotSwap JVM, a Java virtual machine that automatically reloads classes when they change. This feature can potentially eliminate the need to redeploy each time code changes, reducing development cycle time considerably. While setting up the environment, I found I wanted a simple example of hot swapping available for my own experimentation, and I thought I’d share that example here.&lt;/p&gt;
&lt;p&gt;First, let’s create a simple Java program. It needs to be slightly more complex than the ubiquitous “Hello, World!” application, because we need it to keep running for a while; if it just prints some message and exits immediately, we won’t have time to compile new code and see the hot swap feature in action.  Here’s an example that uses a simple infinite loop, wherein it sleeps for one second, prints a message, and then repeats.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;import&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;java.lang.Thread&lt;/span&gt;;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;HotSwapTest&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;{&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;static&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;void&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;main&lt;/span&gt;(String[]&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;args)&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;{&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;while&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;(&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;true&lt;/span&gt;)&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;{&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;try&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;{&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;        &lt;/span&gt;System.&lt;span style=&#34;color:#369&#34;&gt;out&lt;/span&gt;.&lt;span style=&#34;color:#369&#34;&gt;println&lt;/span&gt;(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Hi&amp;#34;&lt;/span&gt;);&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;        &lt;/span&gt;Thread.&lt;span style=&#34;color:#369&#34;&gt;sleep&lt;/span&gt;(1000);&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;      &lt;/span&gt;}&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;catch&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;(InterruptedException&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;e)&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;{&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;        &lt;/span&gt;&lt;span style=&#34;color:#888&#34;&gt;// Ignore this&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;      &lt;/span&gt;}&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;    &lt;/span&gt;}&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;  &lt;/span&gt;}&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;}&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;~&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If I build this into build/​classes/​java/​main and run it, as expected it prints out “Hi” every second:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;josh@igtre:~/hotswaptest$ java -cp build/classes/java/main/ HotSwapTest
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Hi
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Hi
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Hi
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The usual JVM doesn’t include the HotSwap feature. For my purposes I downloaded &lt;a href=&#34;https://dcevm.github.io/&#34;&gt;DCEVM&lt;/a&gt;, an alternative JVM which includes HotSwap. It’s also possible to patch some existing JVMs to add HotSwap, if you’d prefer. When I run the same code with DCEVM, it runs the code just like it did with the normal JVM, with additional debugging output:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Starting HotswapAgent &amp;#39;/home/josh/hotswaptest/dcevm/lib/hotswap/hotswap-agent.jar&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HOTSWAP AGENT: 15:01:23.423 INFO (org.hotswap.agent.HotswapAgent) - Loading Hotswap agent {1.4.1} - unlimited runtime class redefinition.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HOTSWAP AGENT: 15:01:24.189 INFO (org.hotswap.agent.config.PluginRegistry) - Discovered plugins: [JdkPlugin, Hotswapper, WatchResources, ClassInitPlugin, AnonymousClassPatch, Hibernate, Hibernate3JPA, Hibernate3, Spring, Jersey1, Jersey2, Jetty, Tomcat, ZK, Logback, Log4j2, MyFaces, Mojarra, Omnifaces, ELResolver, WildFlyELResolver, OsgiEquinox, Owb, Proxy, WebObjects, Weld, JBossModules, ResteasyRegistry, Deltaspike, GlassFish, Vaadin, Wicket, CxfJAXRS, FreeMarker, Undertow, MyBatis]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To make hot swapping work automatically, we need to provide the JVM with a properties file in the JVM’s classpath. Mine looks like this, and lives in build/​classes/​java/​main, next to the compiled class files:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;autoHotswap=true
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;LOGGER=debug&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;These properties are pretty self-explanatory: they tell the JVM to hot swap automatically when it finds new code, and turn up logging to DEBUG level.&lt;/p&gt;
&lt;p&gt;So, with that all set up, let’s run the program again, change the code and rebuild it, and see what happens. For this test, I’ll just edit the message printed in each loop from “Hi” to “Hello”.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;josh@igtre:~/hotswaptest$ ./dcevm/bin/java -cp build/classes/java/main/ HotSwapTest
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Starting HotswapAgent &amp;#39;/home/josh/hotswaptest/dcevm/lib/hotswap/hotswap-agent.jar&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HOTSWAP AGENT: 15:36:22.132 INFO (org.hotswap.agent.HotswapAgent) - Loading Hotswap agent {1.4.1} - unlimited runtime class redefinition.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HOTSWAP AGENT: 15:36:22.543 DEBUG (org.hotswap.agent.annotation.handler.OnClassLoadedHandler) - Init for method public static void org.hotswap.agent.plugin.jdk.JdkPlugin.flushIntrospectClassInfoCache(java.lang.ClassLoader,org.hotswap.agent.javassist.CtClass)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HOTSWAP AGENT: 15:36:22.546 DEBUG (org.hotswap.agent.util.HotswapTransformer) - Registering transformer for class regexp &amp;#39;.*&amp;#39;.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HOTSWAP AGENT: 15:36:22.549 DEBUG (org.hotswap.agent.annotation.handler.OnClassLoadedHandler) - Init for method public static void org.hotswap.agent.plugin.jdk.JdkPlugin.flushObjectStreamCaches(java.lang.ClassLoader,org.hotswap.agent.javassist.CtClass)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HOTSWAP AGENT: 15:36:22.550 DEBUG (org.hotswap.agent.util.HotswapTransformer) - Registering transformer for class regexp &amp;#39;.*&amp;#39;.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The flurry of DEBUG messages tells me that it must have read my properties file correctly, and when I change the code and rebuild, I see the JVM respond with still more debug messages, saying it found and reloaded my code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HOTSWAP AGENT: 15:38:27.066 DEBUG (org.hotswap.agent.watch.nio.WatcherNIO2) - Watch event &amp;#39;ENTRY_DELETE&amp;#39; on &amp;#39;/home/josh/hotswaptest/build/classes/java/main/HotSwapTest.class&amp;#39; --&amp;gt; HotSwapTest.class
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HOTSWAP AGENT: 15:38:27.118 DEBUG (org.hotswap.agent.watch.nio.WatcherNIO2) - Watch event &amp;#39;ENTRY_CREATE&amp;#39; on &amp;#39;/home/josh/hotswaptest/build/classes/java/main/HotSwapTest.class&amp;#39; --&amp;gt; HotSwapTest.class
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HOTSWAP AGENT: 15:38:27.119 DEBUG (org.hotswap.agent.watch.nio.WatcherNIO2) - Watch event &amp;#39;ENTRY_MODIFY&amp;#39; on &amp;#39;/home/josh/hotswaptest/build/classes/java/main/HotSwapTest.class&amp;#39; --&amp;gt; HotSwapTest.class
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HOTSWAP AGENT: 15:38:27.280 DEBUG (org.hotswap.agent.annotation.handler.WatchEventCommand) - Executing resource changed method watchReload on class org.hotswap.agent.plugin.hotswapper.HotswapperPlugin for event WatchFileEvent on path /home/josh/hotswaptest/build/classes/java/main/HotSwapTest.class for event ENTRY_MODIFY
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HOTSWAP AGENT: 15:38:27.439 DEBUG (org.hotswap.agent.plugin.jdk.JdkPlugin) - Flushing HotSwapTest from introspector
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Hi
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HOTSWAP AGENT: 15:38:27.482 DEBUG (org.hotswap.agent.config.PluginManager) - ... reloaded classes [HotSwapTest] (autoHotswap)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Hi
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Hi
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Hi&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;But although it says it swapped in the new code successfully, it’s still printing “Hi”, not “Hello”. Why?&lt;/p&gt;
&lt;p&gt;It turns out this ability to hot swap new code isn’t unlimited, and one important limitation is that methods you’re already running aren’t reloaded. Since the &lt;code&gt;main()&lt;/code&gt; method was running, it didn’t get swapped out. What if I change the code so that instead of printing a string every second, it calls a method, and that method prints the string? Here’s some code to test that technique.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;import&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;java.lang.Thread&lt;/span&gt;;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;HotSwapTest&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;{&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;static&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;void&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;printMsg&lt;/span&gt;()&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;{&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;    &lt;/span&gt;System.&lt;span style=&#34;color:#369&#34;&gt;out&lt;/span&gt;.&lt;span style=&#34;color:#369&#34;&gt;println&lt;/span&gt;(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Here is printMsg&amp;#34;&lt;/span&gt;);&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;  &lt;/span&gt;}&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;static&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;void&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;main&lt;/span&gt;(String[]&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;args)&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;{&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;while&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;(&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;true&lt;/span&gt;)&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;{&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;try&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;{&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;        &lt;/span&gt;HotSwapTest.&lt;span style=&#34;color:#369&#34;&gt;printMsg&lt;/span&gt;();&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;        &lt;/span&gt;Thread.&lt;span style=&#34;color:#369&#34;&gt;sleep&lt;/span&gt;(1000);&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;      &lt;/span&gt;}&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;catch&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;(InterruptedException&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;e)&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;{&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;        &lt;/span&gt;&lt;span style=&#34;color:#888&#34;&gt;// Ignore this&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;      &lt;/span&gt;}&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;    &lt;/span&gt;}&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;  &lt;/span&gt;}&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, I start the JVM over again, and as expected, it prints “Here is printMsg” once every second. When I change to “Here is printMsg v2.0” and rebuild, this happens:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Here is printMsg
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Here is printMsg
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HOTSWAP AGENT: 15:48:34.923 DEBUG (org.hotswap.agent.watch.nio.WatcherNIO2) - Watch event &amp;#39;ENTRY_DELETE&amp;#39; on &amp;#39;/home/josh/hotswaptest/build/classes/java/main/HotSwapTest.class&amp;#39; --&amp;gt; HotSwapTest.class
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HOTSWAP AGENT: 15:48:35.007 DEBUG (org.hotswap.agent.watch.nio.WatcherNIO2) - Watch event &amp;#39;ENTRY_CREATE&amp;#39; on &amp;#39;/home/josh/hotswaptest/build/classes/java/main/HotSwapTest.class&amp;#39; --&amp;gt; HotSwapTest.class
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HOTSWAP AGENT: 15:48:35.008 DEBUG (org.hotswap.agent.watch.nio.WatcherNIO2) - Watch event &amp;#39;ENTRY_MODIFY&amp;#39; on &amp;#39;/home/josh/hotswaptest/build/classes/java/main/HotSwapTest.class&amp;#39; --&amp;gt; HotSwapTest.class
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HOTSWAP AGENT: 15:48:35.174 DEBUG (org.hotswap.agent.annotation.handler.WatchEventCommand) - Executing resource changed method watchReload on class org.hotswap.agent.plugin.hotswapper.HotswapperPlugin for event WatchFileEvent on path /home/josh/hotswaptest/build/classes/java/main/HotSwapTest.class for event ENTRY_CREATE
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HOTSWAP AGENT: 15:48:35.188 DEBUG (org.hotswap.agent.plugin.hotswapper.HotswapperPlugin) - Class HotSwapTest will be reloaded from URL file:/home/josh/hotswaptest/build/classes/java/main/HotSwapTest.class
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HOTSWAP AGENT: 15:48:35.175 DEBUG (org.hotswap.agent.annotation.handler.WatchEventCommand) - Executing resource changed method watchReload on class org.hotswap.agent.plugin.hotswapper.HotswapperPlugin for event WatchFileEvent on path /home/josh/hotswaptest/build/classes/java/main/HotSwapTest.class for event ENTRY_MODIFY
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HOTSWAP AGENT: 15:48:35.191 DEBUG (org.hotswap.agent.plugin.hotswapper.HotswapperPlugin) - Class HotSwapTest will be reloaded from URL file:/home/josh/hotswaptest/build/classes/java/main/HotSwapTest.class
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HOTSWAP AGENT: 15:48:35.352 DEBUG (org.hotswap.agent.command.impl.SchedulerImpl) - Executing pluginManager.hotswap([class HotSwapTest])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HOTSWAP AGENT: 15:48:35.355 RELOAD (org.hotswap.agent.config.PluginManager) - Reloading classes [HotSwapTest] (autoHotswap)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HOTSWAP AGENT: 15:48:35.370 DEBUG (org.hotswap.agent.plugin.jdk.JdkPlugin) - Flushing HotSwapTest from com.sun.beans.introspect.ClassInfo cache
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HOTSWAP AGENT: 15:48:35.375 DEBUG (org.hotswap.agent.plugin.jdk.JdkPlugin) - Flushing HotSwapTest from ObjectStreamClass caches
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HOTSWAP AGENT: 15:48:35.376 DEBUG (org.hotswap.agent.plugin.jdk.JdkPlugin) - Flushing HotSwapTest from introspector
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HOTSWAP AGENT: 15:48:35.415 DEBUG (org.hotswap.agent.config.PluginManager) - ... reloaded classes [HotSwapTest] (autoHotswap)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Here is printMsg v2.0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Here is printMsg v2.0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;As you can see, it swapped in the new code correctly, and now prints the new message. HotSwap was a success!&lt;/p&gt;
&lt;p&gt;I imagine there are very few production environments where this feature would be applicable, and even in development, getting this to work properly for something like a JEE app deployed to some application container isn’t necessarily a simple task. But if it can cut down on redeployment cycles, it can certainly be a valuable developer tool.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>The Pragmatic Programmer book, 20th anniversary edition</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2020/10/the-pragmatic-programmer-20th-anniversary-edition/"/>
      <id>https://www.endpointdev.com/blog/2020/10/the-pragmatic-programmer-20th-anniversary-edition/</id>
      <published>2020-10-16T00:00:00+00:00</published>
      <author>
        <name>Jon Jensen</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;img src=&#34;/blog/2020/10/the-pragmatic-programmer-20th-anniversary-edition/20201016_130906-sm.jpg&#34; alt=&#34;Photo of the original and 20th anniversary editions of The Pragmatic Programmer book, atop lawn and fall leaves&#34;&gt;&lt;/p&gt;
&lt;!-- Photo by Jon Jensen --&gt;
&lt;p&gt;The Pragmatic Programmer is a now-classic book about software development, first published in 1999. It is old enough that it predates the famous &lt;a href=&#34;https://agilemanifesto.org/&#34;&gt;Agile Manifesto&lt;/a&gt; of 2001. The authors of the book, Andy and Dave, were two of the 14 authors of that manifesto.&lt;/p&gt;
&lt;p&gt;For its 20th anniversary in 2019, Dave and Andy created a new edition. They updated things that had become dated, such as mentions of programming languages, tools, operating systems, websites, etc. That was, I imagine, the easy part. They went on to extensively revise the entire text and incorporate new lessons learned in the past two decades.&lt;/p&gt;
&lt;h3 id=&#34;a-classic&#34;&gt;A classic&lt;/h3&gt;
&lt;p&gt;This book is part of our company’s &lt;a href=&#34;/blog/2018/05/work-philosophy-canon/&#34;&gt;“work philosophy canon”&lt;/a&gt; that I ask every software developer at End Point to read, so for that reason and others I wanted to be familiar with the new edition and make sure it is still something I want to recommend so broadly.&lt;/p&gt;
&lt;p&gt;The book is also required reading for university courses at Cornell (&lt;a href=&#34;https://www.cs.cornell.edu/courses/cs3110/2020sp/reflections.html&#34;&gt;CS 3110: Data Structures and Functional Programming&lt;/a&gt;) and the University of Washington (&lt;a href=&#34;https://courses.cs.washington.edu/courses/cse331/19au/quizzes.html&#34;&gt;CSE 331: Software Design and Implementation&lt;/a&gt;), probably among others!&lt;/p&gt;
&lt;p&gt;I first read this book 19 years ago and really enjoyed it. I found that it clearly expressed many useful concepts I had stumbled upon in my own programming experience. More importantly, it gave me other helpful guidance and warned of pitfalls. Having that all collected in book form with concise, memorable chapter names and tips gave me more shared vocabulary to use with others in our work.&lt;/p&gt;
&lt;p&gt;I also enjoyed reading the new 20th anniversary edition. It did not have the same personal impact, which is to be expected since I am at a very different point in my programming career, technical reading, and life experience. But I think the new edition has as great or even increased power for new readers.&lt;/p&gt;
&lt;h3 id=&#34;overview-of-changes&#34;&gt;Overview of changes&lt;/h3&gt;
&lt;p&gt;The authors estimate that around 75% of the text has changed, and that seems about right. A few areas that stood out to me were:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The now widely-known adage “don’t repeat yourself” originally meant primarily not to duplicate knowledge, that each piece of data should appear in only one canonical location. Over time, “don’t repeat yourself” has been more often used to preach against copying and pasting code. While that is also a good general rule, it has been oversimplified and turned into a blanket prohibition. Dave &amp;amp; Andy mention cases where duplicating code is the right thing to do, because the problem space is not the same and factoring out all such code duplication will make later changes far more complicated as the code has to behave differently for different callers.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Computer security was not nearly as big of a concern when they were writing the first edition in the late 1990s, and now that almost every computer is networked and attackers are motivated to reach every system from anywhere in the world, they gave the topic more attention.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Concurrency gets much more discussion, as is sensible in a time where scaling up typically means using many more CPU cores and processors.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Unit testing was far less common in the late ’90s, and there were few good test frameworks, so they recommended you write your own. Now there are many good test frameworks for every language, so they of course recommend you choose one of those and use it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Dave writes “A Confession” on page 223: He tells us that writing tests for 30+ years made testing so much a part of the way he thinks and programs, that he now writes testable interfaces even when he doesn’t write tests. He isn’t saying that testing is no longer important, but rather that it’s not a religion, that it can and should be examined by experienced programmers, and it has important effects on the programmer aside from the tests themselves.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The old edition had checklists scattered throughout, and collected in the pull-out card at the end. The new edition doesn’t have checklists anymore, except the Debugging Checklist on page 97. I think that’s ok. They weren’t something I ever referred back to.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;tips&#34;&gt;Tips&lt;/h3&gt;
&lt;p&gt;The old edition had 70 tips that appear throughout the chapters. The new edition has 100 tips. In both cases they are extracted and collected on a pull-out card at the end of the book. What changed?&lt;/p&gt;
&lt;h4 id=&#34;removed-or-heavily-reworked-tips&#34;&gt;Removed or heavily reworked tips&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Write Code That Writes Code&lt;/li&gt;
&lt;li&gt;Use Exceptions for Exceptional Problems&lt;/li&gt;
&lt;li&gt;Design Using Services&lt;/li&gt;
&lt;li&gt;Separate Views from Models&lt;/li&gt;
&lt;li&gt;Don’t Use Wizard Code You Don’t Understand&lt;/li&gt;
&lt;li&gt;Abstractions Live Longer than Details&lt;/li&gt;
&lt;li&gt;Costly Tools Don’t Produce Better Designs&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;tips-that-changed-slightly&#34;&gt;Tips that changed slightly&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;“Use a Single Editor Well” is now “Achieve Editor Fluency”&lt;/li&gt;
&lt;li&gt;“Don’t Panic When Debugging” is now simply “Don’t Panic”&lt;/li&gt;
&lt;li&gt;“Minimize Coupling Between Modules” is now “Decoupled Code Is Easier to Change”&lt;/li&gt;
&lt;li&gt;“Configure, Don’t Integrate” is now “Parameterize Your App Using External Configuration”&lt;/li&gt;
&lt;li&gt;“Don’t Gather Requirements—Dig for Them” is now “Requirements Are Learned in a Feedback Loop”&lt;/li&gt;
&lt;li&gt;“Organize Teams Around Functionality” is now “Organize Fully Functional Teams”&lt;/li&gt;
&lt;li&gt;“Gently Exceed Your Users’ Expectations” is now “Delight Users, Don’t Just Deliver Code”&lt;/li&gt;
&lt;li&gt;“Put Abstractions in Code, Details in Metadata” is now “Policy Is Metadata”&lt;/li&gt;
&lt;li&gt;“Always Design for Concurrency” is now “Random Failures Are Often Concurrency Issues”&lt;/li&gt;
&lt;li&gt;“Listen to Nagging Doubts—Start When You’re Ready” is now “Listen to Your Inner Lizard”&lt;/li&gt;
&lt;li&gt;“Don’t Be a Slave to Formal Methods” is now “Do What Works, Not What’s Fashionable”&lt;/li&gt;
&lt;li&gt;“Some Things Are Better Done than Described” transformed to “Agile Is Not a Noun; Agile Is How You Do Things”&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;new-tips&#34;&gt;New tips&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;You Have Agency&lt;/li&gt;
&lt;li&gt;Good Design Is Easier to Change Than Bad Design&lt;/li&gt;
&lt;li&gt;Forgo Following Fads&lt;/li&gt;
&lt;li&gt;Failing Test Before Fixing Code&lt;/li&gt;
&lt;li&gt;Read the Damn Error Message&lt;/li&gt;
&lt;li&gt;Act Locally&lt;/li&gt;
&lt;li&gt;Take Small Steps—Always&lt;/li&gt;
&lt;li&gt;Avoid Fortune-Telling&lt;/li&gt;
&lt;li&gt;Tell, Don’t Ask&lt;/li&gt;
&lt;li&gt;Don’t Chain Method Calls&lt;/li&gt;
&lt;li&gt;Avoid Global Data&lt;/li&gt;
&lt;li&gt;If It’s Important Enough To Be Global, Wrap It in an API&lt;/li&gt;
&lt;li&gt;Programming Is About Code, But Programs Are About Data&lt;/li&gt;
&lt;li&gt;Don’t Hoard State; Pass It Around&lt;/li&gt;
&lt;li&gt;Don’t Pay Inheritance Tax&lt;/li&gt;
&lt;li&gt;Prefer Interfaces to Express Polymorphism&lt;/li&gt;
&lt;li&gt;Delegate to Services: Has-A Trumps Is-A&lt;/li&gt;
&lt;li&gt;Use Mixins to Share Functionality&lt;/li&gt;
&lt;li&gt;Shared State Is Incorrect State&lt;/li&gt;
&lt;li&gt;Use Actors For Concurrency Without Shared State&lt;/li&gt;
&lt;li&gt;Testing Is Not About Finding Bugs&lt;/li&gt;
&lt;li&gt;A Test Is the First User of Your Code&lt;/li&gt;
&lt;li&gt;Build End-To-End, Not Top-Down or Bottom Up&lt;/li&gt;
&lt;li&gt;Use Property-Based Tests to Validate Your Assumptions&lt;/li&gt;
&lt;li&gt;Keep It Simple and Minimize Attack Surfaces&lt;/li&gt;
&lt;li&gt;Apply Security Patches Quickly&lt;/li&gt;
&lt;li&gt;Name Well; Rename When Needed&lt;/li&gt;
&lt;li&gt;No One Knows Exactly What They Want&lt;/li&gt;
&lt;li&gt;Programmers Help People Understand What They Want&lt;/li&gt;
&lt;li&gt;Don’t Go into the Code Alone&lt;/li&gt;
&lt;li&gt;Maintain Small Stable Teams&lt;/li&gt;
&lt;li&gt;Schedule It to Make It Happen&lt;/li&gt;
&lt;li&gt;Deliver When Users Need It&lt;/li&gt;
&lt;li&gt;Use Version Control to Drive Builds, Tests, and Releases&lt;/li&gt;
&lt;li&gt;First, Do No Harm&lt;/li&gt;
&lt;li&gt;Don’t Enable Scumbags&lt;/li&gt;
&lt;li&gt;It’s Your Life. Share it. Celebrate it. Build it. &lt;strong&gt;And have fun!&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The new edition’s PDF version does not include the pull-out card with tips that comes with the printed book. That’s too bad, because the tips were what I most often referred to in the old edition after I finished reading it. At least Andy and Dave have published on their website a list of the 100 updated tips. It would be even nicer to have a PDF of the book’s pull-out card as they did for the old edition.&lt;/p&gt;
&lt;h3 id=&#34;upgrade&#34;&gt;Upgrade?&lt;/h3&gt;
&lt;p&gt;As you can see, there are many new tips. The text has been updated. It is still of excellent quality. So should you get the new edition?&lt;/p&gt;
&lt;p&gt;I mentioned earlier two university courses that use the book. In both courses the professors allow students to use either the original 1999 version or the 2019 version. That seems like the right thing to do to me as well.&lt;/p&gt;
&lt;p&gt;If you already have the old edition of the book, I don’t think it’s necessary to rush out and buy the new edition. The old one is still quite good and relevant, and you’ll be learning a bit of software development history by reading the older one.&lt;/p&gt;
&lt;p&gt;If you do not yet have the book, or if you will be going over it with others who are new to it, it is probably best for you to get the new edition as well so you can be familiar with the new tips and the ways Dave &amp;amp; Andy describe things now.&lt;/p&gt;
&lt;h3 id=&#34;summing-up&#34;&gt;Summing up&lt;/h3&gt;
&lt;p&gt;I am glad that Dave and Andy updated their book. Their updates make sense and make the book more relevant to present-day readers.&lt;/p&gt;
&lt;p&gt;Relatedly, it would be good to also see an update of the also excellent book &lt;em&gt;Practices of an Agile Developer&lt;/em&gt; by Venkat Subramaniam and Andy. That is coming up on 15 years old itself. Perhaps some of its topics have been incorporated in the new edition of &lt;em&gt;The Pragmatic Programmer&lt;/em&gt;, but as I review the table of contents, it looks like it is still mostly additive. I have cited its important maxim “Different Makes a Difference” so often that I thought it was from &lt;em&gt;The Pragmatic Programmer&lt;/em&gt; instead!&lt;/p&gt;
&lt;p&gt;I’ll close with this good observation and advice from Andy in their Changelog podcast interview:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Was it Dijkstra who had the Turing Award lecture about the very humble programmer? That is a critical piece of early literature… And you talk about things that haven’t changed. This was 1972? … And he makes the very important point that complexity will overwhelm us if we don’t take a very humble, very measured approach. And it’s been 30–40 years and everyone—present company included—has ignored this wonderful advice.&lt;/p&gt;
&lt;p&gt;Humility is difficult in our environment, in our culture, and it is probably, of all the human factorsy things that you need to be a good developer, I would submit that being humble, realizing you don’t know all the answers, that you need to find out, that you need to experiment, get feedback, try it.&lt;/p&gt;
&lt;p&gt;This part of our headlong rush into the shiny new thing is this kind of faith that “Well, that’s gonna be better. I can do it better. I’m better than this/​that.” Yeah, maybe… But you should validate that. You should try it. You should go back and read these things. You should try these other experiments.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Thanks, Andy &amp;amp; Dave!&lt;/p&gt;
&lt;h3 id=&#34;reference&#34;&gt;Reference&lt;/h3&gt;
&lt;h4 id=&#34;all-tips-from-each-edition&#34;&gt;All tips from each edition&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://blog.codinghorror.com/a-pragmatic-quick-reference/&#34;&gt;Quick reference 70 tips (and checklists) from original edition&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://pragprog.com/tips/&#34;&gt;Quick reference 100 tips from new edition&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;interviews&#34;&gt;Interviews&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.functionalgeekery.com/episode-126-andy-hunt-and-dave-thomas/&#34;&gt;Functional Geekery Episode 126 – Andy Hunt and Dave Thomas from July 2, 2019&lt;/a&gt; by Steven Proctor&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://changelog.com/podcast/352&#34;&gt;The Changelog – Episode #352: The Pragmatic Programmers with Andy Hunt &amp;amp; Dave Thomas&lt;/a&gt; by Adam Stacoviak &amp;amp; Jerod Santo&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.codenewbie.org/podcast/why-you-should-read-the-new-edition-of-the-pragmatic-programmer&#34;&gt;CodeNewbie Podcast season 9 episode 8 from August 26, 2019: Why you should read the new edition of the Pragmatic Programmer with Andy Hunt, Dave Thomas&lt;/a&gt; by Saron Yitbarek (author of the new edition’s foreword)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;other-comparisons-of-the-two-editions&#34;&gt;Other comparisons of the two editions&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.kevinhooke.com/2020/05/06/the-pragmatic-programmer-1st-edition-vs-20th-anniversary-edition-what-are-the-major-changes/&#34;&gt;Sections added, changed significantly, and removed&lt;/a&gt; by Kevin Hooke&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://booksoncode.com/articles/pragmatic-programmer-comparison&#34;&gt;The Pragmatic Programmer Book 2nd Edition Differences by Miranda Limonczenko&lt;/a&gt; (very detailed, but covers only the first 3 chapters)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;book-pages&#34;&gt;Book pages&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://pragprog.com/titles/tpp20/the-pragmatic-programmer-20th-anniversary-edition/&#34;&gt;The Pragmatic Programmer, 20th Anniversary Edition&lt;/a&gt; book home page, errata, source code downloads, and links to buy&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://pragprog.com/titles/pad/practices-of-an-agile-developer/&#34;&gt;Practices of an Agile Developer&lt;/a&gt; book home page, samples, pull-out card, and &lt;a href=&#34;/blog/2006/06/review-practices-of-agile-developer/&#34;&gt;review by Ethan Rowe&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

      </content>
    </entry>
  
    <entry>
      <title>Cooking with CAS</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2020/03/cooking-with-cas/"/>
      <id>https://www.endpointdev.com/blog/2020/03/cooking-with-cas/</id>
      <published>2020-03-10T00:00:00+00:00</published>
      <author>
        <name>Josh Tolley</name>
      </author>
      <content type="html">
        &lt;img src=&#34;/blog/2020/03/cooking-with-cas/4696900602_77582d1d5d_c.jpg&#34; alt=&#34;Laptop on a desk showing a web browser open to a login form, with a Post-It note saying &#39;ADMIN / ADMIN&#39; attached to the screen&#34; /&gt;
&lt;p&gt;Photo by Flickr user &lt;a href=&#34;http://web.archive.org/web/20190305093832/https://www.flickr.com/photos/reidrac/&#34;&gt;reidrac&lt;/a&gt;, licensed
under &lt;a href=&#34;https://creativecommons.org/licenses/by-sa/2.0/&#34;&gt;CC BY-SA 2.0&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;One of our customers asked us to host a new suite of web-based applications for them and to protect them with a single sign-on (SSO) solution. Ok, easy enough;
these applications were in fact designed with a particular SSO system in mind already, but our situation required a different one, and we eventually chose
Apereo’s open source &lt;a href=&#34;https://www.apereo.org/projects/cas&#34;&gt;Central Authentication Server project&lt;/a&gt;, or CAS. I’d like to describe the conversion process we went
through.&lt;/p&gt;
&lt;h3 id=&#34;the-ingredients&#34;&gt;The ingredients&lt;/h3&gt;
&lt;p&gt;Our customer’s application suite included:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The principal Java application using &lt;a href=&#34;https://docs.oracle.com/javase/7/docs/technotes/guides/security/jaas/JAASRefGuide.html&#34;&gt;JAAS authentication&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Another Java application based on &lt;a href=&#34;https://spring.io/projects/spring-security&#34;&gt;Spring Security&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;A pair of PHP applications&lt;/li&gt;
&lt;li&gt;A few automated tasks that needed to authenticate.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The original SSO system sets a header on each request, identifying an authenticated user. This requires a gateway system to sanitize request headers to ensure
malicious users cannot forge a header themselves. It also requires each application inspect request headers and respond appropriately.&lt;/p&gt;
&lt;p&gt;CAS is a bit more complex: applications redirect unauthenticated requests to a CAS server, which authenticates the user through any of various configurable
methods. The CAS server then redirects the user back to the original application with a parameter called a “Service Ticket”, a seemingly random number
identifying an individual authentication request. The original application contacts the CAS server directly to validate the service ticket and to collect
information to identify the user. It can then establish a session for that user, and proceed normally.&lt;/p&gt;
&lt;p&gt;To CAS-enable an application, we incorporate one of the CAS &lt;a href=&#34;https://apereo.github.io/cas/6.1.x/integration/CAS-Clients.html#build-your-own-cas-client&#34;&gt;client
libraries&lt;/a&gt;, which exist for various languages. In fact we won’t use
the Java client directly, but rather we’ll incorporate components that extend it. When evaluating CAS, I was a bit concerned by what appeared to be a
surprisingly limited selection of actively supported client libraries, and of course your results may vary, but we found software to meet our own needs without
too much difficulty.&lt;/p&gt;
&lt;h3 id=&#34;configuring-wildfly-authentication&#34;&gt;Configuring Wildfly Authentication&lt;/h3&gt;
&lt;p&gt;The most important application in the suite depends on the JAAS-based security subsystem of the &lt;a href=&#34;https://www.wildfly.org/&#34;&gt;Wildfly application server&lt;/a&gt; it’s
deployed to. Originally it used a custom &lt;a href=&#34;https://docs.oracle.com/javase/7/docs/api/javax/security/auth/spi/LoginModule.html&#34;&gt;LoginModule&lt;/a&gt; that inspected
request headers to find the ID of the authenticated user. Our first task was to configure our proxy server to remove this header from every request. We planned
to disable the old authentication system entirely, of course, but this change ensured that even if we mistakenly left it enabled somewhere, malicious users
couldn’t exploit it for access.&lt;/p&gt;
&lt;p&gt;This application uses a declarative security policy: the deployment descriptor identifies a set of user roles, and another set of “security constraints”. Each
security constraint describes one or more URL patterns used in the application, and the set of user roles allowed to access URLs matching those patterns. Here
are two examples:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&amp;lt;!-- clients --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;security-constraint&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;web-resource-collection&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;web-resource-name&amp;gt;&lt;/span&gt;Secure Area&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/web-resource-name&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;url-pattern&amp;gt;&lt;/span&gt;/views/clients/*&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/url-pattern&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;url-pattern&amp;gt;&lt;/span&gt;/client/edit/*&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/url-pattern&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;url-pattern&amp;gt;&lt;/span&gt;/client/edit_tree/*&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/url-pattern&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;url-pattern&amp;gt;&lt;/span&gt;/client/view/*&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/url-pattern&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;url-pattern&amp;gt;&lt;/span&gt;/client/view/id/*&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/url-pattern&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/web-resource-collection&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;auth-constraint&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;role-name&amp;gt;&lt;/span&gt;client_role&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/role-name&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/auth-constraint&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/security-constraint&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&amp;lt;!-- places --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;security-constraint&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;web-resource-collection&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;web-resource-name&amp;gt;&lt;/span&gt;Secure Area&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/web-resource-name&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;url-pattern&amp;gt;&lt;/span&gt;/views/places/*&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/url-pattern&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/web-resource-collection&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;auth-constraint&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;role-name&amp;gt;&lt;/span&gt;manage_places&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/role-name&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/auth-constraint&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/security-constraint&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We installed the &lt;a href=&#34;https://github.com/soulwing/cas-extension&#34;&gt;cas-extension library&lt;/a&gt; in our Wildfly server to handle the CAS protocol. When an unauthenticated
user attempts to access a URL matching a pattern in one of the application’s security constraints, the CAS extension automatically intercepts control and
redirects the user to the CAS server. Assuming the user authenticates successfully, our application will receive another request with a service ticket
parameter. The cas-extension intercepts this request as well, validates the service ticket, and creates an “identity assertion”, which it sends to the Wildfly
security system. Wildfly’s role mapper queries a database to find the user’s roles, after which the authentication process is complete.&lt;/p&gt;
&lt;p&gt;Configuration of the cas-extension begins with a CAS profile, a combination of the URL of the CAS server and the URL of the service the extension should
protect.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;subsystem&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;xmlns=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;urn:soulwing.org:cas:1.0&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;cas-profile&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;name=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;default&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;service-url=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;https://our.application.server/application&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;server-url=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;https://our.cas.server&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/subsystem&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This tells the extension where to send authentication requests, where to listen for requests returning from the CAS server, and where to validate service
tickets. Next we need to validate that identity assertion, and figure out what roles belong to the user. This happens in a &lt;a href=&#34;https://docs.wildfly.org/14/Admin_Guide.html#security-domains&#34;&gt;Wildfly security
domain&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;security-domain&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;name=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;MySecurityDomain&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;authentication&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;login-module&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;name=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;IdentityAssertion&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;code=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;org.soulwing.cas.jaas.IdentityAssertionLoginModule&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;flag=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;required&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;module=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;org.soulwing.cas&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/authentication&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;mapping&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;mapping-module&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;code=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;DatabaseRoles&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;type=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;role&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;module-option&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;name=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;dsJndiName&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;value=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;java:/comp/env/jdbc/databaseConnection&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;module-option&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;name=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;rolesQuery&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;value=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;select role from user_roles where user_id = ?&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/mapping-module&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/mapping&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/security-domain&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;authentication&lt;/code&gt; portion of the security domain refers to a JAAS LoginModule shipped with the CAS extension, which simply verifies that the identity
assertion comes from the CAS extension and not somewhere else. Then the &lt;code&gt;mapping&lt;/code&gt; portion (&lt;a href=&#34;https://docs.wildfly.org/14/Admin_Guide.html#mapping&#34;&gt;documented here&lt;/a&gt;)
looks up the given user in a database to find what roles it should be assigned.&lt;/p&gt;
&lt;p&gt;The last piece of the puzzle is a CAS deployment descriptor for our application, which activates cas-extension for that application. In its simplest form, this
is an empty file in the right place, but ours ended up a little more complex. It identifies both the CAS profile we want to use (unnecessary in this case, as
there’s only one CAS profile on the system, but it helped keep things more clear in our minds), and instructs the extension to load some other libraries into
our application.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;&amp;lt;?xml version=&amp;#34;1.0&amp;#34; encoding=&amp;#34;UTF-8&amp;#34;?&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;cas&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;xmlns=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;urn:soulwing.org:cas:1.0&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;profile&amp;gt;&lt;/span&gt;default&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/profile&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;add-api-dependencies/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/cas&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This configuration proved sufficient to let users log in and use the application, but as is sometimes the case with single sign-on, we needed a little more work
to let them log out properly. Each application in the suite sets a cookie in the user’s browser to identify its session. The CAS server likewise sets a cookie.
When a user logs out of the application, that application’s session cookie is destroyed, but we also need to destroy the CAS server’s session cookie as well as
the other applications’ cookies. Single log-out can be complicated, and I won’t go into the full setup here. One reason the CAS deployment descriptor loads
cas-extension libraries was so we could use cas-extension to generate the proper logout URL, and redirect our users to that URL once the application has
destroyed its own session.&lt;/p&gt;
&lt;h3 id=&#34;configuring-spring-authentication&#34;&gt;Configuring Spring Authentication&lt;/h3&gt;
&lt;p&gt;Another Java-based application in our suite uses Spring Security. &lt;a href=&#34;https://docs.spring.io/spring-security/site/docs/3.0.x/reference/cas.html&#34;&gt;This document&lt;/a&gt;
describes the bulk of the configuration, which seemed less straightforward than for cas-extension, but follows essentially the same mechanism. Here we
configured a Spring
&lt;a href=&#34;https://docs.spring.io/spring-security/site/docs/3.2.3.RELEASE/apidocs/org/springframework/security/core/userdetails/UserDetailsService.html&#34;&gt;UserDetailsService&lt;/a&gt;
to execute the same database query we used above to find the user’s roles. I’m not fully conversant in the large stack of beans Spring uses to manage the
process, and it took some time to get this configuration sorted out.&lt;/p&gt;
&lt;h3 id=&#34;enter-php&#34;&gt;Enter PHP&lt;/h3&gt;
&lt;p&gt;Two of these applications use PHP, which meant yet another configuration. Apereo maintains a &lt;a href=&#34;https://github.com/apereo/phpCAS&#34;&gt;PHP client&lt;/a&gt;, which includes
several helpful examples. I tracked down the part of the application that authenticates users, and replaced the existing code with calls to phpCAS:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;phpCAS::&lt;span style=&#34;color:#369&#34;&gt;client&lt;/span&gt;(CAS_VERSION_2_0, &lt;span style=&#34;color:#369&#34;&gt;$phpCASHost&lt;/span&gt;, &lt;span style=&#34;color:#369&#34;&gt;$phpCASPort&lt;/span&gt;, &lt;span style=&#34;color:#369&#34;&gt;$phpCASContext&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;phpCAS::&lt;span style=&#34;color:#369&#34;&gt;forceAuthentication&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;$_SESSION&lt;/span&gt;[EXPORT_SERVERNAME][&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;umdid&amp;#39;&lt;/span&gt;] = phpCAS::&lt;span style=&#34;color:#369&#34;&gt;getUser&lt;/span&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;forceAuthentication&lt;/code&gt; call determines the current phase of the authentication process this request is in, whether it’s unauthenticated, fully authenticated, or
requires service ticket validation, and responds appropriately. We then set a session variable to the ID of the authenticated user, which replicates what
the original authentication code would have done.&lt;/p&gt;
&lt;p&gt;One of these two applications requires authenticated access to a REST API exposed by the Wildfly application. CAS calls this “proxy” authentication, when one
application requests access to another. Here, CAS issues not only its usual service ticket, but also a “proxy granting ticket”. When the application wants to
use the API, it asks the CAS server for a service ticket, using the proxy granting ticket. The CAS server itself requires some new configuration in this case,
but for the PHP code, the only difference in the login phase from the simpler, non-proxy case is that we call &lt;code&gt;phpCAS::proxy&lt;/code&gt; instead of &lt;code&gt;phpCAS::client&lt;/code&gt; to
configure CAS. Later, when calling the service itself, we used more phpCAS services in place of the cURL library the original used.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;$service&lt;/span&gt; = \phpCAS::&lt;span style=&#34;color:#369&#34;&gt;getProxiedService&lt;/span&gt;(PHPCAS_PROXIED_SERVICE_HTTP_GET);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;$service&lt;/span&gt;-&amp;gt;&lt;span style=&#34;color:#369&#34;&gt;setUrl&lt;/span&gt;(&lt;span style=&#34;color:#369&#34;&gt;$serviceURL&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;$service&lt;/span&gt;-&amp;gt;&lt;span style=&#34;color:#369&#34;&gt;send&lt;/span&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;the-return-of-header-authentication&#34;&gt;The return of header authentication&lt;/h3&gt;
&lt;p&gt;Finally, we have a few automated tasks which use various APIs, and need to authenticate. We can’t redirect requests to a CAS server and expect a user to provide
credentials, so we’ve taken our cue from the applications’ original form, and configured CAS to recognize a “trusted header”. We add this header to any requests
issued by these automated jobs. Of course, we’ve also configured the proxy to disallow this header from any systems outside our internal network.&lt;/p&gt;
&lt;h3 id=&#34;a-few-loose-ends&#34;&gt;A few loose ends&lt;/h3&gt;
&lt;p&gt;Of course, there were other considerations in this project that I’ve not covered here. Configuring CAS itself wasn’t necessarily straightforward, and included a
custom authentication module I hope to describe in a later article. Selecting among CAS server’s available
&lt;a href=&#34;https://apereo.github.io/cas/6.1.x/installation/Configuring-Servlet-Container.html&#34;&gt;deployment&lt;/a&gt;
&lt;a href=&#34;https://apereo.github.io/cas/6.1.x/installation/Docker-Installation.html&#34;&gt;options&lt;/a&gt; and fitting the winner into our existing infrastructure in a way that makes
it easy to manage and monitor was another task entirely. We needed to customize the server’s default user interface to prevent it from offering users an
imaginary method to recover forgotten passwords. The series of redirected browser requests involved in the CAS protocol presents a notable performance impact
under some circumstances. And it has taken me no small effort to learn to appreciate the CAS server’s sometimes distressingly circular
&lt;a href=&#34;https://apereo.github.io/cas/6.1.x/index.html&#34;&gt;documentation&lt;/a&gt;. But several months into the project, CAS seems to be working well enough for our purposes that
other users of the same application suite have begun to express interest.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>How I Learn New Technologies</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2018/10/how-i-learn-new-technologies/"/>
      <id>https://www.endpointdev.com/blog/2018/10/how-i-learn-new-technologies/</id>
      <published>2018-10-30T00:00:00+00:00</published>
      <author>
        <name>Árpád Lajos</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;img src=&#34;/blog/2018/10/how-i-learn-new-technologies/image-0.jpg&#34; alt=&#34;woman typing at desk&#34; /&gt;&lt;br&gt;&lt;a href=&#34;https://www.flickr.com/photos/30478819@N08/&#34;&gt;Photo by Marco Verch&lt;/a&gt; · &lt;a href=&#34;https://www.flickr.com/photos/30478819@N08/45044053152/&#34;&gt;CC BY 2.0, modified&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If a developer has plenty of time, then the best way to learn a technology is to read a book about it, solve the tasks the book presents, and then to do some very basic work just to get some real-world experience. When this is done, one might want to watch some tutorial videos, consult with people who are either also learning, or, even better, are experienced in the given technology.&lt;/p&gt;
&lt;p&gt;When someone gets comfortable with a dev stack, the person might be inclined to prefer to work only in his or her comfort zone. In consulting, this is feasible in the majority of cases. But what if someone gets a new project in a different software stack? Is it a big problem? In my opinion, it’s not a problem, &lt;em&gt;if we are able to determine the minimal knowledge we need to get started&lt;/em&gt;. So how can a developer quickly grasp the essence of the problem space? Where are answers to the most frequent questions reachable?&lt;/p&gt;
&lt;p&gt;In 2008 I graduated from the university and was looking for a job. In the middle of the world economic crisis new programmers had limited chances at getting a job. So I began accepting very small projects from varied clients, all using vastly different technologies. To be successful at this, I realized I had to revise my method of learning technologies.&lt;/p&gt;
&lt;p&gt;I particularly remember the case when in 2009 I had a small JavaScript project and I had no knowledge whatsoever and a deadline of 24 hours, as the client needed the job done ASAP. Reading a book was not an option. Even a tutorial was too long, so after four hours of trying hard to solve the problem I watched &lt;a href=&#34;https://www.youtube.com/watch?v=v2ifWcnQs6M&#34;&gt;Douglas Crockford’s video&lt;/a&gt;. After so much suffering, his joke “Good morning, everybody, welcome to the Blair Witch project” was more than fitting about how I felt in that situation. After four hours of suffering I finally found an ally. With the help of this video I was able to grasp the &lt;strong&gt;core&lt;/strong&gt; of the knowledge I needed, that is, the information I need to be able to quickly find other information if needed. After watching the video, I completed the small project without much difficulty. Of course, it was a new language for me, but at least I had some understanding. That case taught me the importance of quickly grasping the core of the new technology I am learning.&lt;/p&gt;
&lt;p&gt;My methodology is to put the appropriate questions needed to be answered into a list. By looking at the answer of each question, I can acquire the core knowledge which allows me to work with the given technology. Of course, working with a technology one has no previous experience with takes more time in comparison with working with a technology one has years of experience with, because even the most trivial tasks might need some research, but if the core knowledge is already acquired, then 90% of the answers to the question one may have while working are easily answered.&lt;/p&gt;
&lt;h3 id=&#34;new-programming-language&#34;&gt;New Programming Language&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;What justifies the existence of the language? What is the purpose the language aims to fulfill?&lt;/li&gt;
&lt;li&gt;Where can I find the original documentation and how do I search and navigate there?&lt;/li&gt;
&lt;li&gt;Is the syntax similar to a language I already know? How are commands separated, what are the keywords one will frequently use?&lt;/li&gt;
&lt;li&gt;What type of things will I work with using the language? With CSS I define rules which specify the looks of a web page. With query languages I work with databases, relations/​tables, records, and columns. With HTML or XML I define a node hierarchy. With C I write functions. With Java I define classes and objects.&lt;/li&gt;
&lt;li&gt;What types of tasks can I expect from the projects I can work with?&lt;/li&gt;
&lt;li&gt;Can I watch a tutorial video? Watching an introductory video takes hours. Reading a book can  take weeks.&lt;/li&gt;
&lt;li&gt;What operating system should I use?&lt;/li&gt;
&lt;li&gt;What IDE should I use?&lt;/li&gt;
&lt;li&gt;Is there an online possibility to write experimental code to try my hand in this new language?&lt;/li&gt;
&lt;li&gt;Do I need to register in community forums?&lt;/li&gt;
&lt;li&gt;Do I have questions I can’t answer yet? I should  be able to find an answer on community forums or general purpose programming Q&amp;amp;A sites.&lt;/li&gt;
&lt;li&gt;Have I written a simple Hello World in the language?&lt;/li&gt;
&lt;li&gt;What will I have to watch out for?&lt;/li&gt;
&lt;li&gt;What are the best practices for coding in the given language?&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;new-operating-system&#34;&gt;New Operating System&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Do I have two systems I can use, one where I can search the internet for help, and the other where I can begin experimenting on the new operating system?&lt;/li&gt;
&lt;li&gt;How to operate with files and folders?&lt;/li&gt;
&lt;li&gt;How to install/​run an application?&lt;/li&gt;
&lt;li&gt;What is the minimal knowledge I need in order to be able to work on my programming tasks?&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;new-libraries-and-tools&#34;&gt;New Libraries and Tools&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Why do I need this?&lt;/li&gt;
&lt;li&gt;What are the features and use-cases I will be using?&lt;/li&gt;
&lt;li&gt;What are the names of functions/​methods I will be working with frequently?&lt;/li&gt;
&lt;li&gt;What do I need to do to use this?&lt;/li&gt;
&lt;li&gt;Is it documented?&lt;/li&gt;
&lt;li&gt;Does it have a forum?&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;new-projects&#34;&gt;New Projects&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;What is the aim of the project?&lt;/li&gt;
&lt;li&gt;Are there technologies in use that I do have experience with?&lt;/li&gt;
&lt;li&gt;What are the technologies in use which I do not have experience with? Is it urgent to learn them?&lt;/li&gt;
&lt;li&gt;What are the main features of the project?&lt;/li&gt;
&lt;li&gt;What will I have to interact with first in the project?&lt;/li&gt;
&lt;li&gt;Can I play around with the project and do some experiments without being in danger of doing any harm to it?&lt;/li&gt;
&lt;li&gt;Is it documented?&lt;/li&gt;
&lt;li&gt;How am I going to work with it, what do I need to download/​install, and what networks am I going to access?&lt;/li&gt;
&lt;li&gt;How is the personality of the client affecting the working relationship? Am I going to have an easy time or not in my first days?&lt;/li&gt;
&lt;li&gt;Where are the vital points of the project and can I take a look at the code there to have a vague understanding of what is being done?&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;new-concepts&#34;&gt;New Concepts&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;What is the definition of the concept?&lt;/li&gt;
&lt;li&gt;Is it related to something I already know?&lt;/li&gt;
&lt;li&gt;Does it have subconcepts?&lt;/li&gt;
&lt;li&gt;Do I need to understand something complex? If so, can I find/​draw some illustrative diagrams?&lt;/li&gt;
&lt;li&gt;Can I make a fairly accurate allegory, using elements I am aware of?&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;allegory&#34;&gt;Allegory&lt;/h3&gt;
&lt;p&gt;In general, if something is not understandable at all for me, or has so many elements that it will be difficult to remember them all, I construct an allegory, using concepts I am already aware of. This way, if I forget anything from my newly acquired knowledge, then I think about my allegory, which serves as a mental decryption method.&lt;/p&gt;
&lt;p&gt;For instance, when I learned about object oriented concepts, I used the allegory of set theory to understand the concepts.&lt;/p&gt;
&lt;p&gt;I viewed classes as active sets, that is, sets which might have executable methods.&lt;/p&gt;
&lt;p&gt;I viewed objects as items in a set, which, on their own have their capability to perform actions.&lt;/p&gt;
&lt;p&gt;I viewed inheritance as a subset relation.&lt;/p&gt;
&lt;p&gt;To make the allegory more or less full, I had trouble integrating abstract classes and interfaces into the allegory, but after thinking about them, I came up with a solution. I considered abstract classes as partial definitions of a set and interfaces as declarations of the sets. Since neither had a complete definition, I needed a nonabstract subset to find items to these sets.&lt;/p&gt;
&lt;p&gt;Method overloading was easily understood for me as doing something using different domains. a * b is different if both a and b are real numbers and different if they are complex, basically we do the same operations, but with different variables. I added method overriding into my allegory as an evolution of methods, or as a specialization.&lt;/p&gt;
&lt;p&gt;The allegory is not necessarily 100% analogous with the concepts to be grasped, but if its accuracy is fairly high, then it’s a good starting point. In many cases this is enough by itself, but when it’s not enough, the allegory helped me to formulate intelligent questions, which I could transform to keywords which are searchable by a search engine.&lt;/p&gt;
&lt;h3 id=&#34;notes&#34;&gt;Notes&lt;/h3&gt;
&lt;p&gt;I am sure I am not the only human being with bad sectors in his/​her brain. Have you ever had the experience of totally understanding something and then repeatedly forgetting an important detail, but only that detail? Luckily, we are not in a classroom where we need to reproduce accurately all the verses of a long poem. We can write notes. If I observe that I regularly forget something important, then I make notes.&lt;/p&gt;
&lt;h3 id=&#34;closing-words&#34;&gt;Closing Words&lt;/h3&gt;
&lt;p&gt;The methods I described in this article work well for me. We are all different and what works for me does not necessarily work for you and vice versa. However, I think that this approach can be personalized. If you feel that you need to do things differently in comparison to what I described here, then you are probably right, as you have a different brain and it probably does not work in the exact same way as mine.&lt;/p&gt;
&lt;p&gt;For me, when I learn, frequent short breaks are helpful, as my subconscious is working out without any effort some details which are more difficult for my conscious thinking. After I read an article, if I take a walk and breath fresh air, I tend to have deeper knowledge when I return than when I started to walk.&lt;/p&gt;
&lt;p&gt;It is possible that you need to learn in a totally different way. My words here are not carved into stone. My advice, in general is to not be afraid of new challenges and technologies. It is awesome if you add learning into your comfort zone!&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Drupal — rapid development</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2017/05/drupal-rapid-development/"/>
      <id>https://www.endpointdev.com/blog/2017/05/drupal-rapid-development/</id>
      <published>2017-05-26T00:00:00+00:00</published>
      <author>
        <name>Piotr Hankiewicz</name>
      </author>
      <content type="html">
        &lt;div class=&#34;separator&#34; style=&#34;clear: both; text-align: center;&#34;&gt;&lt;a href=&#34;/blog/2017/05/drupal-rapid-development/image-0.gif&#34; imageanchor=&#34;1&#34; style=&#34;margin-left: 1em; margin-right: 1em;&#34;&gt;&lt;img border=&#34;0&#34; data-original-height=&#34;279&#34; data-original-width=&#34;640&#34; src=&#34;/blog/2017/05/drupal-rapid-development/image-0.gif&#34;/&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Here at End Point, we had the pleasure to be a part of multiple &lt;strong&gt;Drupal&lt;/strong&gt; &lt;strong&gt;6&lt;/strong&gt;, &lt;strong&gt;7&lt;/strong&gt; and &lt;strong&gt;8&lt;/strong&gt; projects. Most of our clients wanted to use the latest Drupal version, to have a long term support, stable platform.&lt;/p&gt;
&lt;p&gt;A few years ago, I already had big experience with PHP itself and other, various PHP frameworks like WordPress, Joomla! or TYPO3. I was happy to use all of them, but then one of our clients asked us for a simple Drupal 6 task. That’s how I started my Drupal journey which continues until now.&lt;/p&gt;
&lt;p&gt;To be honest, I had a difficult start, it was different, new and pretty inscrutable for me. After a few days of reading documentation and playing with the system I was ready to do some simple work. Here, I wanted to share my thoughts about Drupal and tell you why &lt;strong&gt;I LOVE!&lt;/strong&gt; it.&lt;/p&gt;
&lt;h3 id=&#34;low-learning-curve&#34;&gt;Low learning curve&lt;/h3&gt;
&lt;p&gt;It took, of course, a few months until I was ready to build something more complex, but it really takes a few days only to be ready for simple development. It’s not only about Drupal, but also PHP, it’s much cheaper to maintain and extend a project. Maybe it’s not so important with smaller projects, but definitely important for massive code bases. Programmers can jump in and start being &lt;strong&gt;productive&lt;/strong&gt; really quick.&lt;/p&gt;
&lt;h3 id=&#34;great-documentation&#34;&gt;Great documentation&lt;/h3&gt;
&lt;p&gt;Drupal documentation is well structured and constantly developed, usually you can find what you need within a few minutes. It’s critical and must have for any other framework and not so common unfortunately.&lt;/p&gt;
&lt;h3 id=&#34;big-community&#34;&gt;Big community&lt;/h3&gt;
&lt;p&gt;The Drupal community is one of the biggest IT communities I have ever encountered. They extend, fix and document the Drupal core regularly. Most of them have their other jobs and work on this project just for fun and with passion.&lt;/p&gt;
&lt;h3 id=&#34;its-free&#34;&gt;It’s free&lt;/h3&gt;
&lt;p&gt;It’s an open source project, that’s one of the biggest pros here. You can get it for free, you can get support &lt;strong&gt;for free&lt;/strong&gt;, you can join the community for free too (:)).&lt;/p&gt;
&lt;div class=&#34;separator&#34; style=&#34;clear: both; text-align: center;&#34;&gt;&lt;a href=&#34;/blog/2017/05/drupal-rapid-development/image-1-big.png&#34; imageanchor=&#34;1&#34; style=&#34;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&#34;&gt;&lt;img border=&#34;0&#34; data-original-height=&#34;318&#34; data-original-width=&#34;318&#34; height=&#34;200&#34; src=&#34;/blog/2017/05/drupal-rapid-development/image-1.png&#34; width=&#34;200&#34;/&gt;&lt;/a&gt;&lt;/div&gt;
&lt;h3 id=&#34;modules&#34;&gt;Modules&lt;/h3&gt;
&lt;p&gt;On the official Drupal website you can find tons of free plugins/modules. It’s a time and money saver, you don’t need to reinvent the wheel for every new widget on your website and focus on fireworks.&lt;/p&gt;
&lt;p&gt;Usually you can just go there and find a proper component. E-commerce shop? Slideshow? Online classifieds website? No problem! It’s all there.&lt;/p&gt;
&lt;h3 id=&#34;php7-support&#34;&gt;PHP7 support&lt;/h3&gt;
&lt;p&gt;I can often hear from other developers that PHP is slow, well, it’s not the Road Runner, but come on, unless you are Facebook (and I think that they, correct me if I’m wrong, still use PHP :)) it’s just OK to use PHP.&lt;/p&gt;
&lt;p&gt;Drupal fully supports PHP7.&lt;/p&gt;
&lt;p&gt;With PHP7 it’s much faster, better and safer. To learn more: &lt;a href=&#34;https://pages.zend.com/rs/zendtechnologies/images/PHP7-Performance%20Infographic.pdf&#34;&gt;https://pages.zend.com/rs/zendtechnologies/images/PHP7-Performance%20Infographic.pdf&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In the infographic you can see that &lt;strong&gt;PHP7&lt;/strong&gt; is much faster than &lt;strong&gt;Ruby&lt;/strong&gt;, &lt;strong&gt;Perl&lt;/strong&gt; and &lt;strong&gt;Python&lt;/strong&gt; when you try to render a Mandelbrot fractal. In general, you definitely can’t say that PHP is slow, same as Drupal.&lt;/p&gt;
&lt;h3 id=&#34;rest-api-support&#34;&gt;REST API support&lt;/h3&gt;
&lt;p&gt;Drupal has the built in, ready to use API system. In a few moments you can spawn a new API endpoint for you application. You don’t need to implement a whole API by yourself, I did it a few times in multiple languages, believe me, it’s problematic.&lt;/p&gt;
&lt;h3 id=&#34;perfect-for-a-backend-system&#34;&gt;Perfect for a backend system&lt;/h3&gt;
&lt;p&gt;Drupal is a perfect candidate for a backend system. Let’s imagine that you want to build a beautiful, mobile application. You want to let editors, other people to edit content. You want to grab this content through the API. It’s easy as pie with Drupal.&lt;/p&gt;
&lt;p&gt;Drupal’s web interface is stable and easy to use.&lt;/p&gt;
&lt;h3 id=&#34;power-of-taxonomies&#34;&gt;Power of taxonomies&lt;/h3&gt;
&lt;p&gt;Taxonomies are, really basically, just dictionaries. The best thing about taxonomies is that you don’t need to touch code to play with them.&lt;/p&gt;
&lt;p&gt;Let’s say that on your website you want to create a list of states in the USA. Using most of the frameworks you need to ask your developer/technical person to do so. With taxonomies you just need a few clicks and that’s it, you can put in on your website. That’s sweet, not only for non technical person, but for us, developers as well. Again, you can focus on actually making the website attractive, rather than spending time on things that can be automated.&lt;/p&gt;
&lt;h3 id=&#34;summary&#34;&gt;Summary&lt;/h3&gt;
&lt;p&gt;Of course, Drupal is not perfect, but it’s undeniably a great tool. Mobile application, single page application, corporate website—​there are no limits for this content management system. And actually, it is, in my opinion, the best tool to manage your content and it does not mean that you need to use Drupal to present it. You can create a &lt;strong&gt;mobile&lt;/strong&gt;, &lt;strong&gt;ReactJS&lt;/strong&gt;, &lt;strong&gt;AngularJS&lt;/strong&gt;, &lt;strong&gt;VueJS&lt;/strong&gt; application and combine it with Drupal easily.&lt;/p&gt;
&lt;p&gt;I hope that you’ve had a good reading and wish to hear back from you! Thanks.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Strict typing fun example — Free Monads in Haskell</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2016/03/strict-typing-fun-example-free-monads/"/>
      <id>https://www.endpointdev.com/blog/2016/03/strict-typing-fun-example-free-monads/</id>
      <published>2016-03-11T00:00:00+00:00</published>
      <author>
        <name>Kamil Ciemniewski</name>
      </author>
      <content type="html">
        &lt;p&gt;From time to time I’ve got a chance to discuss different programming paradigms with colleagues. Very often I like steering the discussion into the programming languages realm as it’s something that interests me a lot.&lt;/p&gt;
&lt;p&gt;Looking at the most popular languages list on GitHub, published last August, we can see that in the most popular five, we only have one that is “statically typed”. &lt;a href=&#34;https://github.com/blog/2047-language-trends-on-github&#34;&gt;https://github.com/blog/2047-language-trends-on-github&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The most popular languages on GitHub as of August 2015:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;JavaScript&lt;/li&gt;
&lt;li&gt;Java&lt;/li&gt;
&lt;li&gt;Ruby&lt;/li&gt;
&lt;li&gt;PHP&lt;/li&gt;
&lt;li&gt;Python&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The dynamic typing approach gives great flexibility. It very often empowers teams to be more productive. There are use cases for static type systems I feel that many people are not aware of though.
I view this post as an experiment. I’d like to present you with a pattern that’s being used in Haskell and Scala worlds (among others). The pattern is especially helpful in these contexts as both Haskell and Scala have extremely advanced type systems (comparing to e. g. Java or C++ and not to mention Ruby or Python).&lt;/p&gt;
&lt;p&gt;My goal is not to explain in detail all the subtleties of the code I’m going to present. The learning curve for both languages can be pretty dramatic. The goal is to make you a bit curious about alternative development styles and how they could be very powerful.&lt;/p&gt;
&lt;h3 id=&#34;short-intro-to-the-idea-behind-the-pattern&#34;&gt;Short intro to the idea behind the pattern&lt;/h3&gt;
&lt;p&gt;The pattern I’m going to present is called the “Free Monad + Interpreter”. The idea behind it is that we can build &lt;a href=&#34;https://en.wikipedia.org/wiki/Domain-specific_language&#34;&gt;DSLs&lt;/a&gt; (domain specific languages) by making our functions not execute the code immediately, but to build the &lt;a href=&#34;https://en.wikipedia.org/wiki/Abstract_syntax_tree&#34;&gt;AST&lt;/a&gt; (abstract syntax tree) out of it and interpret it in different ways depending on the context.&lt;/p&gt;
&lt;p&gt;A fun example I came up with is a DSL for system &lt;a href=&#34;https://en.wikipedia.org/wiki/Provisioning#Server_provisioning&#34;&gt;provisioning&lt;/a&gt; scripts that—​among many use cases one could come up with—​allows to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;present the AST in bash or zsh code or whatever other language like Python, Ruby or Perl&lt;/li&gt;
&lt;li&gt;present the AST as a graph to visualize the execution&lt;/li&gt;
&lt;li&gt;execute it directly, natively in Haskell&lt;/li&gt;
&lt;li&gt;have an easy-to-comprehend set of provisioning instructions while lower level aspects like file handles etc.—​being handled in common Haskell code used for the execution of ASTs&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There are potentially many more use cases but I just wanted to show you a couple—​enough to hopefully make you a bit curious. In this post we’ll focus on interpreting the AST as a bash script.&lt;/p&gt;
&lt;h3 id=&#34;the-coding-part&#34;&gt;The coding part&lt;/h3&gt;
&lt;p&gt;The first step is to define the set of instructions our interpreted Domain Specific Language will support:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-haskell&#34; data-lang=&#34;haskell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;Provision&lt;/span&gt; next &lt;span style=&#34;color:#080&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;Begin&lt;/span&gt; next |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;Install&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;String&lt;/span&gt; next |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;IfNotExists&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;String&lt;/span&gt; (&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;Free&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;Provision&lt;/span&gt; &lt;span style=&#34;color:#038&#34;&gt;()&lt;/span&gt;) next |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;Touch&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;String&lt;/span&gt; next |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;Cd&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;String&lt;/span&gt; next |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;MkDir&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;String&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;Bool&lt;/span&gt; next |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;Echo&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;String&lt;/span&gt; next |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;Continue&lt;/span&gt; |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;Done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;deriving&lt;/span&gt;(&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;Functor&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This odd looking definition is what’s called an &lt;a href=&#34;https://en.wikipedia.org/wiki/Algebraic_data_type&#34;&gt;Algebraic Data Type&lt;/a&gt;. For now it should suffice that the commands can take arguments of different types and almost all of them take a continuation command as the last parameter.&lt;/p&gt;
&lt;p&gt;The continuation parameter is meant to store the next “provisioning command” so that we would have e.g:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-haskell&#34; data-lang=&#34;haskell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;Begin&lt;/span&gt; (&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;Install&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;postgresql-server&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;Echo&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;installed!&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;Done&lt;/span&gt;)))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Out of these blocks, our ASTs will be created. We need some way of composing these blocks into AST trees. I’m not going to explain here why the following code works—​it’s just a teaser post. Let’s just say that the following functions allow us to just build the tree instead of calling any system-affecting code. In other words, it allows these calls to look as if they’re doing something when in fact they are just constructing the data structure in memory:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-haskell&#34; data-lang=&#34;haskell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;begin&lt;/span&gt; &lt;span style=&#34;color:#080&#34;&gt;=&lt;/span&gt; liftF $ &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;Begin&lt;/span&gt; id
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;install&lt;/span&gt; what &lt;span style=&#34;color:#080&#34;&gt;=&lt;/span&gt; liftF $ &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;Install&lt;/span&gt; what id
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;ifNotExists&lt;/span&gt; path what &lt;span style=&#34;color:#080&#34;&gt;=&lt;/span&gt; liftF $ &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;IfNotExists&lt;/span&gt; path what id
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;touch&lt;/span&gt; path &lt;span style=&#34;color:#080&#34;&gt;=&lt;/span&gt; liftF $ &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;Touch&lt;/span&gt; path id
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;cd&lt;/span&gt; path &lt;span style=&#34;color:#080&#34;&gt;=&lt;/span&gt; liftF $ &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;Cd&lt;/span&gt; path id
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;mkDir&lt;/span&gt; path wholeTree &lt;span style=&#34;color:#080&#34;&gt;=&lt;/span&gt; liftF $ &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;MkDir&lt;/span&gt; path wholeTree id
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;echo&lt;/span&gt; message &lt;span style=&#34;color:#080&#34;&gt;=&lt;/span&gt; liftF $ &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;Echo&lt;/span&gt; message id
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;continue&lt;/span&gt; &lt;span style=&#34;color:#080&#34;&gt;=&lt;/span&gt; liftF $ &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;Continue&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;done&lt;/span&gt; &lt;span style=&#34;color:#080&#34;&gt;=&lt;/span&gt; liftF &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;Done&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now that we have these building functions defined, we can create a function that uses them to construct a useful AST:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-haskell&#34; data-lang=&#34;haskell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;app&lt;/span&gt; &lt;span style=&#34;color:#080&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;Free&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;Provision&lt;/span&gt; a
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;app&lt;/span&gt; &lt;span style=&#34;color:#080&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  begin
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  install &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;postgresql-server&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  mkDir &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;/var/run/the-app&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  cd &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;/var/run/the-app&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ifNotExists &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;the-app.log&amp;#34;&lt;/span&gt; $ touch &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;the-app.log&amp;#34;&lt;/span&gt; &amp;gt;&amp;gt; continue
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  done&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Running this function does nothing except for returning AST wrapped inside the “free monad”—​which you can think of as a special, useful kind of container. The above function looks like any other Haskell function. It’s also “type safe”—​which weeds out one class of errors that we’re only able to notice &lt;strong&gt;after&lt;/strong&gt; we ran the code—​in languages like JavaScript or Python.&lt;/p&gt;
&lt;p&gt;Later on we’ll see that to get different results out of the “provisioning workflow” we defined above, no change in this function will be needed.&lt;/p&gt;
&lt;p&gt;Now, having an AST tree wrapped around some “useful” container almost screams for some kind of an interpreter for this to be useful too. That’s in fact part of the description of the pattern I gave you in the beginning of this post.&lt;/p&gt;
&lt;p&gt;Let’s define a set of data types linked with the function that we’ll use as an interpreter:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-haskell&#34; data-lang=&#34;haskell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;InterpretingContext&lt;/span&gt; a &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;where&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  run &lt;span style=&#34;color:#080&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;Free&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;Provision&lt;/span&gt; &lt;span style=&#34;color:#038&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#080&#34;&gt;-&amp;gt;&lt;/span&gt; a&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The above just says that if we want to use the function &lt;strong&gt;run&lt;/strong&gt; to turn the AST wrapped in a monad to some concrete value (by executing it)—​we need to implement this function for the type of the concrete value we’d like to get out of it.&lt;/p&gt;
&lt;p&gt;For example, let’s say that for the portability sakes we want to turn the AST into the bash script. The natural (though naive) way to do this would be to implement this “class” along with its &lt;strong&gt;run&lt;/strong&gt; function for the type of &lt;strong&gt;String&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-haskell&#34; data-lang=&#34;haskell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;instance&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;InterpretingContext&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;String&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;where&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  run (&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;Free&lt;/span&gt; (&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;Begin&lt;/span&gt; next)) &lt;span style=&#34;color:#080&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;#!/usr/bin/env bash&lt;/span&gt;&lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;\n\n&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&lt;/span&gt; ++ (run next)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  run (&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;Free&lt;/span&gt; (&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;Install&lt;/span&gt; what next)) &lt;span style=&#34;color:#080&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;apt-get install &amp;#34;&lt;/span&gt; ++ what ++ &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&lt;/span&gt; ++ nextStr
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;where&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      nextStr &lt;span style=&#34;color:#080&#34;&gt;=&lt;/span&gt; run next
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  run (&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;Free&lt;/span&gt; (&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;IfNotExists&lt;/span&gt; path what next)) &lt;span style=&#34;color:#080&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;if [ ! -f &amp;#34;&lt;/span&gt; ++ path ++ &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34; ]; then&lt;/span&gt;&lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;\n\t&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&lt;/span&gt; ++ whatStr
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      ++ &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;fi&lt;/span&gt;&lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&lt;/span&gt; ++ nextStr
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;where&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      whatStr &lt;span style=&#34;color:#080&#34;&gt;=&lt;/span&gt; run what
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      nextStr &lt;span style=&#34;color:#080&#34;&gt;=&lt;/span&gt; run next
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  run (&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;Free&lt;/span&gt; (&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;Touch&lt;/span&gt; path next)) &lt;span style=&#34;color:#080&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;touch &amp;#34;&lt;/span&gt; ++ path ++ &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&lt;/span&gt; ++ (run next)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  run (&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;Free&lt;/span&gt; (&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;Cd&lt;/span&gt; path next)) &lt;span style=&#34;color:#080&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;cd &amp;#34;&lt;/span&gt; ++ path ++ &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&lt;/span&gt; ++ (run next)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  run (&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;Free&lt;/span&gt; (&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;MkDir&lt;/span&gt; path tree next)) &lt;span style=&#34;color:#080&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;mkdir &amp;#34;&lt;/span&gt; ++ treeOption ++ &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt; ++ path ++ &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&lt;/span&gt; ++ (run next)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;where&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      treeOption &lt;span style=&#34;color:#080&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; tree &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;then&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;-p&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  run (&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;Free&lt;/span&gt; (&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;Echo&lt;/span&gt; message next)) &lt;span style=&#34;color:#080&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;echo &amp;#34;&lt;/span&gt; ++ message ++ &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&lt;/span&gt; ++ (run next)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  run (&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;Free&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;Continue&lt;/span&gt;) &lt;span style=&#34;color:#080&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  run (&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;Free&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;Done&lt;/span&gt;) &lt;span style=&#34;color:#080&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;exit 0&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Each node kind is being &lt;strong&gt;interpreted&lt;/strong&gt; as a data type we chose to be one of the &lt;strong&gt;instances of this class&lt;/strong&gt;—​in our example a &lt;strong&gt;String&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;What this allows us to do, is to use the &lt;strong&gt;run&lt;/strong&gt; function, specifying that we want a &lt;strong&gt;String&lt;/strong&gt; as a return value and automatically the instance we’ve just created will be used:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-haskell&#34; data-lang=&#34;haskell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;run&lt;/span&gt; app &lt;span style=&#34;color:#080&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;String&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will return:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-haskell&#34; data-lang=&#34;haskell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;#!/usr/bin/env bash&lt;/span&gt;&lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;\n\n&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;apt-get install postgresql-server&lt;/span&gt;&lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;mkdir -p /var/run/the-app&lt;/span&gt;&lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;cd /var/run/the-app&lt;/span&gt;&lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;if [ ! -f the-app.log ]; then&lt;/span&gt;&lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;\n\t&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;touch the-app.log&lt;/span&gt;&lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;\n\n&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;fi&lt;/span&gt;&lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;exit 0&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Pretty printed:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;#!/usr/bin/env bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt-get install postgresql-server
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir -p /var/run/the-app
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;cd&lt;/span&gt; /var/run/the-app
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; [ ! -f the-app.log ]; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    touch the-app.log
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;exit&lt;/span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If now we’d like to execute the AST in the context of an action that prints the script to stdout we could do so like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-haskell&#34; data-lang=&#34;haskell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;instance&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;InterpretingContext&lt;/span&gt; (&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;IO&lt;/span&gt; &lt;span style=&#34;color:#038&#34;&gt;()&lt;/span&gt;) &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;where&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  run &lt;span style=&#34;color:#080&#34;&gt;=&lt;/span&gt; print . run&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;From now on it would be perfectly valid to run the function with AST in both contexts:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-haskell&#34; data-lang=&#34;haskell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;run&lt;/span&gt; app &lt;span style=&#34;color:#080&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;String&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;run&lt;/span&gt; app &lt;span style=&#34;color:#080&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;IO&lt;/span&gt; &lt;span style=&#34;color:#038&#34;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We could add a context returning an ExitStatus by running the code against the system very easily too:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-haskell&#34; data-lang=&#34;haskell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;ExitStatus&lt;/span&gt; &lt;span style=&#34;color:#080&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;ExitSuccess&lt;/span&gt; | &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;ExitFailure&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;Int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;instance&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;InterpretingContext&lt;/span&gt; (&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;IO&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;ExitStatus&lt;/span&gt;) &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;where&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  run &lt;span style=&#34;color:#080&#34;&gt;=&lt;/span&gt; (&lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;…&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;What this gives us is the ability to have the provisioning code that could be run in production while having a different interpreter in the testing suite to be able to ensure the structure of execution without inflicting any changes to the system itself.&lt;/p&gt;
&lt;p&gt;If you’d like to play with the code yourself, you’ll need a couple of more lines for this to work:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-haskell&#34; data-lang=&#34;haskell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;{-# LANGUAGE DeriveFunctor #-}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;{-# LANGUAGE FlexibleContexts #-}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;{-# LANGUAGE FlexibleInstances #-}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;{-# LANGUAGE TypeSynonymInstances #-}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;{-# LANGUAGE OverloadedStrings #-}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And also:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-haskell&#34; data-lang=&#34;haskell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;Control.Monad.Free&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Bear in mind though that the code I presented here is by no means optimal—​especially memory wise. I chose to present it this way for the clarity of what the code is doing for those of you not familiar with the language.&lt;/p&gt;
&lt;h3 id=&#34;what-are-other-use-cases-for-this-pattern&#34;&gt;What are other use cases for this pattern?&lt;/h3&gt;
&lt;p&gt;The pattern presented here has a huge number of uses. It could be used for providing a DSL for building SVG combined with an interpreter that could draw it visually for the ease of work. It could also be used for defining RPC data types describing structures and interpreting them differently based on the underlying &lt;a href=&#34;https://en.wikipedia.org/wiki/Remote_procedure_call&#34;&gt;RPC&lt;/a&gt; (remote procedure call) mechanics (Thrift, SOAP etc).&lt;/p&gt;
&lt;p&gt;I doubt that the ability this gives thanks to the &lt;strong&gt;very helpful&lt;/strong&gt; Haskell type system could be reproduced in languages like Ruby or Python easily. It is possible of course, but the amount of boilerplate code and complexity would require lots of testing code too. Here on the other hand the code holds many guarantees just because we’re coding in a language with an advanced strict type system.&lt;/p&gt;
&lt;p&gt;Also, the similarity to the &lt;a href=&#34;https://en.wikipedia.org/wiki/Interpreter_pattern&#34;&gt;Interpreter Pattern&lt;/a&gt; known from the object oriented languages is only superficial. In that case there’s no way to use regular normal functions (or methods) to build AST—​as if it was a regular imperative code. It’s always about some weird mangling of data structures by hand.&lt;/p&gt;
&lt;h3 id=&#34;curious&#34;&gt;Curious?&lt;/h3&gt;
&lt;p&gt;If I managed to make you a bit curious about the aspects I presented here, here are some of the resources you might want to take a look at:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://learnyouahaskell.com/chapters&#34;&gt;Learn You a Haskell — online book&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://book.realworldhaskell.org/read/&#34;&gt;Real World Haskell — online book&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html&#34;&gt;A pleasant visual tutorial about functors and monads&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://wiki.haskell.org/Monad&#34;&gt;Haskell Wiki article on monads&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://programmers.stackexchange.com/questions/242795/what-is-the-free-monad-interpreter-pattern&#34;&gt;A fantastic intro to the Free Monad pattern&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

      </content>
    </entry>
  
    <entry>
      <title>Coding style guides across languages</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2015/08/coding-style-guides-across-languages/"/>
      <id>https://www.endpointdev.com/blog/2015/08/coding-style-guides-across-languages/</id>
      <published>2015-08-17T00:00:00+00:00</published>
      <author>
        <name>Piotr Hankiewicz</name>
      </author>
      <content type="html">
        &lt;h3 id=&#34;introduction&#34;&gt;Introduction&lt;/h3&gt;
&lt;p&gt;Before you can start programming production code in any programming language you should know a few things like syntax, purpose, coding standards, good practices. There is another thing that is really important too and can help developers that work with multiple projects and languages: coding style guides. This is just a set of rules that developers should take care about when writing code. They are not so different across various programming languages. In this article, I will sum up and list coding style guides for the most popular languages.&lt;/p&gt;
&lt;p&gt;It’s not a crime to use different styling, but standardizing this helps in the process of creating software. When your team is using the same standard it’s much easier to read each other’s code.&lt;/p&gt;
&lt;p&gt;There is one universal resource when it comes to programming style guides. Many of you will already have read it: the “Clean Code” book by Robert C. Martin.&lt;/p&gt;
&lt;p&gt;Something else that should be mentioned here:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;When you don’t know how to write a structure, read guides.&lt;/li&gt;
&lt;li&gt;When you know how to write a structure but it’s different than standardized, ask other developers about it.&lt;/li&gt;
&lt;li&gt;When your structure is different than all the other structures made by your co-workers, consider changing it.&lt;/li&gt;
&lt;li&gt;When someone will force you to change your styling code, ask her/him/them why, even if she/he/they are your manager or boss.&lt;/li&gt;
&lt;li&gt;When there is no good coding style guide for your language, create one.&lt;/li&gt;
&lt;li&gt;Try to have the same habits of coding in your team and company—​it’s a time saver.&lt;/li&gt;
&lt;li&gt;Even if you’ve adapted to some structures be open for change.&lt;/li&gt;
&lt;li&gt;Respect experience. If senior developers tell you that your code is weird, there is probably something wrong with it.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Order of the guides is not random, most important and trusted first. Not all the guides cover all the topics so it would be wise to real all of them when you plan to write code in such a language.&lt;/p&gt;
&lt;p&gt;Let’s begin.&lt;/p&gt;
&lt;h4 id=&#34;java&#34;&gt;Java&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://www.oracle.com/technetwork/java/codeconventions-150003.pdf&#34;&gt;http://www.oracle.com/technetwork/java/codeconventions-150003.pdf&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://google.github.io/styleguide/javaguide.html&#34;&gt;https://google.github.io/styleguide/javaguide.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.scribd.com/doc/15884743/Java-Coding-Style-by-Achut-Reddy&#34;&gt;https://www.scribd.com/doc/15884743/Java-Coding-Style-by-Achut-Reddy&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;c&#34;&gt;C&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://www.maultech.com/chrislott/resources/cstyle/indhill-annot.pdf&#34;&gt;http://www.maultech.com/chrislott/resources/cstyle/indhill-annot.pdf&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.maultech.com/chrislott/resources/cstyle/Peter_CStyleGuide.pdf&#34;&gt;http://www.maultech.com/chrislott/resources/cstyle/Peter_CStyleGuide.pdf&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.maultech.com/chrislott/resources/cstyle/LinuxKernelCodingStyle.txt&#34;&gt;http://www.maultech.com/chrislott/resources/cstyle/LinuxKernelCodingStyle.txt&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;c-1&#34;&gt;C++&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://www.maultech.com/chrislott/resources/cstyle/Ellemtel-rules-mm.pdf&#34;&gt;http://www.maultech.com/chrislott/resources/cstyle/Ellemtel-rules-mm.pdf&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.maultech.com/chrislott/resources/cstyle/Wildfire-C++Style.html&#34;&gt;http://www.maultech.com/chrislott/resources/cstyle/Wildfire-C++Style.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.maultech.com/chrislott/resources/cstyle/CppCodingStandard.html&#34;&gt;http://www.maultech.com/chrislott/resources/cstyle/CppCodingStandard.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;c-2&#34;&gt;C#&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/index&#34;&gt;https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/index&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.idesign.net/Downloads/GetDownload/1985&#34;&gt;http://www.idesign.net/Downloads/GetDownload/1985&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.dotnetspider.com/tutorials/BestPractices.aspx&#34;&gt;http://www.dotnetspider.com/tutorials/BestPractices.aspx&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;python&#34;&gt;Python&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.python.org/dev/peps/pep-0008/&#34;&gt;https://www.python.org/dev/peps/pep-0008/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.python.org/dev/peps/pep-0257/&#34;&gt;https://www.python.org/dev/peps/pep-0257/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://python.net/~goodger/projects/pycon/2007/idiomatic/handout.html&#34;&gt;http://python.net/~goodger/projects/pycon/2007/idiomatic/handout.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.memonic.com/user/pneff/folder/python/id/1bufp&#34;&gt;https://www.memonic.com/user/pneff/folder/python/id/1bufp&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;objective-c&#34;&gt;Objective-C&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CodingGuidelines/CodingGuidelines.html&#34;&gt;https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CodingGuidelines/CodingGuidelines.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://google.github.io/styleguide/objcguide.html&#34;&gt;http://google.github.io/styleguide/objcguide.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://cocoadevcentral.com/articles/000082.php&#34;&gt;http://cocoadevcentral.com/articles/000082.php&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;php&#34;&gt;PHP&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://www.php-fig.org/psr/psr-1/&#34;&gt;http://www.php-fig.org/psr/psr-1/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://pear.php.net/manual/en/standards.php&#34;&gt;http://pear.php.net/manual/en/standards.php&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://framework.zend.com/manual/1.12/en/coding-standard.coding-style.html&#34;&gt;https://framework.zend.com/manual/1.12/en/coding-standard.coding-style.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;visual-basic-net&#34;&gt;Visual Basic .NET&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/index&#34;&gt;https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/index&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;javascript&#34;&gt;JavaScript&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/airbnb/javascript&#34;&gt;https://github.com/airbnb/javascript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://google.github.io/styleguide/javascriptguide.xml&#34;&gt;http://google.github.io/styleguide/javascriptguide.xml&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.w3schools.com/js/js_conventions.asp&#34;&gt;https://www.w3schools.com/js/js_conventions.asp&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;visual-basic&#34;&gt;Visual Basic&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.microsoft.com/en-us/dotnet/visual-basic/programming-guide/program-structure/coding-conventions&#34;&gt;https://docs.microsoft.com/en-us/dotnet/visual-basic/programming-guide/program-structure/coding-conventions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;perl&#34;&gt;Perl&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://shop.oreilly.com/product/9780596001735.do&#34;&gt;http://shop.oreilly.com/product/9780596001735.do&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://wiki.dictybase.org/dictywiki/index.php/Perl_Coding_Standards#Documentation&#34;&gt;http://wiki.dictybase.org/dictywiki/index.php/Perl_Coding_Standards#Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://perldoc.perl.org/perlstyle.html&#34;&gt;http://perldoc.perl.org/perlstyle.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;assembly&#34;&gt;Assembly&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://www.sourceformat.com/coding-standard-asm.htm&#34;&gt;http://www.sourceformat.com/coding-standard-asm.htm&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;ruby&#34;&gt;Ruby&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/bbatsov/ruby-style-guide&#34;&gt;https://github.com/bbatsov/ruby-style-guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/airbnb/ruby&#34;&gt;https://github.com/airbnb/ruby&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.caliban.org/ruby/rubyguide.shtml&#34;&gt;http://www.caliban.org/ruby/rubyguide.shtml&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;Maybe it’s not the most important programming part but it’s something you need to think about.&lt;/p&gt;
&lt;p&gt;If we will try to compare those rules to human language, English for example, see “Romeo and Juliet”, Act III:&lt;/p&gt;
&lt;p&gt;MERCUTIO&lt;/p&gt;
&lt;p&gt;Come, come, thou art as hot a Jack in thy mood as
any in Italy, and as soon moved to be moody, and as
soon moody to be moved.&lt;/p&gt;
&lt;p&gt;Now try to remove writing standards:&lt;/p&gt;
&lt;p&gt;MERCUTIO Come, come, thou art as hot a Jack in thy mood as any in Italy, and as soon moved to be moody, and as soon moody to be moved.&lt;/p&gt;
&lt;p&gt;It’s not easy to read this one liner. Our code is the same: Be smart, listen to more experienced people, read style guides and you will make live easier for you and other people too.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Perl’s CPAN is 20 years old</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2015/08/perls-cpan-is-20-years-old/"/>
      <id>https://www.endpointdev.com/blog/2015/08/perls-cpan-is-20-years-old/</id>
      <published>2015-08-17T00:00:00+00:00</published>
      <author>
        <name>Jon Jensen</name>
      </author>
      <content type="html">
        &lt;div class=&#34;separator&#34; style=&#34;clear: both; float: right; text-align: center; margin-bottom: 1em&#34;&gt;&lt;a href=&#34;/blog/2015/08/perls-cpan-is-20-years-old/image-0-big.png&#34; imageanchor=&#34;1&#34; style=&#34;clear: right; float: right; margin-bottom: 0.5em; margin-left: 1em;&#34;&gt;&lt;img border=&#34;0&#34; src=&#34;/blog/2015/08/perls-cpan-is-20-years-old/image-0.png&#34;/&gt;&lt;/a&gt;&lt;br/&gt;&lt;small&gt;(Photo by &lt;a href=&#34;https://flic.kr/p/8VPGbE&#34;&gt;emma.kate on Flickr&lt;/a&gt;)&lt;/small&gt;&lt;/div&gt;
&lt;p&gt;This is just a short note to celebrate the fact that &lt;a href=&#34;http://blogs.perl.org/users/neilb/2015/08/cpan-is-20.html&#34;&gt;the Comprehensive Perl Archive Network (CPAN) turned 20 years old&lt;/a&gt; yesterday!&lt;/p&gt;
&lt;p&gt;CPAN began as a way to collect, mirror, and distribute open-source Perl packages. Over time it led to development of better packaging and module naming conventions; formed a community for feedback, testing, and contributions; and became one of the great strengths of the Perl world.&lt;/p&gt;
&lt;p&gt;It is rare to find some needed functionality that is not available on CPAN. These days a more common problem is finding too much choice there, and needing to choose between several modules based on which are better maintained and supported on current versions of Perl, or kept current against external dependencies.&lt;/p&gt;
&lt;p&gt;Perl does not get as much press these days as it once did, but it continues to thrive and improve. On that topic, our former co-worker Steph Skardal sent me an article called &lt;a href=&#34;http://www.virtuouscode.com/2015/08/07/were-still-catching-up-to-perl/&#34;&gt;We’re still catching up to Perl&lt;/a&gt; by Avdi Grimm of Ruby fame. It is not an in-depth language comparison, just a brief observation to his fellow Rubyists that there is plenty to be learned from Perl. (Of course Perl has plenty to learn from Ruby and other languages too.)&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Nothing more permanent than a temporary fix</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2015/07/nothing-more-permanent-than-temporary/"/>
      <id>https://www.endpointdev.com/blog/2015/07/nothing-more-permanent-than-temporary/</id>
      <published>2015-07-28T00:00:00+00:00</published>
      <author>
        <name>Jon Jensen</name>
      </author>
      <content type="html">
        &lt;p&gt;A brief thought:&lt;/p&gt;
&lt;p&gt;You may have heard the saying that nothing is more permanent than a temporary fix. Or that prototypes are things we just haven’t yet recognized will be permanent. Or some variation on the theme.&lt;/p&gt;
&lt;p&gt;As an illustration of this, I recently came across the initial commit to the source code repository of our endpoint.com website when we ported it to Ruby on Rails back in April 2007. Our then co-worker PJ’s comment is a perfect example of how long-lasting some of our planned temporary work can be:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;commit 2ee55da6ed953c049b3ef6f9f132ed3c1e0d4de9
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Author: PJ Cabreras &amp;lt;pj@endpoint.com&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Date:   Wed Apr 18 13:07:46 2007 +0000
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Initial test setup of repository for mkcamp testing -- will probably throw away later
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    git-svn-id: file:///home/camp/endpoint/svnrepo/trunk@1 7e1941c4-622e-0410-b359-a11864f70de7&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It’s wise to avoid big architecture up front for experimental things we don’t know the needed shape and size of. But we should plan on iterating and being agile (in the real basic sense of the word), because we may never have the chance to start over from scratch. And starting over from scratch is often ill-advised in any case.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>To ask or not to ask? Debug first.</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2013/02/to-ask-or-not-to-ask-debug-first/"/>
      <id>https://www.endpointdev.com/blog/2013/02/to-ask-or-not-to-ask-debug-first/</id>
      <published>2013-02-18T00:00:00+00:00</published>
      <author>
        <name>Miguel Alatorre</name>
      </author>
      <content type="html">
        &lt;p&gt;Jumping head first into a project, the ramp up will likely lead to questions galore. In the eagerness of getting things done, it seems like the best thing to do when stuck is to just ask the seasoned developers to tell you how to move forward. After all, they did build the application. However, when to reach out for help can be dependent on the deadline and priority of the task at hand as well as your subjective definition of “stuck.” Knowing when it’s too early, just right, or too late to get help can be a tricky thing. Here are some things to consider when reaching out for help early:&lt;/p&gt;
&lt;p&gt;Pros.&lt;/p&gt;
&lt;p&gt; 1. Time/money is of the essence and getting a quick answer is best.&lt;/p&gt;
&lt;p&gt; 2. Time saved debugging a particular issue that does not further your understanding of the application can be applied elsewhere.&lt;/p&gt;
&lt;p&gt;Cons.&lt;/p&gt;
&lt;p&gt; 1. You risk a learning opportunity by throwing in the towel too early.&lt;/p&gt;
&lt;p&gt; 2. You risk looking lazy or unprepared if the person whom you are reaching out to believes you could have done more.&lt;/p&gt;
&lt;p&gt; 3. Developers are busy, too.&lt;/p&gt;
&lt;p&gt;All cases being different, there is no right time to reach out for help but steps can be taken to ensure that you have your part. First, get better at reading source code. The more you practice reading and making sense of other people’s code, the quicker you will build your complete mental model of the application, and the quicker you’ll be able to debug. Brandon Bloom (snprbob86) wrote an &lt;a href=&#34;https://news.ycombinator.com/item?id=3769446&#34;&gt;excellent post&lt;/a&gt; regarding this. Second, create your own stack trace. The application may have many entry points. Pick one, feed it some input and trace it down the rabbit hole. A white board may come in handy here. Third, make heavy use of the logs. The code should already be sprinkled with plenty of log messages, but feel free to add more wherever you feel they will be useful.&lt;/p&gt;
&lt;p&gt;These three tips will go a long way in helping you debug smarter, which should allow you to find solutions more quickly. In the event that a white flag must be raised and another developer’s help requested, the efforts you made attempting to debug will have a positive impact on your productivity as well as your team’s perception of you as a programmer.&lt;/p&gt;

      </content>
    </entry>
  
</feed>
