<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Ronald Blüthl's Blog]]></title><description><![CDATA[I write about software, business, and other interesting stuff. ✌️]]></description><link>https://r.bluethl.net</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1649598218578/yMYE-f2dj.png</url><title>Ronald Blüthl&apos;s Blog</title><link>https://r.bluethl.net</link></image><generator>RSS for Node</generator><lastBuildDate>Sun, 19 Apr 2026 08:43:13 GMT</lastBuildDate><atom:link href="https://r.bluethl.net/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[The only constant is an ID]]></title><description><![CDATA[I claim that all (user) data in a database should be mutable by default. Always. Well, almost all data. There are only four exceptions.
1. The primary key
A dedicated column that serves as the unique identifier of the record (ideally, a GUID or a con...]]></description><link>https://r.bluethl.net/the-only-constant-is-an-id</link><guid isPermaLink="true">https://r.bluethl.net/the-only-constant-is-an-id</guid><category><![CDATA[Databases]]></category><category><![CDATA[database design]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[software development]]></category><category><![CDATA[Software Engineering]]></category><dc:creator><![CDATA[Ronald Blüthl]]></dc:creator><pubDate>Thu, 05 Jan 2023 21:15:15 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1673079691304/9f8fa682-a8cd-4774-8859-d3794d090253.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I claim that all (user) data in a database should be mutable by default. Always. Well, <em>almost</em> all data. There are only four exceptions.</p>
<h3 id="heading-1-the-primary-key"><strong>1. The primary key</strong></h3>
<p>A <em>dedicated</em> column that serves as the unique identifier of the record (ideally, a <code>GUID</code> or a consecutive number). <em>Every</em> table — without an exception, and I mean it — <strong>must have</strong> a <em>separate</em> column that uniquely identifies the record.</p>
<p>It may be tempting to use an existing column (such as <code>email</code> in a <code>user</code> table) as the primary key, but doing so makes it impossible to change a user’s email later on. Avoid this at all costs.</p>
<p>Instead, always use a separate column with a truly unique value and use this column exclusively to build relations and connect records in a database. That way, all other data (such as, for example, <code>email</code> or <code>slug</code>) can always be changed without breaking anything.</p>
<h3 id="heading-2-foreign-keys"><strong>2. Foreign keys</strong></h3>
<p>Similar to primary keys, foreign keys take care of connecting records and maintaining relationships in a database. These must be always treated as read-only, as they ensure data integrity.</p>
<h3 id="heading-3-automatically-generated-values"><strong>3. Automatically generated values</strong></h3>
<p>Many databases use computed values such as timestamps (e.g. <code>created_at</code>). All data that was generated without user input should generally be considered immutable. They usually provide meta information about a record and should be treated differently than user data.</p>
<h3 id="heading-4-records-that-are-immutable-by-their-nature"><strong>4. Records that are immutable by their nature</strong></h3>
<p>Some database models include entirely read-only tables, where new data can be added, but existing data can never be modified. It can only be read. A common use case for this is a document activity log or a login history.</p>
<h3 id="heading-conclusion"><strong>Conclusion</strong></h3>
<p>All other (user-entered) data should be mutable — always. It may sound obvious, but it’s not always the case. Of course, there can be exceptions, but 99% of the time, this should be the default.</p>
<p>Suppose I’m using a SaaS where I can create a workspace with my company’s name and slug. In case I ever rebrand from ”Average company” to ”Superior company”, I want to be able to change the name, the slug, the admin user’s email address, and so on. If this is not possible, it’s usually a sign of weak database design (or poor UX).</p>
<p>Thanks for reading. Feel free to <a target="_blank" href="https://twitter.com/rbluethl">follow me on Twitter</a>.</p>
]]></content:encoded></item><item><title><![CDATA[The code]]></title><description><![CDATA[Every line of code you don’t write, you don’t have to maintain.

Every single line of code adds complexity to your software. It needs to be developed. It needs to be tested. It needs to be deployed. It requires maintenance. It can break. It can affec...]]></description><link>https://r.bluethl.net/the-code</link><guid isPermaLink="true">https://r.bluethl.net/the-code</guid><category><![CDATA[code]]></category><category><![CDATA[software development]]></category><category><![CDATA[Software Engineering]]></category><category><![CDATA[Programming Tips]]></category><category><![CDATA[General Programming]]></category><dc:creator><![CDATA[Ronald Blüthl]]></dc:creator><pubDate>Tue, 03 Jan 2023 21:38:41 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1672781455970/d52dcab3-fbbf-440c-94a1-697b2c3ee24a.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p><strong>Every line of code you don’t write, you don’t have to maintain.</strong></p>
</blockquote>
<p>Every single line of code adds complexity to your software. It needs to be developed. It needs to be tested. It needs to be deployed. It requires maintenance. It can break. It can affect other parts of your software. Whenever you feel the urge to add code, think again. Does it justify the work that’s required? Not only to write it but also to keep it intact.</p>
<blockquote>
<p><strong>The real 10x engineers are the ones who delete code instead of adding it.</strong></p>
</blockquote>
<p>10x engineers are overrated. I’m not even sure if they’re a real thing. The most valuable engineers are the ones who make software less complex. Either by removing code instead of adding even more or not adding any code at all.</p>
<blockquote>
<p><strong>Good code reads like a book.</strong></p>
</blockquote>
<p>If you’re reading code in an unknown project and you quickly know and understand what’s going on, then you know you’re dealing with good code. Great code should explain itself — even without comments. Comments can add value at times, but generally speaking, code should also be readable without plenty of comments.</p>
<blockquote>
<p><strong>Don’t add code unless deemed necessary.</strong></p>
</blockquote>
<p>Writing software is fun. But in real-world projects and products, code should only be added if it’s necessary. Don’t add code just for the sake of it. As stated earlier, every piece of code comes at a cost. If you don’t need it <em>right now</em>, don’t add it. Because if you don’t need it right now, you probably never will.</p>
<blockquote>
<p><strong>Coding is thinking.</strong></p>
</blockquote>
<p>Coding is thinking — executed. Essentially, a piece of code is just thoughts, written in a form computers can understand. When you sit down to solve a problem, you should already have a rough solution in mind. Great code can’t be produced without thinking clearly and thoroughly. Think, then code.</p>
<blockquote>
<p><strong>Good code is as complex as necessary, but as simple as possible.</strong></p>
</blockquote>
<p>Building a feature in the most complex way is a red flag. Some programming languages can do fancy things — things that make it especially hard to understand what’s going on. Try to strive for the simplest solution possible. Code gets more complex over time automatically. No need to make it extra complicated in the first place just to show off exotic skills.</p>
<blockquote>
<p><strong>The code is the truth.</strong></p>
</blockquote>
<p>Computers are great at doing <em>precisely</em> what we tell them to. If something doesn’t work as expected, you have given the computer the wrong instructions by writing false or faulty code. Don’t expect the problem elsewhere. Technically speaking, your code always behaves correctly. It just doesn’t do the right thing (correctly).</p>
<blockquote>
<p><strong>The code is the only real documentation.</strong></p>
</blockquote>
<p>No matter how well you maintain any kind of documentation of your code, it’s almost guaranteed to be outdated. The actual code is the only real documentation of what’s going on in your software and why/how a feature behaves a certain way. Documentation is good, documentation is necessary. But the code is the single source of truth.</p>
<blockquote>
<p><strong>8 hours of thinking, 1 hour of coding &gt; 1 hour of thinking, 8 hours of coding.</strong></p>
</blockquote>
<p>It’s stupid to measure the output of a software engineer by hours spent writing actual code. Coding is the final piece of the puzzle. It’s way more important to sit down, think, and come up with the best possible solution for the problem at hand. Focus on solving the problem first, then sit down and write code. Not the other way around.</p>
<blockquote>
<p><strong>A programming language is just a tool.</strong></p>
</blockquote>
<p>Every programming language has its specialties — it has its strengths, it has its weaknesses. And it has certain areas of application. Different programming languages are suitable for different kinds of platforms and problems. But a programming language can always be learned. It’s most important to master the foundations. If you’re a problem solver and if you’re good at abstract and logical thinking, you can code in any language.</p>
<blockquote>
<p><strong>The best code is no code at all.</strong></p>
</blockquote>
<p>If you’ve read this far, then this point needs no further explanation. If you skipped everything, go to the top.</p>
<p>To be continued.</p>
<p>Thanks for reading. If you enjoyed this post, feel free to <a target="_blank" href="https://twitter.com/rbluethl">follow me on Twitter</a>.</p>
]]></content:encoded></item><item><title><![CDATA[How to write better code]]></title><description><![CDATA[I've been professionally building software for more than 10 years now.
Over time, I've written a lot of code.
I have also read a lot of code.
My own code, and code from other people.
Code that's terribly bad and code that's a real joy to work with.
T...]]></description><link>https://r.bluethl.net/how-to-write-better-code</link><guid isPermaLink="true">https://r.bluethl.net/how-to-write-better-code</guid><category><![CDATA[coding]]></category><category><![CDATA[best practices]]></category><category><![CDATA[tips]]></category><category><![CDATA[Software Engineering]]></category><category><![CDATA[General Programming]]></category><dc:creator><![CDATA[Ronald Blüthl]]></dc:creator><pubDate>Fri, 07 Oct 2022 08:05:33 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1665129447102/NTXSfFgy8.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I've been professionally building software for more than 10 years now.
Over time, I've written a lot of code.
I have also read a lot of code.
My own code, and code from other people.
Code that's terribly bad and code that's a real joy to work with.
Turns out that good code mostly has the same characteristics.
It's easy to read, it's easy to understand, it's easy to maintain and extend.
It's as complex as necessary, but as simple as possible.
In this post, I'm trying to describe what great code means (to me).</p>
<h3 id="heading-1-understand-the-basics">1. Understand the basics</h3>
<p>Let's start with something obvious (but really important).
No matter what you do in life, you need to understand the foundations.
This is especially true for programming.
I know there are people out there copying code from StackOverflow, pasting it into their editor and then wondering why stuff doesn't work.
This doesn't make any sense.
If you don't fundamentally <em>understand</em> what you're doing, you're gonna have a bad time.
Learn how data types, algorithms and data structures work.
Get your hands on different types and kinds of programming languages.
Make sure to know your tools before jumping into something bigger.</p>
<h3 id="heading-2-think-before-you-write">2. Think before you write</h3>
<p>As you mature as a software engineer, you probably notice that you tend to spend more time thinking about a problem and its solution than actually sitting down and writing code.
That's because <em>coding is thinking</em>.
If you think about your problem first and have a solution in mind already, the actual coding part becomes easy.
I often like to say that programming languages are a tool.
They look different, they work different, they have their strengths and weaknesses.
But if you master logical thinking and problem solving, you can use any programming language with a bit of experience.</p>
<h3 id="heading-3-be-consistent">3. Be consistent</h3>
<p>If you've read my blog post on <a target="_blank" href="https://r.bluethl.net/how-to-design-better-apis">How to design better APIs</a>, you have probably noticed that there is a "Be consistent" section as well.
That's intentional. :)
I'd argue that consistency is one of the most important factors when writing software.
If you follow the same rules across your entire codebase, it's a lot easier for other people to read, follow, and understand your code.
Your code becomes more readable, understandable and maintainable.
It's also easier for yourself (if you're working on a project alone).
Keep your code clean, keep it simple, keep it consistent.</p>
<p>This applies to:</p>
<ul>
<li>File naming</li>
<li>Indentation</li>
<li>Naming variables</li>
<li>Naming functions</li>
<li>Using single/double quotes</li>
</ul>
<h4 id="heading-bad">❌ Bad</h4>
<pre><code class="lang-typescript"><span class="hljs-comment">// Different file name styles</span>
<span class="hljs-comment">// Not all parameters with explicit type</span>
<span class="hljs-comment">// Odd indentations</span>
<span class="hljs-comment">// Unnecessary whitespaces</span>
<span class="hljs-comment">// Mix of single and double quotes</span>
<span class="hljs-comment">// Different variable naming style</span>
<span class="hljs-comment">// Different function naming style</span>

