<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://felipejoglar.dev/feed.xml" rel="self" type="application/atom+xml" /><link href="https://felipejoglar.dev/" rel="alternate" type="text/html" /><updated>2026-02-04T18:23:20+01:00</updated><id>https://felipejoglar.dev/feed.xml</id><title type="html">felipejoglar.dev</title><subtitle>Here are my approaches when writing software. How I build things 👋 ❤️</subtitle><icon>https://felipejoglar.dev/assets/images/global/favicon.svg</icon><entry><title type="html">Wait, where is my domain?</title><link href="https://felipejoglar.dev/blog/where-is-my-domain/" rel="alternate" type="text/html" title="Wait, where is my domain?" /><published>2024-11-11T00:00:00+01:00</published><updated>2024-11-11T00:00:00+01:00</updated><id>https://felipejoglar.dev/blog/where-is-my-domain</id><content type="html" xml:base="https://felipejoglar.dev/blog/where-is-my-domain/"><![CDATA[<p>There is a common misconception in the Android community about the domain layer. And this is for a strong reason. Google says in its <a href="https://developer.android.com/topic/architecture#domain-layer">architecture guides</a>, that this layer is optional. Really.</p>

<blockquote>
  <p>The domain layer is an optional layer that sits between the UI and data layers.</p>
</blockquote>

<p>So many programmers would normally think so. But is it really like that? Is the domain layer optional?</p>

<h2 id="when-did-it-all-begin">When did it all begin?</h2>

<p>So, let’s think about how this optionality originated. Usually, when we talk about the domain layer, we think about use cases or interactors (at least in the Android world), as defined by Uncle Bob in its <a href="https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html#use-cases">Clean Architecture blog post</a>. Then, in an attempt to conform to a cleaner code, everything became a use case. Even a simple repository call got wrapped in a use case. Or <a href="https://developer.android.com/topic/architecture/domain-layer#use-cases-kotlin">formatting a date</a> for presentation purposes!</p>

<p>After that, a smell started to arise. Use cases were everywhere. The codebases began to be full of <em>useless use cases</em>™️, which only encapsulated a call to another collaborator. The <a href="https://refactoring.guru/smells/middle-man">middleman anti-pattern</a> was knocking at the door.</p>

<p>Now, we have a bunch of use cases that caused an anti-pattern. Our domain layer is then useless in many cases. Let’s remove all those use cases that do nothing, call the repository directly from the presentation layer, and make it optional. And here we are.</p>

<h2 id="the-domain-layer-is-mandatory">The domain layer is mandatory</h2>

<p>The problem is that we have built these decisions based on wrong assumptions. First, the domain layer isn’t built exclusively from use cases. And second, we probably already have this layer, but it is spread across other layers. We should group it and take it to the place it deserves.</p>

<p>Every app, or almost every app, is built for a concrete business domain. It can be banking, communication, gaming, playing media, etc. Those apps have business logic, and not all business logic consists of complex operations and data transformations that can be encapsulated in a single reusable component. It could be as simple as loading a feed from a social network or getting the comments for a specific feed item.</p>

<p>However, the domain is not only suited for behavior. Some data structures are part of the domain. Following the example above, a <code class="language-plaintext highlighter-rouge">FeedItem</code> or a <code class="language-plaintext highlighter-rouge">Comment</code>, are things everyone can understand and know about in your business, from programmers to marketing to HR, and thus they are part of the domain.</p>

<h2 id="finding-our-missing-domain">Finding our missing domain</h2>

<p>So let’s create a domain for a simple feature. We will set a couple of constraints to adhere to what we said above:</p>

<ul>
  <li>We can’t have useless use cases. We can’t have a use case its only work is to delegate the call to a collaborator.</li>
  <li>We can’t access the data layer directly from the UI. So the <code class="language-plaintext highlighter-rouge">ViewModel</code> can’t access the <code class="language-plaintext highlighter-rouge">Repository</code> directly. That means that we should go through the domain.</li>
</ul>

<p>First, we will define the goal of the feature we have on our hands. Following the above examples, we will implement a feature to show a social media feed to the user. So they can stay up to date with their friends and family.</p>

<p>But what is a feed in the scope of our feature? We will start with a basic data structure to hold all the data — this is a simple example, a full domain may look quite different.</p>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">data class</span> <span class="nc">FeedItem</span><span class="p">(</span>
    <span class="kd">val</span> <span class="py">id</span><span class="p">:</span> <span class="nc">Uuid</span><span class="p">,</span>
    <span class="kd">val</span> <span class="py">title</span><span class="p">:</span> <span class="nc">String</span><span class="p">,</span>
    <span class="kd">val</span> <span class="py">body</span><span class="p">:</span> <span class="nc">String</span><span class="p">?,</span>
    <span class="kd">val</span> <span class="py">imageUrl</span><span class="p">:</span> <span class="nc">String</span><span class="p">,</span>
    <span class="kd">val</span> <span class="py">createdAt</span><span class="p">:</span> <span class="nc">Instant</span><span class="p">,</span>
    <span class="kd">val</span> <span class="py">author</span><span class="p">:</span> <span class="nc">Author</span><span class="p">,</span>