<span class="hljs-comment">// users-Service.ts</span>
<span class="hljs-keyword">const</span> sendEmail = <span class="hljs-keyword">async</span> (mailSubject, body: <span class="hljs-built_in">string</span>) =&gt; {
  <span class="hljs-keyword">const</span> mailClient = <span class="hljs-keyword">new</span> EmailClient()

    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span>   emailClient.sendEmail(mailSubject, body)

  <span class="hljs-keyword">return</span> response.status
}

<span class="hljs-comment">// orders.ts</span>
<span class="hljs-keyword">let</span> stat = <span class="hljs-keyword">await</span> sendEmail(<span class="hljs-string">"Thank you for your order"</span>,
    <span class="hljs-string">'Your package is on the way.'</span>)
</code></pre>
<h4 id="heading-good">✅ Good</h4>
<pre><code class="lang-typescript"><span class="hljs-comment">// users.ts</span>
<span class="hljs-keyword">const</span> sendEmail = <span class="hljs-keyword">async</span> (subject: <span class="hljs-built_in">string</span>, body: <span class="hljs-built_in">string</span>) =&gt; {
  <span class="hljs-keyword">const</span> emailClient = <span class="hljs-keyword">new</span> EmailClient()
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> emailClient.sendEmail(subject, body)

  <span class="hljs-keyword">return</span> response.status
}

<span class="hljs-comment">// orders.ts</span>
<span class="hljs-keyword">const</span> status = <span class="hljs-keyword">await</span> sendEmail(<span class="hljs-string">'Thank you for your order'</span>, <span class="hljs-string">'Your package is on the way.'</span>)
</code></pre>
<h3 id="heading-4-separate-concerns">4. Separate concerns</h3>
<p>You should always advocate for code that has as little side effects and dependencies as possible.
Concerns should be clearly separated, certain pieces of code should do one thing and do one thing well.
For example, if you're working on a database service, avoid accessing the application state for accessing the current user ID.
Instead, add a parameter that lets callers pass this information themselves.
That way, consumers clearly understand which parameters are required in order to call a function.
Also, the program doesn't depend on other parts of the software and behaves the same, no matter the state.</p>
<h4 id="heading-bad">❌ Bad</h4>
<pre><code class="lang-typescript"><span class="hljs-comment">// orders.ts</span>
<span class="hljs-keyword">import</span> { store } <span class="hljs-keyword">from</span> <span class="hljs-string">'state'</span>

<span class="hljs-keyword">const</span> getUserOrders = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-comment">// Database call is depending on the shared application state</span>
  <span class="hljs-comment">// It's hard for consumers to understand this</span>
  <span class="hljs-comment">// It can have unpleasant side effects and makes it hard to discover problems</span>
  <span class="hljs-keyword">return</span> orders.filter(<span class="hljs-function"><span class="hljs-params">o</span> =&gt;</span> o.userId === store.userId)
}
</code></pre>
<h4 id="heading-good">✅ Good</h4>
<pre><code class="lang-typescript"><span class="hljs-comment">// orders.ts</span>
<span class="hljs-keyword">const</span> getUserOrders = <span class="hljs-function">(<span class="hljs-params">userId: <span class="hljs-built_in">string</span></span>) =&gt;</span> {
  <span class="hljs-comment">// User ID is passed as parameters</span>
  <span class="hljs-comment">// The function is more "pure" and doesn't depend on other components/state</span>
  <span class="hljs-keyword">return</span> orders.filter(<span class="hljs-function"><span class="hljs-params">o</span> =&gt;</span> o.userId === userId)
}
</code></pre>
<h3 id="heading-5-dont-use-magic-numbers">5. Don't use magic numbers</h3>
<p>Magic numbers and strings are bad.
They are mostly inline variables that are used for a specific purpose that isn't immediately clear when looking at the code, which makes the code complicated to read and understand.
Instead of throwing in a "magic number", extract a variable with a name that clearly indicates the purpose.</p>
<h4 id="heading-bad">❌ Bad</h4>
<pre><code class="lang-typescript"><span class="hljs-keyword">if</span> (users.length &gt;= <span class="hljs-number">100</span>) {
  <span class="hljs-comment">// Which limit? What does 100 mean?</span>
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Limit reached'</span>)
  <span class="hljs-keyword">return</span>
}
</code></pre>
<h4 id="heading-good">✅ Good</h4>
<pre><code class="lang-typescript">
<span class="hljs-comment">// Add separate variable that clearly indicates what "100" stands for</span>
<span class="hljs-keyword">const</span> earlyAccessUserLimit = <span class="hljs-number">100</span>

<span class="hljs-keyword">if</span> (users.length &gt;= earlyAccessUserLimit) {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Early access user limit reached'</span>)
  <span class="hljs-keyword">return</span>
}
</code></pre>
<h3 id="heading-6-dont-reinvent-the-wheel">6. Don't reinvent the wheel</h3>
<p>Programming is fun. As engineers, we tend to want to write our own solutions for almost everything, because we love solving problems. It doesn't always make sense though.
Try to leverage other frameworks, tools and services and focus on solving your own problem.
There is so much great software out there you can use – mostly even free of charge. 
Go use it!
Every line of code you don't write, you don't have to maintain.</p>
<h3 id="heading-7-use-fewer-dependencies">7. Use fewer dependencies</h3>
<p>Conversely, don't pull in a package or use another provider for <em>everything</em>.
If there is a very simple solution to your problem, don't add too much overhead by adding an external dependency.
There are literally npm packages that provide one single function.
Don't overuse packages.
Know when it makes sense to use a third-party service or package instead of writing your own code.</p>
<h3 id="heading-8-use-self-explanatory-names">8. Use self-explanatory names</h3>
<p>As already mentioned in "Be consistent", it's crucial to use self-explanatory, simple names across your entire codebase.
Don't use unnecessary abbreviations.
Don't use arbitrary names.
Good code reads like a book.
It's easy to understand, it's easy to maintain, it's a joy to work with.</p>
<p>This applies to:</p>
<ul>
<li>Files</li>
<li>Functions</li>
<li>Variables</li>
<li>Parameters</li>
</ul>
<h4 id="heading-bad">❌ Bad</h4>
<pre><code class="lang-typescript"><span class="hljs-comment">// What does this mean?</span>
<span class="hljs-keyword">const</span> maxMbs = <span class="hljs-number">10</span>

<span class="hljs-comment">// Get orders from where/whom?</span>
<span class="hljs-keyword">const</span> getOrders = <span class="hljs-function">(<span class="hljs-params">id: <span class="hljs-built_in">string</span></span>) =&gt;</span> {
  ...
}

<span class="hljs-comment">// Matching what?</span>
<span class="hljs-keyword">const</span> matchingOrders = orders.filter(<span class="hljs-function"><span class="hljs-params">x</span> =&gt;</span> x.status === <span class="hljs-string">'fulfilled'</span>)
</code></pre>
<h4 id="heading-good">✅ Good</h4>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> fileSizeLimitMb = <span class="hljs-number">10</span>

<span class="hljs-keyword">const</span> getOrdersByUserId = <span class="hljs-function">(<span class="hljs-params">userId: <span class="hljs-built_in">string</span></span>) =&gt;</span> {
  ...
}

<span class="hljs-keyword">const</span> unfulfilledOrders = orders.filter(<span class="hljs-function"><span class="hljs-params">o</span> =&gt;</span> o.status !== <span class="hljs-string">'fulfilled'</span>)
</code></pre>
<h3 id="heading-9-dont-over-engineer-yagni">9. Don't over engineer (YAGNI)</h3>
<p>In programming, there is a principle called "YAGNI" (You ain't gonna need it), which states that functionality should not be added unless deemed necessary.
You should always keep this in mind.
Only implement new functionality when you actually need it, not when you <em>think</em> you will need it in the future.
Because, most likely, you never will.
Also, don't build a feature in the most complex way.
Abstraction can be great where it makes sense, but it can also be a real pain if used mindlessly.
Remember, every new code needs to be maintained, so it's better to only add code that's actually required.
Otherwise it only adds overhead and doesn't bring any value.</p>
<h3 id="heading-10-avoid-duplicationredundancy">10. Avoid duplication/redundancy</h3>
<p>There's also a principle called "DRY" (Don't repeat yourself), which states that you should avoid redundancy (don't duplicate code, have a single source of truth) at all costs. 
This holds true for code, data and comments.</p>
<ul>
<li>Don't copy or duplicate code</li>
<li>Don't store data redundantly</li>
<li>Don't add comments that don't add context</li>
</ul>
<p>It's better to write clean, reasonable code and refrain from comments rather than writing less readable code and adding comments.
Also, code duplication is one of the worst things you can do.
Whenever you need to reuse a piece of code, extract it into a separate file/module/function depending on the language you're using.</p>
<h3 id="heading-11-refactor-if-necessary">11. Refactor if necessary</h3>
<p>Don't be afraid of refactoring your code if there is a necessity.
Software evolves, and so should you.
It's better to get rid of a technical debt and refactor that piece of code instead of carrying it along and grit your teeth on it.
Every now and then, take some time to go through your code and take the time to refactor and make it better instead of adding another feature.
It's worth it in the long run.</p>
<h3 id="heading-12-dont-make-assumptions">12. Don't make assumptions</h3>
<p>You shouldn't make any assumptions about how your code will behave in certain situations.
Even though you think your code can never enter state X, it doesn't mean that it won't.
Handle errors.
Expect the unexpected.
Make sure your code runs, no matter the state or outcome.
This is especially important for user inputs – you can never know what kind of data a user will enter.
I often like to apply Murphy's law in this context – anything that <em>can</em> go wrong <em>will</em> go wrong at some point.</p>
<h3 id="heading-13-take-advantage-of-immutability">13. Take advantage of immutability</h3>
<p>Whenever possible (and reasonable), try to use immutable data types and avoid manipulating existing variables directly.
It might seem cumbersome first, but your code becomes way more predictable and less error-prone if you work with immutable objects.
Changing existing variables directly can have unintended, hard to find side effects, which you should avoid if necessary.
You literally protect yourself from making dumb mistakes.</p>
<h3 id="heading-14-introduce-environment-variables">14. Introduce environment variables</h3>
<p>Always introduce environment variables for data that shouldn't be hard-coded into your software.
For example, database connection strings, file system paths and app preferences.
Never store data like this directly in your code.
It's a lot better to inject information from outside – that way, you keep everything in one place, can make changes quickly, and most importantly, don't expose confidential in your source code.</p>
<h3 id="heading-15-get-in-the-zone">15. Get in the zone</h3>
<p>Programming requires concentration, it requires focus.
When you tackle a problem, make sure to get in the zone.
Silence notifications.
Think into the problem and its possible solutions.
If your mind is not free, you will find yourself jumping around, not being concentrated and thus, not getting anything done.
Get in the zone, and don't break the flow.</p>
<p>If you enjoyed this post, feel free to <a target="_blank" href="https://twitter.com/rbluethl">follow me on Twitter</a>.</p>
]]></content:encoded></item><item><title><![CDATA[Rules to live (and work) by]]></title><description><![CDATA[We just came back from our three-week vacation in Scandinavia.
While on the road with our camper van, I had some time to reflect on the last couple of months.
Maybe the last couple of years.
Being self-employed for more than five years now, I‘ve alwa...]]></description><link>https://r.bluethl.net/rules-to-live-and-work-by</link><guid isPermaLink="true">https://r.bluethl.net/rules-to-live-and-work-by</guid><category><![CDATA[work]]></category><category><![CDATA[life]]></category><category><![CDATA[software development]]></category><category><![CDATA[Startups]]></category><category><![CDATA[General Programming]]></category><dc:creator><![CDATA[Ronald Blüthl]]></dc:creator><pubDate>Thu, 23 Jun 2022 06:02:55 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1655963943679/gQcQaaIwc.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>We just came back from our three-week vacation in Scandinavia.
While on the road with our camper van, I had some time to reflect on the last couple of months.
Maybe the last couple of years.
Being self-employed for more than five years now, I‘ve always been pushing hard to get <em>everything</em> right.
I‘ve wanted to be a great guy to work with, satisfy my customers, roll in enough money, have a lot of free time, and be very happy.
But things don‘t always work out the way we expect them to.
While I‘m fairly good at building software, I‘m terrible at separating myself from my „work-self“.
But we try, we fail, we learn, we improve.
Over the last few weeks, I thought a lot about my strengths and weaknesses, things I‘m good at, and stuff I want to generally improve – both personally and in a business context.
Finally, I tried to come up with a ruleset I want to live by.
A ruleset I want to run my company by.
A framework to build the house I want to live in.</p>
<h2 id="heading-1-learn-every-day">1. Learn every day</h2>
<p>The only constant is change.
Most people think that they‘re done learning once they finish school or education.
Wrong.
By the time you‘ve finished school, you probably don‘t know much.
You‘re only getting started there.
It‘s important to know that you should learn every day and that you can learn from everyone.
Develop a new skill, satisfy your curiosity, and try something completely different.
Learning is fun and can get you anywhere.
Never stop learning.</p>
<h2 id="heading-2-help-as-much-as-you-can">2. Help as much as you can</h2>
<p>I‘ve always been convinced that helping others and sharing knowledge without expecting anything in return is a positive-sum game.
But only since I started blogging last year, I‘ve experienced this in practice.
My post on <a target="_blank" href="https://r.bluethl.net/how-to-design-better-apis">How to design better APIs</a> recently hit 150k views. 
It resonated with many people and was genuinely helpful to a lot of folks.
Knowing that something you‘ve created is valuable and helpful to others is an incredible feeling.
I think that everyone can and should create more things.</p>
<h2 id="heading-3-take-ownership">3. Take ownership</h2>
<p>I‘ve made it a habit to publicly acknowledge my own mistakes.
If something goes wrong, you should always take full responsibility for it.
You shouldn‘t blame it on anyone else.
Explain what went wrong, why it happened, and how it will never happen again.
By the end of the day, it‘s more important to be high integrity and honest instead of making up some random excuse and blaming it on someone else.
Customers will forgive you.
They will appreciate and value your openness.
That way, they can verify that you‘re a trustworthy and long-term partner.</p>
<h2 id="heading-4-give-credit">4. Give credit</h2>
<p>Similarly, if someone else does something great, give credit to them.
Say „thank you“, „nicely done“, or „I couldn‘t have made it without you“.
It‘s extremely powerful to actively show a team member, business partner, or customer your appreciation.
It makes them feel valued and appreciated.
Their work is important and should be treated that way.
Never underestimate the effect of saying something nice.</p>
<h2 id="heading-5-dont-take-it-personally">5. Don‘t take it personally</h2>
<p>This is something I need to work on myself.
I‘m extremely proud of my work and I don‘t want to make any mistakes.
Consequently, I quickly take things personally, which is unnecessary.
If a customer is – for example – angry because of some nasty bug in their software, they‘re angry <em>because of that bug</em>, not because they consider you an idiot.
It‘s important to differentiate yourself from your company, especially if you‘re working alone.
Focus on fixing the problem instead of feeling attacked.</p>
<h2 id="heading-6-celebrate-your-achievements">6. Celebrate your achievements</h2>
<p>In our fast-moving world – particularly in the software industry – it’s easy to lose track of your achievements and successes.
Milestone after milestone, it often happens that victories are not properly celebrated.
It shouldn‘t be that way.
Once you publish that first version of an app, take a break, get a cold drink, have a nice dinner, and celebrate.
If you don‘t celebrate your achievements yourself, why should anyone else?
Consciously taking time to celebrate is important to get new energy and stay motivated.</p>
<h2 id="heading-7-learn-from-your-mistakes">7. Learn from your mistakes</h2>
<p>Failing is not a shame.
It’s one of the most important factors to grow – both personally and as a business.
No matter how hard you fail, there’s always an upside.
You just have to see it.
Find that positive side, accept it, and draw your lessons from it.
Failure is natural. 
Failure is OK. 
Not getting better with every failure you make is not.</p>
<h2 id="heading-8-dont-get-lost-in-details">8. Don‘t get lost in details</h2>
<p>There‘s a saying.
Make it work, make it fast, make it beautiful.
The order is important.
Whatever you do, don‘t lose yourself in tiny details early on.
It‘s more important to ship a working feature that delivers value to a customer rather than building it in the most beautiful way.
Focus, get in the zone and don‘t go in circles.
Execution is everything.</p>
<h2 id="heading-9-say-no-more-often">9. Say „no“ more often</h2>
<p>People generally want to be nice and don‘t want to hurt their counterparts.
It‘s therefore often hard to say NO.
But it‘s important.
Always saying yes to everything makes you prone to being exploited by people.
Also, it‘s irrational to accept and do everything that‘s expected from you.
You‘re an individual human and you have the right to do things your way.</p>
<h2 id="heading-10-dont-make-promises-you-cant-keep">10. Don‘t make promises you can‘t keep</h2>
<p>It‘s tough to let someone down by saying „no“.
But it‘s even worse to make promises you can‘t keep.
Be honest, say the truth, and only do realistic things.
It‘s better to decline something up front instead of being sorry later on.</p>
<h2 id="heading-11-make-your-own-decisions">11. Make your own decisions</h2>
<p>It‘s great to listen to people and get their feedback and opinions.
Feedback can be really valuable.
But be careful who you get feedback from.
Most people care about themselves and act according to their interests.
Use your judgment.
Listen to yourself.
By the end of the day, you must make your own decisions and live with them.</p>
<h2 id="heading-12-dont-define-yourself-solely-by-work">12. Don‘t define yourself solely by work</h2>
<p>People are multivariate.
You are not exclusively your company.
Of course – if you‘re working on your startup, work will take up a big part of your life.
But that doesn‘t mean there‘s nothing else.
You still have hobbies, you have interests, and you have other opinions.
There are people out there that value you for things other than your MRR or your startup‘s valuation.
Don‘t couple your personality too tightly to your business.</p>
<h2 id="heading-13-dont-chase-arbitrary-things">13. Don‘t chase arbitrary things</h2>
<p>Live in the here and now.
Most people choose to be unhappy until something arbitrary happens.
Don‘t chase an arbitrary 1 million dollars.
Don‘t wait until you‘re 30.
Don‘t wait for that special day to come.
It probably never will.
Be the person you always wanted to be and do the things you always wanted to do, now.
Just do it.</p>
<h2 id="heading-14-watch-yourself">14. Watch yourself</h2>
<p>You are busy building your startup.
I get that.
Everyone is.
I am so too.
But while you‘re working hard, you shouldn‘t do so to a detriment of your health.
Slow down.
Take some time off.
Take care of your body.
Take care of your mind.
Be happy.
Be healthy.
Nothing else matters.</p>
<h2 id="heading-15-dont-take-it-too-seriously">15. Don‘t take it too seriously</h2>
<p>Life is short.
Your lifetime is limited (I know, it sucks).
Don‘t take yourself so seriously.
It doesn‘t always have to be hard.
Laugh about yourself.
Have fun.
Do some crazy stuff.
Make it count. ✌️</p>
]]></content:encoded></item><item><title><![CDATA[How to build robust Vue 3 components]]></title><description><![CDATA[Vue has been my go-to framework for the last couple of years. It gets the job done, it‘s easy to use, and I understand it quite well. Over time, I had built up some great boilerplate code to bootstrap new projects. The scaffold project had TypeScript...]]></description><link>https://r.bluethl.net/how-to-build-robust-vue-3-components</link><guid isPermaLink="true">https://r.bluethl.net/how-to-build-robust-vue-3-components</guid><category><![CDATA[Vue.js]]></category><category><![CDATA[vue]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[javascript framework]]></category><category><![CDATA[Web Development]]></category><dc:creator><![CDATA[Ronald Blüthl]]></dc:creator><pubDate>Sun, 10 Apr 2022 15:18:27 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1649603883882/ZxX__PeQX.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Vue has been my go-to framework for the last couple of years. It gets the job done, it‘s easy to use, and I understand it quite well. Over time, I had built up some great boilerplate code to bootstrap new projects. The scaffold project had <code>TypeScript</code> support, used <code>vue-class-component</code>, <code>vuex</code>, <code>vue-router</code> and had also set up some neat tooling stuff. Every new app started off with this template, which I was very happy with. The only problem: That was Vue 2.x.</p>
<p>Vue 3 has officially been released on 18 September 2020, and <a target="_blank" href="https://twitter.com/vuejs/status/1490592213184573441?s=21&amp;t=Dpb5-9HxF-PIPqb1dxmBoQ">as of 7 February 2022, it‘s now the default version</a>. So when I started working on a new app in autumn 2021, an app which I knew would exist for many years, I thought it would be a good idea to start with Vue 3 right away. But since Vue 3 brings quite some changes — most notably, the Composition API — I had been very hesitant to make the switch. Especially, because my beloved scaffold project had worked so well.</p>
<p>But kicking off a large project with an old framework doesn‘t make any sense, so I needed to figure out a way to get started with Vue 3. I struggled a bit to get into the „flow“ of building clean, maintainable and robust components first, but I think I found a way that I probably like even more than the Vue 2.x class component way. So in this post, I want to share my opinionated approach to work with Vue 3. An approach, that will hopefully help you building better Vue components. We will create a component step-by-step, explaining all the decisions we make in detail. But first, let‘s get started with some fundamental things.</p>
<h2 id="heading-1-typescript">1. TypeScript</h2>
<p>Starting with Vue 3, TypeScript is now a first-class citizen of the framework (Vue 3 is written in TypeScript itself). For that reason, it's especially easy to use TypeScript in your Vue 3 projects. I had been using TypeScript in Vue 2 already, and starting with Vue 3, it makes even more sense. <a target="_blank" href="https://vuejs.org/guide/typescript/overview.html#using-vue-with-typescript">Use Vue with TypeScript</a>, your entire codebase becomes type-safe and it will save you from a lot of troubles.</p>
<h2 id="heading-2-composition-api">2. Composition API</h2>
<p>As mentioned before, the <a target="_blank" href="https://vuejs.org/guide/extras/composition-api-faq.html">Composition API</a> is probably the most important concept to understand in comparison to Vue 2. In Vue 2, we only had the Options API (where we define <code>data</code>, <code>props</code>, <code>methods</code>, and so on in our components), where in Vue 3, we <em>also</em> have the more flexible Composition API, that exposes reactive data and logic, which can be reused in other components as well.</p>
<p>I‘d argue that it generally makes sense to use the Composition API for new Vue 3 projects, as it‘s a lot more versatile and allows for easier sharing of logic and data. In fact, I haven‘t written an Options API-style component in Vue 3 yet, but we‘re getting there. ✌️</p>
<h2 id="heading-3-syntax">3. Syntax</h2>
<p>Now that we‘ve committed ourselves to prefer the Composition API over the Options API, we need to choose one of the syntax styles that are supported to create Composition API components.</p>
<p><strong>❌ Option 1 — Component</strong> (example from the official Vue.js documentation)</p>
<p>The first option is to export a default component and expose reactive data using the <code>setup</code> method. When I first saw this, I thought that it was very verbose. Luckily, there‘s a better way — but let's see the conventional syntax first.</p>
<pre><code class="lang-javascript">&lt;script&gt;
<span class="hljs-keyword">import</span> { ref } <span class="hljs-keyword">from</span> <span class="hljs-string">'vue'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  setup() {
    <span class="hljs-keyword">const</span> count = ref(<span class="hljs-number">0</span>)

    <span class="hljs-keyword">return</span> {
      count
    }
  }

  mounted() {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">this</span>.count) <span class="hljs-comment">// 0</span>
  }
}
&lt;/script&gt;

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">button</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"count++"</span>&gt;</span>{{ count }}<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span></span>
</code></pre>
<p><strong>✅ Option 2 — <code>script setup</code></strong></p>
<p>The second option is to use the <a target="_blank" href="https://vuejs.org/api/sfc-script-setup.html#script-setup"><code>script setup</code></a> syntax, which has a couple of benefits (less verbose, exposure of top level bindings, better TypeScript support, … I will explain them in detail as we proceed). So this is what we‘re going to use.</p>
<pre><code class="lang-javascript">&lt;script setup&gt;
<span class="hljs-keyword">import</span> { ref } <span class="hljs-keyword">from</span> <span class="hljs-string">'vue'</span>