<span class="p">)</span> <span class="p">{</span>
    <span class="kd">data class</span> <span class="nc">Author</span><span class="p">(</span>
        <span class="kd">val</span> <span class="py">id</span><span class="p">:</span> <span class="nc">Uuid</span><span class="p">,</span>
        <span class="kd">val</span> <span class="py">name</span><span class="p">:</span> <span class="nc">String</span><span class="p">,</span>
        <span class="kd">val</span> <span class="py">avatarUrl</span><span class="p">:</span> <span class="nc">String</span><span class="p">,</span>
    <span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Great. This structure will be part of our domain, it is not only data, it is a domain entity representing a business concept.</p>

<p>Now we need a way to get this data for our users, so how do we go around it if we can’t call the repository from either the <code class="language-plaintext highlighter-rouge">ViewModel</code> or a <code class="language-plaintext highlighter-rouge">UseCase</code>? What we need is a <em>contract</em>. Our domain needs a way to get this information, so we can define an interface to act as a contract for the business needs.</p>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">interface</span> <span class="nc">FeedLoader</span> <span class="p">{</span>
    <span class="k">fun</span> <span class="nf">load</span><span class="p">():</span> <span class="nc">Flow</span><span class="p">&lt;</span><span class="nc">List</span><span class="p">&lt;</span><span class="nc">FeedItem</span><span class="p">&gt;&gt;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>And that’s it. We have the domain for our feature defined. Now, it is time to wire this up together with the rest of the layers.</p>

<h2 id="wiring-up-our-domain">Wiring up our domain</h2>

<p>Now that we have the domain defined. We still miss the real thing, the concrete implementation of the contract.</p>

<p>For this example, the implementation will live in the data layer. There, we will have a <code class="language-plaintext highlighter-rouge">Repository</code> that will be in charge of getting the data from wherever it needs to be retrieved. It is not a domain responsibility to choose or even know where the feed data is retrieved from, that responsibility is for the data layer.</p>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">FeedRepository</span> <span class="p">:</span> <span class="nc">FeedLoader</span> <span class="p">{</span>
    <span class="k">override</span> <span class="k">fun</span> <span class="nf">load</span><span class="p">():</span> <span class="nc">Flow</span><span class="p">&lt;</span><span class="nc">List</span><span class="p">&lt;</span><span class="nc">FeedItem</span><span class="p">&gt;&gt;</span> <span class="p">{</span>
        <span class="c1">// Retrieve data</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The contract is now fulfilled by our data layer. It’s time to inject it into our presentation layer to make use of it.</p>

<p>We can’t access directly the <code class="language-plaintext highlighter-rouge">FeedRepository</code> from our <code class="language-plaintext highlighter-rouge">ViewModel</code>. It was one of our constraints. So, our <code class="language-plaintext highlighter-rouge">ViewModel</code> will depend on the domain contract, it’s all it needs: a way to get the data. It doesn’t care who provides or how this data is retrieved.</p>

<p>Here is where the <a href="https://freecontent.manning.com/dependency-injection-in-net-2nd-edition-understanding-the-composition-root/">composition root</a> comes into play. Using dependency injection patterns, we can pass the concrete implementation to the <code class="language-plaintext highlighter-rouge">ViewModel</code> without coupling any layers. The application module (<code class="language-plaintext highlighter-rouge">:app</code>) usually takes this role, as it has a view over all the other modules composing the whole app, integrating them all.</p>

<p>The <code class="language-plaintext highlighter-rouge">ViewModel</code> will look like this:</p>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">FeedViewModel</span><span class="p">(</span>
    <span class="k">private</span> <span class="kd">val</span> <span class="py">feedLoader</span><span class="p">:</span> <span class="nc">FeedLoader</span><span class="p">,</span>
<span class="p">)</span> <span class="p">:</span> <span class="nc">ViewModel</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">fun</span> <span class="nf">getFeed</span><span class="p">()</span> <span class="p">{</span>
        <span class="n">viewModelScope</span><span class="p">.</span><span class="nf">launch</span> <span class="p">{</span>
            <span class="n">feedLoader</span><span class="p">.</span><span class="nf">load</span><span class="p">().</span><span class="nf">collect</span> <span class="p">{</span> <span class="n">feed</span> <span class="p">-&gt;</span>
                <span class="c1">// Do your thing</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>A simplified dependency diagram for this feature would be like this one:</p>

<p><img src="/assets/images/where-is-my-domain/arch-diagram.png" alt="arch-diagram.png" /></p>

<p>We can see that no arrows go from our domain to other layers. And, the data and presentation layers are also separated by the domain. So we are keeping the clean architecture dependency rule in place. Also, we have managed to comply with the given constraints.</p>

<h2 id="we-found-it">We found it!</h2>

<p>Now we have our domain in place. No useless use cases and no direct dependency between data and presentation layers.</p>

<p>It doesn’t mean that this is the only way to go. As you are operating on a team, yours may be a different approach, and that’s fine! At the end of the day, your team may have agreed upon other conventions, like having a use case for every interaction, or accessing the repository directly if there is no data manipulation in between. Whatever keeps the team aligned and moving forward is a good approach.</p>

<p>Domain modeling is a must-have skill. And, it is not as easy or trivial as this example above. The domain exists in almost all features in every app, and it is our work to do our best to define it and give it its place. It is not optional, a feature can have it or not, but it is not a matter of choice, it is what the feature asks for.</p>

<p>I’m using this approach in my personal and work projects, and it is working pretty well. It gives me and my team a unified solution. We use the contracts when there is not much data manipulation. We can build up proper use cases when required and encapsulate a set of operations at the domain level. And give us a set of understandable data structures to work with.</p>]]></content><author><name>Felipe Joglar</name></author><summary type="html"><![CDATA[The domain layer is optional! This is a trend in the Android community now. But should it be? We are mostly writing an app for a business, and this business definitely operates in a specific domain. Let's find it.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://felipejoglar.dev/%7B%22url%22=%3E%22/assets/images/where-is-my-domain/search%22,%20%22caption%22=%3E%22Photo%20by%20%3Ca%20href=%5C%22https://unsplash.com/@dlerman6?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash%5C%22%3EDaniel%20Lerman%3C/a%3E%20on%20%3Ca%20href=%5C%22https://unsplash.com/photos/brown-and-silver-telescope-near-body-of-water-during-daytime-fr3YLb9UHSQ?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash%5C%22%3EUnsplash%3C/a%3E%22%7D" /><media:content medium="image" url="https://felipejoglar.dev/%7B%22url%22=%3E%22/assets/images/where-is-my-domain/search%22,%20%22caption%22=%3E%22Photo%20by%20%3Ca%20href=%5C%22https://unsplash.com/@dlerman6?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash%5C%22%3EDaniel%20Lerman%3C/a%3E%20on%20%3Ca%20href=%5C%22https://unsplash.com/photos/brown-and-silver-telescope-near-body-of-water-during-daytime-fr3YLb9UHSQ?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash%5C%22%3EUnsplash%3C/a%3E%22%7D" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Coming soon</title><link href="https://felipejoglar.dev/blog/coming-soon/" rel="alternate" type="text/html" title="Coming soon" /><published>2024-09-06T00:00:00+02:00</published><updated>2024-09-06T00:00:00+02:00</updated><id>https://felipejoglar.dev/blog/coming-soon</id><content type="html" xml:base="https://felipejoglar.dev/blog/coming-soon/"><![CDATA[<p>Hello! And, welcome to my blog. I’ll be sharing content on writing software and good practices. We’re gearing up to start, so hold tight.</p>]]></content><author><name>Felipe Joglar</name></author><summary type="html"><![CDATA[Hello! And, welcome to my blog. I'll be sharing content on writing software and good practices]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://felipejoglar.dev/%7B%22url%22=%3E%22/assets/images/coming-soon/hello%22,%20%22caption%22=%3E%22Photo%20by%20%3Ca%20href=%5C%22https://unsplash.com/@polhow?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash%5C%22%3EPablo%20Gentile%3C/a%3E%20on%20%3Ca%20href=%5C%22https://unsplash.com/photos/hello-neon-light-signage-3MYvgsH1uK0?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash%5C%22%3EUnsplash%3C/a%3E%22%7D" /><media:content medium="image" url="https://felipejoglar.dev/%7B%22url%22=%3E%22/assets/images/coming-soon/hello%22,%20%22caption%22=%3E%22Photo%20by%20%3Ca%20href=%5C%22https://unsplash.com/@polhow?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash%5C%22%3EPablo%20Gentile%3C/a%3E%20on%20%3Ca%20href=%5C%22https://unsplash.com/photos/hello-neon-light-signage-3MYvgsH1uK0?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash%5C%22%3EUnsplash%3C/a%3E%22%7D" xmlns:media="http://search.yahoo.com/mrss/" /></entry></feed>