<span class="hljs-keyword">const</span> count = ref(<span class="hljs-number">0</span>)
&lt;/script&gt;

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">button</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"count++"</span>&gt;</span>{{ count }}<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span></span>
</code></pre>
<p>If you compare the <code>script setup</code> syntax with the component syntax, you can instantly see a huge difference. It's a lot more clean and concise, and is generally preferred over the "default" component approach, because of its better TypeScript support, performance, and ease of use.</p>
<h2 id="heading-4-putting-it-together">4. Putting it together</h2>
<p>So if we combine the use of TypeScript and the Composition API (using the <code>script setup</code> syntax), we get the following boilerplate code for our Vue 3 components. It's important to use the <code>lang="ts"</code> attribute so that strict type checking is enabled.</p>
<pre><code class="lang-javascript">&lt;script setup lang=<span class="hljs-string">"ts"</span>&gt;
&lt;/script&gt;

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span></span>
</code></pre>
<p>Quite little code, isn't it? I really value the beauty and simplicity of writing components like this. Compared to the class component approach in Vue 2, there is practically no overhead required to bootstrap new components.</p>
<h2 id="heading-5-custom-button-component">5. Custom button component</h2>
<p>Let's build our first custom <code>MagicButton</code> component in Vue 3. We will add more functionality to the component step-by-step, which I will explain in detail.</p>
<p>Our initial draft renders a default HTML button element with the text "Click me", but doesn't provide any options to pass props or receive events.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// MagicButton.vue</span>

&lt;script setup lang=<span class="hljs-string">"ts"</span>&gt;
&lt;/script&gt;

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>Click me<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span></span>
</code></pre>
<h3 id="heading-props">Props</h3>
<p>We want to accept a text that the button should display. Therefore, we first add a <code>Props</code> interface to the component, which defines the shape of the props that can be passed. We then call <code>defineProps&lt;Props&gt;()</code> to expose our props.</p>
<pre><code class="lang-diff">// MagicButton.vue

&lt;script setup lang="ts"&gt;
<span class="hljs-addition">+ interface Props {</span>
<span class="hljs-addition">+  text: string</span>
<span class="hljs-addition">+ }</span>

<span class="hljs-addition">+ defineProps&lt;Props&gt;()</span>
&lt;/script&gt;

&lt;template&gt;
<span class="hljs-addition">+  &lt;button&gt;{{ text }}&lt;/button&gt;</span>
&lt;/template&gt;
</code></pre>
<p>Like that, we are able to import the component and use it as follows.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Home.vue</span>

&lt;script setup lang=<span class="hljs-string">"ts"</span>&gt;
<span class="hljs-keyword">import</span> MagicButton <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/MagicButton.vue'</span>
&lt;/script&gt;

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">MagicButton</span> <span class="hljs-attr">text</span>=<span class="hljs-string">"Login"</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span></span>
</code></pre>
<h3 id="heading-default-values">Default values</h3>
<p>We want to be able to set the loading state of the button, which should be an optional property. Therefore, we add another prop called <code>loading</code>, which accepts a boolean value. Since we don't want to explicitly set this prop, we use the <code>withDefaults</code> compiler macro to define a default value. That way, the compiler knows that this property is optional and won't warn us when not setting it. We also set the <code>button</code> state to <code>disabled</code> if <code>loading</code> is true and show a different text in that case.</p>
<pre><code class="lang-diff">// MagicButton.vue

&lt;script setup lang="ts"&gt;
interface Props {
  text: string
<span class="hljs-addition">+ loading: boolean</span>
}

<span class="hljs-addition">+ withDefaults(defineProps&lt;Props&gt;(), {</span>
<span class="hljs-addition">+  loading: false</span>
<span class="hljs-addition">+ })</span>
&lt;/script&gt;

&lt;template&gt;
<span class="hljs-addition">+  &lt;button :disabled="loading"&gt;</span>
<span class="hljs-addition">+    &lt;span v-if="loading"&gt;Loading...&lt;/span&gt;</span>
<span class="hljs-addition">+    &lt;span v-else&gt;{{ text }}&lt;/span&gt;</span>
   &lt;/button&gt;
&lt;/template&gt;
</code></pre>
<h3 id="heading-emits">Emits</h3>
<p>We also want to get an event when the button is actually clicked. We therefore define emits using the <code>defineEmits</code> compiler macro. Whenever the button is clicked, we call the <code>click</code> event, passing the actual click event payload.</p>
<pre><code class="lang-diff">// MagicButton.vue

&lt;script setup lang="ts"&gt;
interface Props {
  text: string
  loading: boolean
}

withDefaults(defineProps&lt;Props&gt;(), {
  loading: false
})

<span class="hljs-addition">+ const emit = defineEmits&lt;{</span>
<span class="hljs-addition">+  (event: 'click', mouseEvent: MouseEvent): void</span>
<span class="hljs-addition">+ }&gt;()</span>
&lt;/script&gt;

&lt;template&gt;
<span class="hljs-addition">+  &lt;button @click="(event) =&gt; emit('click', event)" :disabled="loading"&gt;</span>
     &lt;span v-if="loading"&gt;Loading...&lt;/span&gt;
     &lt;span v-else&gt;{{ text }}&lt;/span&gt;
   &lt;/button&gt;
&lt;/template&gt;
</code></pre>
<h3 id="heading-wrapping-up">Wrapping up</h3>
<p>So we created a custom <code>&lt;MagicButton&gt;</code> component and added support to accept props (including default values) using <code>defineProps</code> and <code>withDefaults</code>, and emit events using <code>defineEmits</code> — all in a type-safe manner! That's pretty neat. We can now use our custom component as follows.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Home.vue</span>

&lt;script setup lang=<span class="hljs-string">"ts"</span>&gt;
<span class="hljs-keyword">import</span> MagicButton <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/MagicButton.vue'</span>

<span class="hljs-keyword">const</span> click = <span class="hljs-function">(<span class="hljs-params">event: MouseEvent</span>) =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'click'</span>, event)
}
&lt;/script&gt;

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">MagicButton</span> <span class="hljs-attr">loading</span> <span class="hljs-attr">text</span>=<span class="hljs-string">"Login"</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"click"</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span></span>
</code></pre>
<h2 id="heading-6-custom-input-component">6. Custom input component</h2>
<p>Let's build a second custom component called <code>MagicInput</code>. In this component, we will use a custom <code>v-model</code> expression, call functions within our component, as well as introduce reactivity using <code>ref</code> and <code>computed</code>. Again, we start with the most basic setup, rendering only a default HTML input element.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// MagicInput.vue</span>

&lt;script setup lang=<span class="hljs-string">"ts"</span>&gt;
&lt;/script&gt;

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span></span>
</code></pre>
<h3 id="heading-two-way-binding">Two-way binding</h3>
<p>To use two-way binding with <code>v-model</code> in a custom component, we can use the <code>modelValue</code> prop and the <code>update:modelValue</code> emit accordingly.</p>
<pre><code class="lang-diff">// MagicInput.vue

&lt;script setup lang="ts"&gt;
<span class="hljs-addition">+ interface Props {</span>
<span class="hljs-addition">+   modelValue: string</span>
<span class="hljs-addition">+ }</span>

<span class="hljs-addition">+ defineProps&lt;Props&gt;()</span>

<span class="hljs-addition">+ const emit = defineEmits&lt;{</span>
<span class="hljs-addition">+  (event: 'update:modelValue', value: string): void</span>
<span class="hljs-addition">+ }&gt;()</span>
}
&lt;/script&gt;

&lt;template&gt;
<span class="hljs-addition">+ &lt;input :value="modelValue" @input="emit('update:modelValue', $event.target.value)" type="text" /&gt;</span>
&lt;/template&gt;
</code></pre>
<p>We can then use the <code>v-model</code> expression on our custom component to two-way bind the text.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Home.vue</span>

&lt;script setup lang=<span class="hljs-string">"ts"</span>&gt;
<span class="hljs-keyword">import</span> { ref } <span class="hljs-keyword">from</span> <span class="hljs-string">'vue'</span>
<span class="hljs-keyword">import</span> MagicInput <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/MagicInput.vue'</span>

<span class="hljs-keyword">const</span> text = ref(<span class="hljs-string">''</span>)
&lt;/script&gt;

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">MagicInput</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"text"</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span></span>
</code></pre>
<h3 id="heading-ref-and-computed">ref and computed</h3>
<p>To get a bit more into detail on what the Composition API offers us, we are now going to add some reactivity using <code>ref</code> and <code>computed</code>. We therefore get rid of the two-way binding and instead, accept only an initial value and use an internal <code>ref</code> that handles input changes.</p>
<pre><code class="lang-diff">// MagicInput.vue

&lt;script setup lang="ts"&gt;
<span class="hljs-addition">+ import { ref } from 'vue'</span>

interface Props {
<span class="hljs-deletion">- modelValue: string</span>
<span class="hljs-addition">+ initialValue: string</span>
}

const props = defineProps&lt;Props&gt;()

// Introduce a ref and pass the initalValue prop as the initial value
<span class="hljs-addition">+ const text = ref(props.initialValue)</span>

<span class="hljs-deletion">- const emit = defineEmits&lt;{</span>
<span class="hljs-deletion">-  (event: 'update:modelValue', value: string): void</span>
<span class="hljs-deletion">- }&gt;()</span>
}
&lt;/script&gt;

&lt;template&gt;
  &lt;input v-model="text" type="text" /&gt;
&lt;/template&gt;
</code></pre>
<p>So far so good, we now have a reactive <code>ref</code> variable that is bound to the <code>input</code> using the <code>v-model</code> expression. That way, the variable always reflects the current value of the input. Now, let's add a <code>computed</code> property that displays the length of the current text.</p>
<pre><code class="lang-diff">// MagicInput.vue

&lt;script setup lang="ts"&gt;
<span class="hljs-deletion">- import { ref } from 'vue'</span>
<span class="hljs-addition">+ import { ref, computed } from 'vue'</span>

interface Props {
  initialValue: string
}

const props = defineProps&lt;Props&gt;()

const text = ref(props.initialValue)
<span class="hljs-addition">+ const textLength = computed(() =&gt; text.value.length)</span>
&lt;/script&gt;

&lt;template&gt;
  &lt;input v-model="text" type="text" /&gt;
<span class="hljs-addition">+ &lt;p&gt;Your text is {{ textLength }} characters long.&lt;/p&gt;</span>
&lt;/template&gt;
</code></pre>
<p>So now we can use the <code>textLength</code> computed property that always returns the current length of the text. Please note that, because <code>text</code> is a <code>ref</code>, we need to call <code>.value</code> (e.g. <code>text.value.length</code>) to get the actual value of the property.</p>
<h3 id="heading-functions">Functions</h3>
<p>Most of the time, we also want to execute some kind of logic within our components, that's why we'll add a function that logs the current text of the input to the console whenever it changes. Since all top-level bindings are exposed to our template, it's as easy as adding a default TypeScript function.</p>
<pre><code class="lang-diff">// MagicInput.vue

&lt;script setup lang="ts"&gt;
import { ref, computed } from 'vue'

interface Props {
  initialValue: string
}

const props = defineProps&lt;Props&gt;()

const text = ref(props.initialValue)
const textLength = computed(() =&gt; text.value.length)

<span class="hljs-addition">+ const logText = (text: string) =&gt; {</span>
<span class="hljs-addition">+  console.log(`The current text is ${text}`)</span>
<span class="hljs-addition">+ }</span>
&lt;/script&gt;

&lt;template&gt;
<span class="hljs-addition">+ &lt;input </span>
<span class="hljs-addition">+   v-model="text"</span>
<span class="hljs-addition">+   @input="logText($event.target.value)"</span>
<span class="hljs-addition">+   type="text"</span>
<span class="hljs-addition">+ /&gt;</span>
  &lt;p&gt;Your text is {{ textLength }} characters long.&lt;/p&gt;
&lt;/template&gt;
</code></pre>
<h3 id="heading-wrapping-up-again">Wrapping up (again)</h3>
<p>This time, we created a custom <code>&lt;MagicInput&gt;</code> component that allows us to use <code>v-model</code>, leverage reactivity using <code>ref</code> and <code>computed</code> and also execute custom logic. We can now use our custom component as follows.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Home.vue</span>

&lt;script setup lang=<span class="hljs-string">"ts"</span>&gt;
<span class="hljs-keyword">import</span> { ref } <span class="hljs-keyword">from</span> <span class="hljs-string">'vue'</span>
<span class="hljs-keyword">import</span> MagicInput <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/MagicInput.vue'</span>

<span class="hljs-keyword">const</span> text = ref(<span class="hljs-string">'Ronald Blüthl'</span>)
&lt;/script&gt;

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
  <span class="hljs-comment">&lt;!-- First version using v-model --&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">MagicInput</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"text"</span> /&gt;</span>

  <span class="hljs-comment">&lt;!-- Second version using initial value --&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">MagicInput</span> <span class="hljs-attr">initial-value</span>=<span class="hljs-string">"Ronald Blüthl"</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span></span>
</code></pre>
<h2 id="heading-7-summary">7. Summary</h2>
<p>We built two minimalistic components, <code>MagicButton</code> and <code>MagicInput</code>, that cover probably 95% of the functionality that is typically needed when creating custom components.</p>
<ul>
<li>Using TypeScript to enjoy full type safety for all our components </li>
<li><code>script setup</code> to make use of the Composition API in a very convenient way</li>
<li><code>defineProps</code> and <code>withDefaults</code> for props and default values</li>
<li><code>defineEmits</code> for emits (events)</li>
<li><code>v-model</code> for two-way binding</li>
<li><code>ref</code> for reactive data</li>
<li><code>computed</code> for reactive read-only data</li>
</ul>
<p>Using these few techniques, we're able to pass data to a component, receive data from a component, bind values in both ways and create reactive state and logic.</p>
<h2 id="heading-8-general-considerations">8. General considerations</h2>
<p>In Vue, there are sometimes many ways to achieve the desired result. I usually try to be as consistent as possible, that's why I make sure to follow these rules (most of which are suggested in the Vue documentation as well). </p>
<h3 id="heading-naming-and-casing">Naming and casing</h3>
<ul>
<li>Use <code>PascalCase</code> for components (<code>&lt;MagicButton&gt;</code>, <code>&lt;MagicInput&gt;</code>)</li>
<li>Use <code>kebab-case</code> for props (<code>initial-value</code>, <code>loading</code>) — except <code>modelValue</code></li>
</ul>
<h3 id="heading-best-practices">Best practices</h3>
<ul>
<li>Use single quotes instead of double quotes</li>
<li>Infer the data type if obvious (<code>const text = ref('Ronald')</code>) instead of (<code>const text = ref&lt;string&gt;('Ronald')</code>)</li>
<li>Define the data type if it must be explicit (e.g. <code>const text = ref&lt;string | null&gt;(null)</code>)</li>
<li>Don‘t use semicolons (they are not necessary and improve readability)</li>
<li>Always extract a <code>Props</code> interface instead of defining an inline object</li>
<li>Prefer <code>initial-value="Ronald Blüthl"</code> over <code>:initial-value="'Ronald Blüthl'"</code> when NOT passing a variable</li>
<li>Prefer <code>loading</code> over <code>:loading="true"</code> when passing boolean props</li>
<li>Avoid <code>watch</code> expressions as much as possible (they are really hard to debug)</li>
</ul>
<h3 id="heading-one-way-data-flow">One-way data flow</h3>
<p>Data flows into one way only in Vue. If the parent data updates, the child data is updated as well, but not the other way around. This means, that <code>props</code> are read-only. If you want to mutate passed props, use a ref and pass the prop value as the initial value, for example:</p>
<pre><code class="lang-javascript">interface Props {
  <span class="hljs-attr">initialText</span>: string
}

<span class="hljs-keyword">const</span> props = defineProps&lt;Props&gt;()
<span class="hljs-keyword">const</span> text = ref(props.initialText)
</code></pre>
<h3 id="heading-dont-mutate-objects-and-arrays">Don't mutate objects and arrays</h3>
<p>Because of the nature of JavaScript objects and arrays, it is technically possible to mutate them in a component, which then also affects the parent component. You should always avoid this, as it becomes extremely hard to discover problems in your data flow later on. Instead, emit an event with the updated data and let the parent component perform the mutation, for example:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> props = defineProps&lt;{
  <span class="hljs-attr">names</span>: string[]
}&gt;

<span class="hljs-keyword">const</span> emit = defineEmits&lt;{
  (event: <span class="hljs-string">'change'</span>, <span class="hljs-attr">names</span>: string[]): <span class="hljs-keyword">void</span>
}&gt;()

<span class="hljs-keyword">const</span> addName = <span class="hljs-function">(<span class="hljs-params">name: string</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> updatedNames = [...props.names, name]
  emit(<span class="hljs-string">'change'</span>, updatedNames)
}
</code></pre>
<h2 id="heading-9-final-words">9. Final words</h2>
<p>So this is my practical approach to building Vue 3 components, which I used for many projects in the last couple of months. As mentioned at the beginning of the article, I've been using Vue for many years already, and I think that it really grew as a framework. The combination of using the Composition API with TypeScript and <code>script setup</code> is a really nice way to write clean and concise components in Vue 3. It works very well for me, and I hope it does for you too.</p>
<p>If you have any questions, just let me know in the comments below. If you found this post useful, feel free to <a target="_blank" href="https://twitter.com/rbluethl">follow me on Twitter</a>, as I document my journey as an indie hacker there. My DMs are open (I'm always happy to help). 🙌</p>
]]></content:encoded></item><item><title><![CDATA[How to implement better APIs]]></title><description><![CDATA[TL;DR
I created "reference implementation" based on my recent post on How to design better APIs. I tried my best to practically implement all tips mentioned in the article. It's built with Next.js. Check it out here.
Walk-through Video
https://www.yo...]]></description><link>https://r.bluethl.net/how-to-implement-better-apis</link><guid isPermaLink="true">https://r.bluethl.net/how-to-implement-better-apis</guid><category><![CDATA[APIs]]></category><category><![CDATA[REST API]]></category><category><![CDATA[Next.js]]></category><category><![CDATA[json]]></category><dc:creator><![CDATA[Ronald Blüthl]]></dc:creator><pubDate>Sat, 02 Apr 2022 13:52:26 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1649586379853/J6cjDZR7t.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-tldr">TL;DR</h3>
<p>I created "reference implementation" based on my recent post on <a target="_blank" href="https://r.bluethl.net/how-to-design-better-apis">How to design better APIs</a>. I tried my best to practically implement all tips mentioned in the article. It's built with Next.js. <a target="_blank" href="https://github.com/rbluethl/better-apis">Check it out here</a>.</p>
<h3 id="heading-walk-through-video">Walk-through Video</h3>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=H3YLiCtGits">https://www.youtube.com/watch?v=H3YLiCtGits</a></div>
<h3 id="heading-preface">Preface</h3>
<p>On March 3rd 2022, I published an article on <a target="_blank" href="https://r.bluethl.net/how-to-design-better-apis">How to design better APIs</a> on my <a target="_blank" href="https://r.bluethl.net">Hashnode blog</a>. For some reason, it got quite popular — by the time of writing this, it has over 325 reactions, 34 comments (including my answers) and 112k+ views. It even made it to the <a target="_blank" href="https://news.ycombinator.com/item?id=30647784">front page of Hacker News</a> on March 12th, which is kind of a big deal for me.</p>
<p>What I’m even more happy about, however, is that so many people reached out to me, said that the post was helpful and that it really provided value to them. I appreciate that a lot and I’ll do my best to continue creating useful content in the future, so thank you for reading this. 🙂</p>
<p>Since the tips mentioned in the post were meant to be „language-agnostic“, a couple of folks also asked if there is a project where they can look up an actual real-world implementation. That’s when I thought it would be a nice idea to complement the blog post with an actual project where most of the tips are applied in practice. So here it is! The API is, of course, overly simplistic (no database, no real authentication), but you should get an idea of all the concepts.</p>
<h3 id="heading-how-does-it-work">How does it work?</h3>
<p>The project is built with <a target="_blank" href="https://nextjs.org/docs/api-routes/introduction">Next.js API Routes</a> and TypeScript. I created one <code>/users</code> resource and tried to compress all 15 tips (including pagination, error handling, ...) into a few routes. You can have a look at the repository and the entire source code on my GitHub account. <a target="_blank" href="https://github.com/rbluethl/better-apis">Clone it here</a>. If you have any questions, just <a target="_blank" href="https://twitter.com/rbluethl">shoot me a DM on Twitter</a>. I'm always happy to help and discuss.</p>
<p>The project is basically structured like this:</p>
<ul>
<li><code>pages/api/v1*</code> — The API</li>
<li><code>models/*</code> — Request and response types</li>
<li><code>services/*</code> — Fake data services</li>
</ul>
<p>In order to keep everything focused on the API itself, I didn't use a real database. Instead, I "faked" the data access logic and used services that return test data.</p>
<p>Following, I will repeat the original blog post's tips and add detailed information on how they're implemented. You can click most of the headers and jump right into the code on GitHub.</p>
<p>There is also a <a target="_blank" href="https://github.com/rbluethl/better-apis/blob/main/Better%20APIs.postman_collection.json">Postman collection</a> checked into the project, where you can play with all API routes.</p>
<h3 id="heading-1-be-consistent">1. Be consistent</h3>
<p>I use the same naming conventions, resource names, HTTP methods and status codes across the entire project.</p>
<ul>
<li><code>snake_case</code> naming in requests and responses</li>
<li><code>POST</code> for creating</li>
<li><code>GET</code> for reading</li>
<li><code>PATCH</code> for updating</li>
<li><code>DELETE</code> for deleting</li>
<li><code>200</code> for success</li>
<li><code>201</code> for creation</li>
<li><code>400</code> for client errors</li>
<li><code>401</code> for unauthorized</li>
<li><code>404</code> for not found</li>
<li><code>405</code> for method not allowed</li>
</ul>
<h3 id="heading-2-use-iso-8601-utc-dateshttpsgithubcomrbluethlbetter-apisblobmainservicesuserstsl31"><a target="_blank" href="https://github.com/rbluethl/better-apis/blob/main/services/users.ts#L31">2. Use ISO 8601 UTC dates</a></h3>
<p>I use ISO 8601 UTC dates (more precisely, the specific <a target="_blank" href="https://datatracker.ietf.org/doc/html/rfc3339">RFC 3339</a> format, providing date and time). </p>
<pre><code class="lang-javascript">  <span class="hljs-keyword">const</span> now = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>()
  <span class="hljs-keyword">return</span> {
    id,
    name,
    email,
    <span class="hljs-attr">created_at</span>: now.toISOString(),
    <span class="hljs-attr">modified_at</span>: now.toISOString()
  }
</code></pre>
<h3 id="heading-3-make-an-exception-for-public-endpointshttpsgithubcomrbluethlbetter-apisblobmainpagesmiddlewaretsx"><a target="_blank" href="https://github.com/rbluethl/better-apis/blob/main/pages/_middleware.tsx">3. Make an exception for public endpoints</a></h3>
<p>I added a middleware that requires an API key to be present for each API route.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { NextResponse, NextRequest } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/server'</span>
<span class="hljs-keyword">import</span> { unauthorized } <span class="hljs-keyword">from</span> <span class="hljs-string">'models/error'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">middleware</span>(<span class="hljs-params">req: NextRequest, res: NextResponse</span>) </span>{
  <span class="hljs-keyword">const</span> { pathname } = req.nextUrl

  <span class="hljs-keyword">if</span> (pathname.startsWith(<span class="hljs-string">'/api'</span>) &amp;&amp; !req.headers.get(<span class="hljs-string">'Api-Key'</span>)) {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Response(<span class="hljs-built_in">JSON</span>.stringify(unauthorized), {
      <span class="hljs-attr">status</span>: <span class="hljs-number">401</span>, <span class="hljs-attr">headers</span>: {
        <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'application/json'</span>
      }
    })
  }

  <span class="hljs-keyword">return</span> NextResponse.next()
}
</code></pre>
<h3 id="heading-4-provide-a-health-check-endpointhttpsgithubcomrbluethlbetter-apisblobmainpagesapiv1statusindextsl6"><a target="_blank" href="https://github.com/rbluethl/better-apis/blob/main/pages/api/v1/status/index.ts#L6">4. Provide a health check endpoint</a></h3>
<p>I added a <code>GET /api/v1/status</code> endpoint that always returns <code>200</code>. </p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handler</span>(<span class="hljs-params">req: NextApiRequest, res: NextApiResponse</span>) </span>{
  <span class="hljs-comment">// GET /api/v1/status</span>
  <span class="hljs-keyword">if</span> (req.method === <span class="hljs-string">'GET'</span>) {
    res.status(<span class="hljs-number">200</span>).end()
  }

  res.status(<span class="hljs-number">405</span>).end()
}
</code></pre>
<h3 id="heading-5-version-the-apihttpsgithubcomrbluethlbetter-apistreemainpagesapiv1"><a target="_blank" href="https://github.com/rbluethl/better-apis/tree/main/pages/api/v1">5. Version the API</a></h3>
<p>All API routes live inside the v1 folder, which automatically adds the <code>/v1</code> version to every resource within that folder. I also added a <code>/v2</code> version of the status endpoint to give you an idea on how another version would look like.</p>
<h3 id="heading-6-accept-api-key-authenticationhttpsgithubcomrbluethlbetter-apisblobmainpagesmiddlewaretsx"><a target="_blank" href="https://github.com/rbluethl/better-apis/blob/main/pages/_middleware.tsx">6. Accept API key authentication</a></h3>
<p>The middleware is used to determine the presence of an <code>Api-Key</code> HTTP header which could then be used to fetch an account with the given API key from the database. In our case, we only check whether this header is provided, otherwise the API will return a 401.</p>
<h3 id="heading-7-use-reasonable-http-status-codes">7. Use reasonable HTTP status codes</h3>
<p>I'm using a very small set of HTTP status codes (200, 201, 400, 401, 404, 405). See #1 for details.</p>
<h3 id="heading-8-use-reasonable-http-methods">8. Use reasonable HTTP methods</h3>
<p>I'm using a very small set of HTTP methods (<code>POST</code>, <code>GET</code>, <code>PATCH</code>, <code>DELETE</code>). See #1 for details.</p>
<h3 id="heading-9-use-self-explanatory-simple-names">9. Use self-explanatory, simple names</h3>
<p>All endpoints and names are self-explanatory.</p>
<ul>
<li><code>POST /users</code></li>
<li><code>GET /users</code></li>
<li><code>GET /users/{id}</code></li>
<li><code>PATCH /users/{id}</code></li>
<li><code>DELETE /users/{id}</code></li>
</ul>
<h3 id="heading-10-use-standardized-error-responseshttpsgithubcomrbluethlbetter-apisblobmainmodelserrorts"><a target="_blank" href="https://github.com/rbluethl/better-apis/blob/main/models/error.ts">10. Use standardized error responses</a></h3>
<p>I added an error response type that is always used when something wrong happens (4xx).</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> type <span class="hljs-built_in">Error</span> = {
  <span class="hljs-attr">code</span>: string
  <span class="hljs-attr">message</span>: string
}
</code></pre>
<h3 id="heading-11-return-created-resources-upon-posthttpsgithubcomrbluethlbetter-apisblobmainpagesapiv1usersindextsl30"><a target="_blank" href="https://github.com/rbluethl/better-apis/blob/main/pages/api/v1/users/index.ts#L30">11. Return created resources upon POST</a></h3>
<p>After a resource is created, the most recent "snapshot" of that object is returned from the API.</p>
<h3 id="heading-12-prefer-patch-over-puthttpsgithubcomrbluethlbetter-apisblobmainpagesapiv1users5bid5dtsl23"><a target="_blank" href="https://github.com/rbluethl/better-apis/blob/main/pages/api/v1/users/%5Bid%5D.ts#L23">12. Prefer PATCH over PUT</a></h3>
<p>I don't use any <code>PUT</code> requests. Updates are always designed around <code>PATCH</code>.</p>
<h3 id="heading-13-be-as-specific-as-possible">13. Be as specific as possible</h3>
<p>All endpoints are limited to the essentials and don't do anything unexpected. </p>
<h3 id="heading-14-use-paginationhttpsgithubcomrbluethlbetter-apisblobmainpagesapiv1usersindextsl35"><a target="_blank" href="https://github.com/rbluethl/better-apis/blob/main/pages/api/v1/users/index.ts#L35">14. Use pagination</a></h3>
<p>I added a <code>Paged</code> type that wraps GET requests into a standardized paginated response.</p>
<h3 id="heading-15-allow-expanding-resourceshttpsgithubcomrbluethlbetter-apisblobmainpagesapiv1usersindextsl38"><a target="_blank" href="https://github.com/rbluethl/better-apis/blob/main/pages/api/v1/users/index.ts#L38">15. Allow expanding resources</a></h3>
<p>It's possible to load <code>orders</code> when fetching users using the <code>expand</code> query parameter.</p>
]]></content:encoded></item><item><title><![CDATA[How to design better APIs]]></title><description><![CDATA[APIs are awesome, but they're also extremely hard to design. When creating an API from scratch, you need to get many details right. From basic security considerations to using the right HTTP methods, implementing authentication, deciding which reques...]]></description><link>https://r.bluethl.net/how-to-design-better-apis</link><guid isPermaLink="true">https://r.bluethl.net/how-to-design-better-apis</guid><category><![CDATA[APIs]]></category><category><![CDATA[REST API]]></category><category><![CDATA[REST]]></category><category><![CDATA[restful]]></category><category><![CDATA[JWT]]></category><dc:creator><![CDATA[Ronald Blüthl]]></dc:creator><pubDate>Thu, 03 Mar 2022 22:11:31 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1649586422366/OagX7pSnk.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>APIs are awesome, but they're also extremely hard to design. When creating an API from scratch, you need to get many details right. From basic security considerations to using the right HTTP methods, implementing authentication, deciding which requests and responses you should accept and return, ... the list goes on.</p>
<p>In this post, I'm trying my best to compress everything I know about what makes a good API. An API, that your consumers will enjoy using. All tips are language-agnostic, so they apply to any framework or technology.</p>
<h3 id="heading-1-be-consistent">1. Be consistent</h3>
<p>I know it sounds logical, but it's hard to get this one right. The best APIs I know are <em>predictable</em>. When a consumer uses and understands one endpoint, they can expect that another endpoint works the same way. This is important for the entire API and one of the key indicators of whether or not an API is well-designed and great to use.</p>
<ul>
<li>Use the same casing for fields, resources, and parameters (I prefer <code>snake_case</code>)</li>
<li>Use either plural or singular resource names (I prefer plural)<ul>
<li><code>/users/{id}</code>, <code>/orders/{id}</code> or <code>/user/{id}</code>, <code>/order/{id}</code></li>
</ul>
</li>
<li>Use the same authentication and authorization methods for all endpoints</li>
<li>Use the same HTTP headers across the API<ul>
<li>For example <code>Api-Key</code> for passing an API key</li>
</ul>
</li>
<li>Use the same HTTP status codes based on the type of response<ul>
<li>For example <code>404</code> when a resource can not be found</li>
</ul>
</li>
<li>Use the same HTTP methods for the same kind of actions<ul>
<li>For example <code>DELETE</code> when deleting a resource</li>
</ul>
</li>
</ul>
<h3 id="heading-2-use-iso-8601httpsenwikipediaorgwikiiso8601-utc-dates">2. Use <a target="_blank" href="https://en.wikipedia.org/wiki/ISO_8601">ISO 8601</a> UTC dates</h3>
<p>When dealing with date and time, APIs should always return ISO 8601-formatted strings. Displaying dates in a specific time zone is generally a concern of client applications.</p>
<pre><code class="lang-JSON">{
    <span class="hljs-attr">"published_at"</span>: <span class="hljs-string">"2022-03-03T21:59:08Z"</span>
}
</code></pre>
<h3 id="heading-3-make-an-exception-for-public-endpoints">3. Make an exception for public endpoints</h3>
<p>Every endpoint should require authorization <em>by default</em>. Most endpoints require an authenticated user to be called, so making this the default makes sense. If an endpoint needs to be called publicly, explicitly set this endpoint to allow unauthorized requests.</p>
<h3 id="heading-4-provide-a-health-check-endpoint">4. Provide a health check endpoint</h3>
<p>Provide an endpoint (for example <code>GET /health</code>) that determines whether or not a service is healthy. This endpoint can be called by other applications such as load balancers to act in case of a service outage.</p>
<h3 id="heading-5-version-the-api">5. Version the API</h3>
<p>Make sure you version your API and pass the version on each request so that consumers aren't affected by any changes to another version. API versions can be passed using HTTP headers or query/path parameters. Even the first version of the API (1.0) should be explicitly versioned.</p>
<p>Some examples:</p>
<ul>
<li><code>https://api.averagecompany.com/v1/health</code></li>
<li><code>https://api.averagecompany.com/health?api_version=1.0</code></li>
</ul>
<h3 id="heading-6-accept-api-key-authentication">6. Accept API key authentication</h3>
<p>If an API needs to be called by a third party, it makes sense to allow authentication via API keys. API keys should be passed using a custom HTTP header (such as <code>Api-Key</code>). They should have an expiration date, and it must be possible to revoke active keys so that they can be invalidated in case they get compromised. Avoid checking API keys into source control (use environment variables instead).</p>
<h3 id="heading-7-use-reasonable-http-status-codes">7. Use reasonable HTTP status codes</h3>
<p>Use conventional HTTP status codes to indicate the success or failure of a request. Don't use too many, and use the same status codes for the same outcomes across the API. Some examples:</p>
<ul>
<li><code>200</code> for general success</li>
<li><code>201</code> for successful creation</li>
<li><code>400</code> for bad requests from the client</li>
<li><code>401</code> for unauthorized requests</li>
<li><code>403</code> for missing permissions</li>
<li><code>404</code> for missing resources</li>
<li><code>429</code> for too many requests</li>
<li><code>5xx</code> for internal errors (these should be avoided at all costs) </li>
</ul>
<h3 id="heading-8-use-reasonable-http-methods">8. Use reasonable HTTP methods</h3>
<p>There are many HTTP methods, but the most important ones are:</p>
<ul>
<li><code>POST</code> for creating resources<ul>
<li><code>POST /users</code></li>
</ul>
</li>
<li><code>GET</code> for reading resources (both single resources and collections)<ul>
<li><code>GET /users</code></li>
<li><code>GET /users/{id}</code></li>
</ul>
</li>
<li><code>PATCH</code> for applying partial updates to a resource<ul>
<li><code>PATCH /users/{id}</code></li>
</ul>
</li>
<li><code>PUT</code> for applying full updates to a resource (replaces the current resource)<ul>
<li><code>PUT /users/{id}</code></li>
</ul>
</li>
<li><code>DELETE</code> for deleting resources<ul>
<li><code>DELETE /users/{id}</code></li>
</ul>
</li>
</ul>
<h3 id="heading-9-use-self-explanatory-simple-names">9. Use self-explanatory, simple names</h3>
<p>Most endpoints are resource-oriented and should be named that way. Don't add unnecessary information that can be inferred from elsewhere. This also applies to field names.</p>
<p>✅ <strong>GOOD</strong></p>
<ul>
<li><code>GET /users</code> =&gt; Retrieve users</li>
<li><code>DELETE /users/{id}</code> =&gt; Delete a user</li>
<li><code>POST /users/{id}/notifications</code> =&gt; Create a notification for a specific user</li>
<li><code>user.first_name</code></li>
<li><code>order.number</code></li>
</ul>
<p>❌ <strong>BAD</strong></p>
<ul>
<li><code>GET /getUser</code></li>
<li><code>POST /updateUser</code></li>
<li><code>POST /notification/user</code></li>
<li><code>order.ordernumber</code></li>
<li><code>user.firstName</code></li>
</ul>
<h3 id="heading-10-use-standardized-error-responses">10. Use standardized error responses</h3>
<p>Aside from using HTTP status codes that indicate the outcome of the request (success or error), when returning errors, always use a <em>standardized</em> error response that includes more detailed information on what went wrong. Consumers can always expect the same structure and act accordingly.</p>
<pre><code class="lang-JSON"><span class="hljs-comment">// Request =&gt; GET /users/4TL011ax</span>

<span class="hljs-comment">// Response &lt;= 404 Not Found</span>
{
    <span class="hljs-attr">"code"</span>: <span class="hljs-string">"user/not_found"</span>,
    <span class="hljs-attr">"message"</span>: <span class="hljs-string">"A user with the ID 4TL011ax could not be found."</span>
}
</code></pre>
<pre><code class="lang-JSON"><span class="hljs-comment">// Request =&gt; POST /users</span>
{
    <span class="hljs-attr">"name"</span>: <span class="hljs-string">"John Doe"</span>
}

<span class="hljs-comment">// Response &lt;= 400 Bad Request</span>
{
    <span class="hljs-attr">"code"</span>: <span class="hljs-string">"user/email_required"</span>,
    <span class="hljs-attr">"message"</span>: <span class="hljs-string">"The parameter [email] is required."</span>
}
</code></pre>
<h3 id="heading-11-return-created-resources-upon-post">11. Return created resources upon <code>POST</code></h3>
<p>It's a good idea to return the created resource after creating it with a <code>POST</code> request. That's mostly important because the returned, created resource will reflect the current state of the underlying data source and will contain more recent information (such as a generated ID).</p>
<pre><code class="lang-JSON"><span class="hljs-comment">// Request: POST /users</span>
{
    <span class="hljs-attr">"email"</span>: <span class="hljs-string">"jdoe@averagecompany.com"</span>,
    <span class="hljs-attr">"name"</span>: <span class="hljs-string">"John Doe"</span>
}

<span class="hljs-comment">// Response</span>
{
    <span class="hljs-attr">"id"</span>: <span class="hljs-string">"T9hoBuuTL4"</span>,
    <span class="hljs-attr">"email"</span>: <span class="hljs-string">"jdoe@averagecompany.com"</span>,
    <span class="hljs-attr">"name"</span>: <span class="hljs-string">"John Doe"</span>
}
</code></pre>
<h3 id="heading-12-prefer-patch-over-put">12. Prefer <code>PATCH</code> over <code>PUT</code></h3>
<p>As mentioned earlier, <code>PATCH</code> requests should apply partial updates to a resource, whereas <code>PUT</code> replaces an existing resource entirely. It's usually a good idea to design updates around PATCH requests, because:</p>
<ul>
<li>When using <code>PUT</code> to update only a subset of fields for a resource, the entire resource still needs to be passed, which makes it more network-intensive and error-prone</li>
<li>It's also quite dangerous to allow any field to be updated without any restrictions</li>
<li>From my experience, there barely exist any use cases in practice where a full update on a resource would make sense</li>
<li>Imagine an <code>order</code> resource that has an <code>id</code> and a <code>state</code></li>
<li>It would be very dangerous to allow consumers to update the <code>state</code> of an <code>order</code></li>
<li>A state change would much more likely be triggered by another endpoint (such as <code>/orders/{id}/fulfill</code>)</li>
</ul>
<h3 id="heading-13-be-as-specific-as-possible">13. Be as specific as possible</h3>
<p>As outlined in the previous section, it's generally a good idea to be <em>as specific as possible</em> when designing endpoints, naming fields, and deciding which requests and responses to accept. If a <code>PATCH</code> request only accepts two fields (<code>name</code> and <code>description</code>), there is no danger of using it incorrectly and corrupting data.</p>
<h3 id="heading-14-use-pagination">14. Use pagination</h3>
<p>Paginate all requests that return a collection of resources and use the same response structure. Use <code>page_number</code> and <code>page_size</code> (or similar) to control which chunk you want to retrieve. </p>
<pre><code class="lang-JSON"><span class="hljs-comment">// Request =&gt; GET /users?page_number=1&amp;page_size=15</span>

<span class="hljs-comment">// Response &lt;= 200 OK</span>
{
    <span class="hljs-attr">"page_number"</span>: <span class="hljs-number">1</span>,
    <span class="hljs-attr">"page_size"</span>: <span class="hljs-number">15</span>,
    <span class="hljs-attr">"count"</span>: <span class="hljs-number">378</span>,
    <span class="hljs-attr">"data"</span>: [
        <span class="hljs-comment">// resources</span>
    ],
    <span class="hljs-attr">"total_pages"</span>: <span class="hljs-number">26</span>,
    <span class="hljs-attr">"has_previous_page"</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">"has_next_page"</span>: <span class="hljs-literal">true</span>
}
</code></pre>
<h3 id="heading-15-allow-expanding-resources">15. Allow expanding resources</h3>
<p>Allow consumers to load related data using a query parameter called <code>expand</code> (or similar). This is especially useful to avoid round-trips and load all data that is necessary for a specific action in one go.</p>
<pre><code class="lang-JSON"><span class="hljs-comment">// Request =&gt; GET /users/T9hoBuuTL4?expand=orders&amp;expand=orders.items</span>

<span class="hljs-comment">// Response &lt;= 200 OK</span>
{
  <span class="hljs-attr">"id"</span>: <span class="hljs-string">"T9hoBuuTL4"</span>,
  <span class="hljs-attr">"email"</span>: <span class="hljs-string">"jdoe@averagecompany.com"</span>,
  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"John Doe"</span>,
  <span class="hljs-attr">"orders"</span>: [
    {
      <span class="hljs-attr">"id"</span>: <span class="hljs-string">"Hy3SSXU1PF"</span>,
      <span class="hljs-attr">"items"</span>: [
        {
          <span class="hljs-attr">"name"</span>: <span class="hljs-string">"API course"</span>
        },
        {
          <span class="hljs-attr">"name"</span>: <span class="hljs-string">"iPhone 13"</span>
        }
      ]
    },
    {
      <span class="hljs-attr">"id"</span>: <span class="hljs-string">"bx1zKmJLI6"</span>,
      <span class="hljs-attr">"items"</span>: [
        {
          <span class="hljs-attr">"name"</span>: <span class="hljs-string">"SaaS subscription"</span>
        }
      ]
    }
  ]
}
</code></pre>
<p>If you enjoyed this post, feel free to <a target="_blank" href="https://twitter.com/rbluethl">follow me on Twitter</a>.</p>
]]></content:encoded></item><item><title><![CDATA[We went to Ecuador to build an App]]></title><description><![CDATA[A Short Backstory
A good friend of mine, Norbert, moved to the United States a few years ago. Since I still live in Austria, we don't see each other very often. For that reason, we've made it a habit to meet once a year - somewhere in the world. This...]]></description><link>https://r.bluethl.net/we-went-to-ecuador-to-build-an-app</link><guid isPermaLink="true">https://r.bluethl.net/we-went-to-ecuador-to-build-an-app</guid><category><![CDATA[app development]]></category><category><![CDATA[Android]]></category><category><![CDATA[Startups]]></category><category><![CDATA[SaaS]]></category><category><![CDATA[android app development]]></category><dc:creator><![CDATA[Ronald Blüthl]]></dc:creator><pubDate>Mon, 25 Oct 2021 05:41:06 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1649586459470/iy5WW3nf2.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-a-short-backstory">A Short Backstory</h2>
<p>A good friend of mine, <a target="_blank" href="https://twitter.com/TheHuethman">Norbert</a>, moved to the United States a few years ago. Since I still live in Austria, we don't see each other very often. For that reason, we've made it a habit to meet once a year - <em>somewhere</em> in the world. This summer, we went to Ecuador. And quite accidentally, we built an app together...</p>
<p>Norbert and I met somewhere around 2011-2012 at a company where I was doing my apprenticeship at that time. We've been software engineers for all our careers and over the years, we've worked on many projects together - most of which didn't end up anywhere. </p>
<h2 id="heading-ecuador-2021">Ecuador 2021</h2>
<p>In the meantime, we both work as freelance software engineers - giving us the flexibility to work from anywhere at any time. When we flew to Ecuador this year, we were actually planning on working on our ongoing projects during the week, having dinner/drinks at night and visiting some cool places in our spare time. Well, things turned out a bit differently.</p>
<p>Instead of going out for drinks, we decided to do an entire rewrite of <a target="_blank" href="https://autoforwardsms.com/">AutoForward SMS</a>, an app that Norbert acquired on <a target="_blank" href="https://flippa.com/">Flippa</a> earlier this year. (If you're interested in the full story, you should definitely <a target="_blank" href="https://www.indiehackers.com/post/how-i-acquired-a-mobile-app-on-flippa-and-grew-it-from-700-mrr-to-5-4k-d50b9a8e82">read this post on Indie Hackers</a>). </p>
<p>The app's functionality? Forwarding text messages (SMS) to an E-Mail or URL based on a user defined ruleset. Norbert had told me about the acquisition and his intention to rewrite the app before, but there were no concrete plans until our get-together in Quito. </p>
<p>After several conversations, we spontaneously decided to partner up and start rebuilding AutoForward SMS immediately while we were together. So while we were putting in the ours at our client projects, we were diligently drafting, designing and developing the new app every free minute.</p>
<h2 id="heading-the-app">The App</h2>
<h3 id="heading-why-rewrite">Why Rewrite?</h3>
<p>When Norbert took over AutoForward SMS in early 2021, it became clear very quickly that the tech stack was fairly outdated, the code base was in poor condition and the UI/UX could be largely improved. Also, the app should become more scalable, reliable and generally be prepared for future growth - something that couldn't be done very easily.</p>
<h3 id="heading-the-new-tech-stacks-premise">The New Tech Stack's Premise</h3>
<p>For the reasons mentioned above, the new tech stack needed to meet some criteria:</p>
<ul>
<li>Cloud-native, serverless architecture</li>
<li>Cross-platform mobile app framework</li>
<li>Minimalistic admin UI to manage users/subscriptions</li>
<li>Generally lightweight and straightforward technology, no overhead</li>
</ul>
<p>Considering our skillsets and existing knowledge, we then went with the following technologies:</p>
<ul>
<li><strong>Firebase Cloud Functions</strong> — Backend</li>
<li><strong>Firebase Firestore</strong> — Database</li>
<li><strong>Flutter</strong> — Mobile App</li>
<li><strong>Vue &amp; Tailwind</strong> — Admin UI</li>
<li><strong>WordPress</strong> — Website</li>
</ul>
<h2 id="heading-the-result">The Result</h2>
<p>We dedicated our entire workcation pushing the app forward and we actually managed to develop a large chunk of the entire new product (App, Backend, Admin UI, Website) in less than two weeks. When we parted ways at the end of August, we were 80% done and decided to continue working on the remaining 20% remotely. </p>
<p>And so far, everything worked out really well. By the time of writing this blog post, we have already deployed and rolled out the new product to our customers. Our new tech stack is rock-solid and just a joy to work with, both in terms of simplicity and stability.</p>
<p>We challenged ourselves to develop a solid product in a really short time period whilst working on other time-consuming projects, which turned out to work really well. When you commit yourself to a fun project with a good friend, there are literally no limits.</p>
<h2 id="heading-whats-next">What's Next?</h2>
<p>Now that we have successfully made the transition to the new product, we have a lot of work to do at marketing the product, bringing it into the Google Play Store and generally polishing and improving the App. Our target is to attract new customers and making AutoForward SMS the #1 solution for forwarding text messages.</p>
<p>If you enjoyed this post, you can <a target="_blank" href="https://twitter.com/rbluethl">follow my journey on Twitter</a>.</p>
]]></content:encoded></item></channel></rss>