<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>Anton Ždanov</title>
        <link>https://www.azdanov.dev</link>
        <description>Personal website of Anton Ždanov</description>
        <lastBuildDate>Wed, 29 Apr 2026 02:37:39 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>Anton Ždanov</title>
            <url>https://www.azdanov.dev/favicon.ico</url>
            <link>https://www.azdanov.dev</link>
        </image>
        <copyright>All rights reserved 2026</copyright>
        <item>
            <title><![CDATA[Rust Error Guidelines]]></title>
            <link>https://www.azdanov.dev/articles/2025/rust-error-guidelines</link>
            <guid isPermaLink="false">https://www.azdanov.dev/articles/2025/rust-error-guidelines</guid>
            <pubDate>Fri, 31 Oct 2025 12:34:39 GMT</pubDate>
            <content:encoded><![CDATA[<blockquote>
<p>Personal notes on Rust error guidelines, handling, and tips for library and application errors.</p>
</blockquote>
<h2>TL;DR</h2>
<p><strong>Core Principles:</strong></p>
<ul>
<li>Use <code>enum</code> types with <code>#[non_exhaustive]</code> for error definitions</li>
<li>Wrap third-party errors—never expose them directly in your public API</li>
<li>Implement <code>Display</code> and <code>Error</code> traits (or use <code>thiserror</code> to reduce boilerplate)</li>
<li>Create <code>Result&lt;T&gt;</code> type aliases for cleaner function signatures</li>
</ul>
<p><strong>Key Decisions:</strong></p>
<ul>
<li><strong>Libraries:</strong> Use <code>thiserror</code> for custom error types with minimal boilerplate</li>
<li><strong>Applications:</strong> Use <code>anyhow</code> for flexible error handling with context</li>
<li><strong>CLI Tools:</strong> Consider <code>miette</code> or <code>eyre</code> for rich, user-friendly error diagnostics</li>
<li><strong>Recoverable vs Unrecoverable:</strong> Use <code>Result</code> for recoverable errors, <code>panic!</code> for programming errors</li>
</ul>
<p><strong>Essential Patterns:</strong></p>
<ul>
<li>Implement <code>From</code> trait for automatic error conversion with <code>?</code> operator</li>
<li>Add context to errors using <code>map_err()</code> or <code>.context()</code> (with <code>anyhow</code>)</li>
<li>Document error conditions in function docs with <code># Errors</code> section</li>
<li>Use helper methods for common error construction patterns</li>
</ul>
<h2>Recommendations for Creating Error Types</h2>
<h3>1. Use an <code>enum</code> for Your Error Type</h3>
<p>Define errors as <a href="https://doc.rust-lang.org/reference/items/enumerations.html"><code>enum</code></a> to represent multiple distinct error conditions:</p>
<pre class="language-rust"><code class="language-rust"><span class="token keyword">pub</span> <span class="token keyword">enum</span> <span class="token type-definition class-name">MyError</span> <span class="token punctuation">{</span>
    <span class="token class-name">IoError</span><span class="token punctuation">(</span><span class="token namespace">std<span class="token punctuation">::</span>io<span class="token punctuation">::</span></span><span class="token class-name">Error</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token class-name">ParseError</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token class-name">ValidationError</span> <span class="token punctuation">{</span> field<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token punctuation">,</span> reason<span class="token punctuation">:</span> <span class="token class-name">String</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
</code></pre>
<p><strong>Why?</strong> Enums provide type-safe error handling and enable exhaustive pattern matching.</p>
<h3>2. Group Related Error Conditions</h3>
<p>Organize error variants logically within as few enums as necessary:</p>
<pre class="language-rust"><code class="language-rust"><span class="token keyword">pub</span> <span class="token keyword">enum</span> <span class="token type-definition class-name">DatabaseError</span> <span class="token punctuation">{</span>
    <span class="token class-name">ConnectionFailed</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token class-name">QueryFailed</span> <span class="token punctuation">{</span> query<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token punctuation">,</span> cause<span class="token punctuation">:</span> <span class="token class-name">String</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token class-name">RecordNotFound</span> <span class="token punctuation">{</span> id<span class="token punctuation">:</span> <span class="token keyword">u64</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token class-name">Timeout</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
</code></pre>
<p><strong>Why?</strong> This improves maintainability and keeps error types focused on a single domain.</p>
<h3>3. Encapsulate Third-Party Errors</h3>
<p>Don't expose error types from external dependencies directly:</p>
<pre class="language-rust"><code class="language-rust"><span class="token comment">// Bad: Exposes implementation details</span>
<span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function-definition function">read_config</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token class-name">Result</span><span class="token operator">&lt;</span><span class="token class-name">Config</span><span class="token punctuation">,</span> <span class="token namespace">std<span class="token punctuation">::</span>io<span class="token punctuation">::</span></span><span class="token class-name">Error</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span>

<span class="token comment">// Good: Wraps external error</span>
<span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function-definition function">read_config</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token class-name">Result</span><span class="token operator">&lt;</span><span class="token class-name">Config</span><span class="token punctuation">,</span> <span class="token class-name">ConfigError</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span>

<span class="token keyword">pub</span> <span class="token keyword">enum</span> <span class="token type-definition class-name">ConfigError</span> <span class="token punctuation">{</span>
    <span class="token class-name">Io</span><span class="token punctuation">(</span><span class="token namespace">std<span class="token punctuation">::</span>io<span class="token punctuation">::</span></span><span class="token class-name">Error</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token class-name">Parse</span><span class="token punctuation">(</span><span class="token namespace">serde_json<span class="token punctuation">::</span></span><span class="token class-name">Error</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
</code></pre>
<p><strong>Why?</strong> This decouples your API from implementation details and allows error type evolution.</p>
<h3>4. Make Your Enum Non-Exhaustive</h3>
<p>Use <a href="https://doc.rust-lang.org/reference/attributes/type_system.html#r-attributes.type-system.non_exhaustive"><code>#[non_exhaustive]</code></a> to allow adding variants without breaking changes:</p>
<pre class="language-rust"><code class="language-rust"><span class="token attribute attr-name">#[non_exhaustive]</span>
<span class="token keyword">pub</span> <span class="token keyword">enum</span> <span class="token type-definition class-name">ApiError</span> <span class="token punctuation">{</span>
    <span class="token class-name">Unauthorized</span><span class="token punctuation">,</span>
    <span class="token class-name">NotFound</span><span class="token punctuation">,</span>
    <span class="token class-name">ServerError</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
</code></pre>
<p><strong>Why?</strong> This maintains backward compatibility when adding new error variants in future releases.</p>
<h3>5. Implement Required Traits</h3>
<h4>5a. Manual Implementation</h4>
<p>Will require implementing <a href="https://doc.rust-lang.org/std/fmt/trait.Display.html"><code>std::fmt::Display</code></a> and <a href="https://doc.rust-lang.org/std/fmt/struct.Error.html"><code>std::error::Error</code></a>:</p>
<pre class="language-rust"><code class="language-rust"><span class="token keyword">use</span> <span class="token namespace">std<span class="token punctuation">::</span></span>fmt<span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token namespace">std<span class="token punctuation">::</span>error<span class="token punctuation">::</span></span><span class="token class-name">Error</span><span class="token punctuation">;</span>

<span class="token keyword">impl</span> <span class="token namespace">fmt<span class="token punctuation">::</span></span><span class="token class-name">Display</span> <span class="token keyword">for</span> <span class="token class-name">MyError</span> <span class="token punctuation">{</span>
    <span class="token keyword">fn</span> <span class="token function-definition function">fmt</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">self</span><span class="token punctuation">,</span> f<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token keyword">mut</span> <span class="token namespace">fmt<span class="token punctuation">::</span></span><span class="token class-name">Formatter</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token namespace">fmt<span class="token punctuation">::</span></span><span class="token class-name">Result</span> <span class="token punctuation">{</span>
        <span class="token keyword">match</span> <span class="token keyword">self</span> <span class="token punctuation">{</span>
            <span class="token class-name">MyError</span><span class="token punctuation">::</span><span class="token class-name">IoError</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token macro property">write!</span><span class="token punctuation">(</span>f<span class="token punctuation">,</span> <span class="token string">"IO error: {}"</span><span class="token punctuation">,</span> e<span class="token punctuation">)</span><span class="token punctuation">,</span>
            <span class="token class-name">MyError</span><span class="token punctuation">::</span><span class="token class-name">ParseError</span><span class="token punctuation">(</span>msg<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token macro property">write!</span><span class="token punctuation">(</span>f<span class="token punctuation">,</span> <span class="token string">"Parse error: {}"</span><span class="token punctuation">,</span> msg<span class="token punctuation">)</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token comment">// Implementing source will enable error chaining</span>
<span class="token comment">// https://doc.rust-lang.org/std/error/trait.Error.html#method.source</span>
<span class="token keyword">impl</span> <span class="token class-name">Error</span> <span class="token keyword">for</span> <span class="token class-name">MyError</span> <span class="token punctuation">{</span>
    <span class="token keyword">fn</span> <span class="token function-definition function">source</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">self</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token class-name">Option</span><span class="token operator">&lt;</span><span class="token operator">&amp;</span><span class="token punctuation">(</span><span class="token keyword">dyn</span> <span class="token class-name">Error</span> <span class="token operator">+</span> <span class="token lifetime-annotation symbol">'static</span><span class="token punctuation">)</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
        <span class="token keyword">match</span> <span class="token keyword">self</span> <span class="token punctuation">{</span>
            <span class="token class-name">MyError</span><span class="token punctuation">::</span><span class="token class-name">IoError</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token class-name">Some</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span><span class="token punctuation">,</span>
            _ <span class="token operator">=&gt;</span> <span class="token class-name">None</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<h4>5b. Using <code>thiserror</code> (Recommended)</h4>
<p>An alternative is to use the <a href="https://crates.io/crates/thiserror"><code>thiserror</code></a> package to reduce boilerplate:</p>
<pre class="language-rust"><code class="language-rust"><span class="token keyword">use</span> <span class="token namespace">thiserror<span class="token punctuation">::</span></span><span class="token class-name">Error</span><span class="token punctuation">;</span>

<span class="token attribute attr-name">#[derive(Error, Debug)]</span>
<span class="token attribute attr-name">#[non_exhaustive]</span>
<span class="token keyword">pub</span> <span class="token keyword">enum</span> <span class="token type-definition class-name">MyError</span> <span class="token punctuation">{</span>
    <span class="token attribute attr-name">#[error(<span class="token string">"IO error: {0}"</span>)]</span>
    <span class="token class-name">IoError</span><span class="token punctuation">(</span><span class="token attribute attr-name">#[from]</span> <span class="token namespace">std<span class="token punctuation">::</span>io<span class="token punctuation">::</span></span><span class="token class-name">Error</span><span class="token punctuation">)</span><span class="token punctuation">,</span>

    <span class="token attribute attr-name">#[error(<span class="token string">"Parse error: {0}"</span>)]</span>
    <span class="token class-name">ParseError</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">)</span><span class="token punctuation">,</span>

    <span class="token attribute attr-name">#[error(<span class="token string">"Validation failed for field '{field}': {reason}"</span>)]</span>
    <span class="token class-name">ValidationError</span> <span class="token punctuation">{</span> field<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token punctuation">,</span> reason<span class="token punctuation">:</span> <span class="token class-name">String</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
</code></pre>
<p><strong>Why?</strong> The <code>Error</code> trait enables compatibility with <code>?</code> operator and error handling libraries. <code>thiserror</code> reduces boilerplate significantly.</p>
<hr>
<h2>Additional Tips</h2>
<h3>Use <code>Result</code> Type Aliases</h3>
<p>Create type aliases using <a href="https://doc.rust-lang.org/std/result/"><code>Result</code></a> for cleaner and more consistent function signatures:</p>
<pre class="language-rust"><code class="language-rust"><span class="token keyword">pub</span> <span class="token keyword">type</span> <span class="token type-definition class-name">Result</span><span class="token operator">&lt;</span><span class="token class-name">T</span><span class="token operator">&gt;</span> <span class="token operator">=</span> <span class="token namespace">std<span class="token punctuation">::</span>result<span class="token punctuation">::</span></span><span class="token class-name">Result</span><span class="token operator">&lt;</span><span class="token class-name">T</span><span class="token punctuation">,</span> <span class="token class-name">UserServiceError</span><span class="token operator">&gt;</span><span class="token punctuation">;</span>

<span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function-definition function">get_user</span><span class="token punctuation">(</span>id<span class="token punctuation">:</span> <span class="token keyword">u64</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token class-name">Result</span><span class="token operator">&lt;</span><span class="token class-name">User</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
    <span class="token comment">// ...</span>
<span class="token punctuation">}</span>
</code></pre>
<p><strong>Why?</strong> This reduces repetition and makes refactoring easier if you need to change the error type.</p>
<h3>Implement <code>From</code> Trait for Error Conversion</h3>
<p>The <a href="https://doc.rust-lang.org/std/convert/trait.From.html"><code>From</code></a> trait helps with automatic error conversion:</p>
<pre class="language-rust"><code class="language-rust"><span class="token comment">// Manual implementation</span>
<span class="token keyword">impl</span> <span class="token class-name">From</span><span class="token operator">&lt;</span><span class="token namespace">std<span class="token punctuation">::</span>io<span class="token punctuation">::</span></span><span class="token class-name">Error</span><span class="token operator">&gt;</span> <span class="token keyword">for</span> <span class="token class-name">MyError</span> <span class="token punctuation">{</span>
    <span class="token keyword">fn</span> <span class="token function-definition function">from</span><span class="token punctuation">(</span>error<span class="token punctuation">:</span> <span class="token namespace">std<span class="token punctuation">::</span>io<span class="token punctuation">::</span></span><span class="token class-name">Error</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token keyword">Self</span> <span class="token punctuation">{</span>
        <span class="token class-name">MyError</span><span class="token punctuation">::</span><span class="token class-name">Io</span><span class="token punctuation">(</span>error<span class="token punctuation">)</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token keyword">impl</span> <span class="token class-name">From</span><span class="token operator">&lt;</span><span class="token namespace">serde_json<span class="token punctuation">::</span></span><span class="token class-name">Error</span><span class="token operator">&gt;</span> <span class="token keyword">for</span> <span class="token class-name">MyError</span> <span class="token punctuation">{</span>
    <span class="token keyword">fn</span> <span class="token function-definition function">from</span><span class="token punctuation">(</span>error<span class="token punctuation">:</span> <span class="token namespace">serde_json<span class="token punctuation">::</span></span><span class="token class-name">Error</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token keyword">Self</span> <span class="token punctuation">{</span>
        <span class="token class-name">MyError</span><span class="token punctuation">::</span><span class="token class-name">Parse</span><span class="token punctuation">(</span>error<span class="token punctuation">.</span><span class="token function">to_string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token comment">// Or use thiserror's #[from] attribute</span>
<span class="token attribute attr-name">#[derive(Error, Debug)]</span>
<span class="token keyword">pub</span> <span class="token keyword">enum</span> <span class="token type-definition class-name">MyError</span> <span class="token punctuation">{</span>
    <span class="token attribute attr-name">#[error(<span class="token string">"IO error: {0}"</span>)]</span>
    <span class="token class-name">Io</span><span class="token punctuation">(</span><span class="token attribute attr-name">#[from]</span> <span class="token namespace">std<span class="token punctuation">::</span>io<span class="token punctuation">::</span></span><span class="token class-name">Error</span><span class="token punctuation">)</span><span class="token punctuation">,</span>

    <span class="token attribute attr-name">#[error(<span class="token string">"Parse error: {0}"</span>)]</span>
    <span class="token class-name">Parse</span><span class="token punctuation">(</span><span class="token attribute attr-name">#[from]</span> <span class="token namespace">serde_json<span class="token punctuation">::</span></span><span class="token class-name">Error</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>

<span class="token comment">// Now you can use ? operator with automatic conversion</span>
<span class="token keyword">fn</span> <span class="token function-definition function">read_and_parse</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token class-name">Result</span><span class="token operator">&lt;</span><span class="token class-name">Config</span><span class="token punctuation">,</span> <span class="token class-name">MyError</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">let</span> content <span class="token operator">=</span> <span class="token namespace">std<span class="token punctuation">::</span>fs<span class="token punctuation">::</span></span><span class="token function">read_to_string</span><span class="token punctuation">(</span><span class="token string">"config.json"</span><span class="token punctuation">)</span><span class="token operator">?</span><span class="token punctuation">;</span> <span class="token comment">// auto-converts io::Error</span>
    <span class="token keyword">let</span> config <span class="token operator">=</span> <span class="token namespace">serde_json<span class="token punctuation">::</span></span><span class="token function">from_str</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>content<span class="token punctuation">)</span><span class="token operator">?</span><span class="token punctuation">;</span> <span class="token comment">// auto-converts serde_json::Error</span>
    <span class="token class-name">Ok</span><span class="token punctuation">(</span>config<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre>
<p><strong>Why?</strong> Automatic conversion eliminates manual <code>map_err()</code> calls and makes error propagation seamless.</p>
<h3>Add Context with Error Chaining</h3>
<pre class="language-rust"><code class="language-rust"><span class="token keyword">fn</span> <span class="token function-definition function">load_config</span><span class="token punctuation">(</span>path<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token keyword">str</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token class-name">Result</span><span class="token operator">&lt;</span><span class="token class-name">Config</span><span class="token punctuation">,</span> <span class="token class-name">ConfigError</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">let</span> content <span class="token operator">=</span> <span class="token namespace">std<span class="token punctuation">::</span>fs<span class="token punctuation">::</span></span><span class="token function">read_to_string</span><span class="token punctuation">(</span>path<span class="token punctuation">)</span>
        <span class="token punctuation">.</span><span class="token function">map_err</span><span class="token punctuation">(</span><span class="token closure-params"><span class="token closure-punctuation punctuation">|</span>source<span class="token closure-punctuation punctuation">|</span></span> <span class="token class-name">ConfigError</span><span class="token punctuation">::</span><span class="token class-name">ReadFailed</span> <span class="token punctuation">{</span>
            path<span class="token punctuation">:</span> path<span class="token punctuation">.</span><span class="token function">to_string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
            source<span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">?</span><span class="token punctuation">;</span>

    <span class="token keyword">let</span> config <span class="token operator">=</span> <span class="token namespace">serde_json<span class="token punctuation">::</span></span><span class="token function">from_str</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>content<span class="token punctuation">)</span>
        <span class="token punctuation">.</span><span class="token function">map_err</span><span class="token punctuation">(</span><span class="token closure-params"><span class="token closure-punctuation punctuation">|</span>source<span class="token closure-punctuation punctuation">|</span></span> <span class="token class-name">ConfigError</span><span class="token punctuation">::</span><span class="token class-name">ParseFailed</span> <span class="token punctuation">{</span>
            path<span class="token punctuation">:</span> path<span class="token punctuation">.</span><span class="token function">to_string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
            source<span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">?</span><span class="token punctuation">;</span>

    <span class="token class-name">Ok</span><span class="token punctuation">(</span>config<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre>
<p><strong>Why?</strong> Context-rich errors make debugging significantly easier by preserving the error chain.</p>
<h3>Consider Error Codes for APIs</h3>
<pre class="language-rust"><code class="language-rust"><span class="token attribute attr-name">#[derive(Error, Debug)]</span>
<span class="token attribute attr-name">#[non_exhaustive]</span>
<span class="token keyword">pub</span> <span class="token keyword">enum</span> <span class="token type-definition class-name">ApiError</span> <span class="token punctuation">{</span>
    <span class="token attribute attr-name">#[error(<span class="token string">"[AUTH001] Unauthorized: {0}"</span>)]</span>
    <span class="token class-name">Unauthorized</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">)</span><span class="token punctuation">,</span>

    <span class="token attribute attr-name">#[error(<span class="token string">"[RES404] Resource not found: {resource_type} with id {id}"</span>)]</span>
    <span class="token class-name">NotFound</span> <span class="token punctuation">{</span> resource_type<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token punctuation">,</span> id<span class="token punctuation">:</span> <span class="token class-name">String</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>

<span class="token keyword">impl</span> <span class="token class-name">ApiError</span> <span class="token punctuation">{</span>
    <span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function-definition function">error_code</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">self</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token operator">&amp;</span><span class="token keyword">str</span> <span class="token punctuation">{</span>
        <span class="token keyword">match</span> <span class="token keyword">self</span> <span class="token punctuation">{</span>
            <span class="token class-name">ApiError</span><span class="token punctuation">::</span><span class="token class-name">Unauthorized</span><span class="token punctuation">(</span>_<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token string">"AUTH001"</span><span class="token punctuation">,</span>
            <span class="token class-name">ApiError</span><span class="token punctuation">::</span><span class="token class-name">NotFound</span> <span class="token punctuation">{</span> <span class="token punctuation">..</span> <span class="token punctuation">}</span> <span class="token operator">=&gt;</span> <span class="token string">"RES404"</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p><strong>Why?</strong> Error codes enable clients to handle errors programmatically and support internationalization.</p>
<h3>Document Error Conditions</h3>
<pre class="language-rust"><code class="language-rust"><span class="token comment">/// Fetches a user by their ID from the database.</span>
<span class="token comment">///</span>
<span class="token comment">/// # Errors</span>
<span class="token comment">///</span>
<span class="token comment">/// This function will return an error if:</span>
<span class="token comment">/// - [`UserServiceError::Database`] - Database connection or query fails</span>
<span class="token comment">/// - [`UserServiceError::UserNotFound`] - No user exists with the given ID</span>
<span class="token comment">/// - [`UserServiceError::PermissionDenied`] - Caller lacks read permissions</span>
<span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function-definition function">get_user</span><span class="token punctuation">(</span>id<span class="token punctuation">:</span> <span class="token keyword">u64</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token class-name">Result</span><span class="token operator">&lt;</span><span class="token class-name">User</span><span class="token punctuation">,</span> <span class="token class-name">UserServiceError</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
    <span class="token comment">// ...</span>
<span class="token punctuation">}</span>
</code></pre>
<p><strong>Why?</strong> Documentation helps users understand and handle errors correctly without reading the source code.</p>
<h3>Use <code>#[must_use]</code> for Result Types</h3>
<p>When necessary use <a href="https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute"><code>#[must_use]</code></a> to enforce handling of results:</p>
<pre class="language-rust"><code class="language-rust"><span class="token attribute attr-name">#[must_use = <span class="token string">"this function returns a Result that should be handled"</span>]</span>
<span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function-definition function">save_user</span><span class="token punctuation">(</span>user<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token class-name">User</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token class-name">Result</span><span class="token operator">&lt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
    <span class="token comment">// ...</span>
<span class="token punctuation">}</span>
</code></pre>
<p><strong>Why?</strong> This prevents accidentally ignoring errors, which is a common source of bugs.</p>
<h3>Create Helper Methods for Common Patterns</h3>
<pre class="language-rust"><code class="language-rust"><span class="token keyword">use</span> <span class="token namespace">thiserror<span class="token punctuation">::</span></span><span class="token class-name">Error</span><span class="token punctuation">;</span>

<span class="token attribute attr-name">#[derive(Error, Debug)]</span>
<span class="token attribute attr-name">#[non_exhaustive]</span>
<span class="token keyword">pub</span> <span class="token keyword">enum</span> <span class="token type-definition class-name">ValidationError</span> <span class="token punctuation">{</span>
    <span class="token attribute attr-name">#[error(<span class="token string">"Field '{field}' is required"</span>)]</span>
    <span class="token class-name">Required</span> <span class="token punctuation">{</span> field<span class="token punctuation">:</span> <span class="token class-name">String</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>

    <span class="token attribute attr-name">#[error(<span class="token string">"Field '{field}' has invalid format: {reason}"</span>)]</span>
    <span class="token class-name">InvalidFormat</span> <span class="token punctuation">{</span> field<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token punctuation">,</span> reason<span class="token punctuation">:</span> <span class="token class-name">String</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>

<span class="token comment">// Helper methods</span>
<span class="token keyword">impl</span> <span class="token class-name">ValidationError</span> <span class="token punctuation">{</span>
    <span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function-definition function">required</span><span class="token punctuation">(</span>field<span class="token punctuation">:</span> <span class="token keyword">impl</span> <span class="token class-name">Into</span><span class="token operator">&lt;</span><span class="token class-name">String</span><span class="token operator">&gt;</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token keyword">Self</span> <span class="token punctuation">{</span>
        <span class="token keyword">Self</span><span class="token punctuation">::</span><span class="token class-name">Required</span> <span class="token punctuation">{</span> field<span class="token punctuation">:</span> field<span class="token punctuation">.</span><span class="token function">into</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function-definition function">invalid_format</span><span class="token punctuation">(</span>field<span class="token punctuation">:</span> <span class="token keyword">impl</span> <span class="token class-name">Into</span><span class="token operator">&lt;</span><span class="token class-name">String</span><span class="token operator">&gt;</span><span class="token punctuation">,</span> reason<span class="token punctuation">:</span> <span class="token keyword">impl</span> <span class="token class-name">Into</span><span class="token operator">&lt;</span><span class="token class-name">String</span><span class="token operator">&gt;</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token keyword">Self</span> <span class="token punctuation">{</span>
        <span class="token keyword">Self</span><span class="token punctuation">::</span><span class="token class-name">InvalidFormat</span> <span class="token punctuation">{</span>
            field<span class="token punctuation">:</span> field<span class="token punctuation">.</span><span class="token function">into</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
            reason<span class="token punctuation">:</span> reason<span class="token punctuation">.</span><span class="token function">into</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token comment">// Usage</span>
<span class="token keyword">fn</span> <span class="token function-definition function">validate_email</span><span class="token punctuation">(</span>email<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token keyword">str</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token class-name">Result</span><span class="token operator">&lt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token class-name">ValidationError</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> email<span class="token punctuation">.</span><span class="token function">is_empty</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> <span class="token class-name">Err</span><span class="token punctuation">(</span><span class="token class-name">ValidationError</span><span class="token punctuation">::</span><span class="token function">required</span><span class="token punctuation">(</span><span class="token string">"email"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">if</span> <span class="token operator">!</span>email<span class="token punctuation">.</span><span class="token function">contains</span><span class="token punctuation">(</span><span class="token char">'@'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> <span class="token class-name">Err</span><span class="token punctuation">(</span><span class="token class-name">ValidationError</span><span class="token punctuation">::</span><span class="token function">invalid_format</span><span class="token punctuation">(</span><span class="token string">"email"</span><span class="token punctuation">,</span> <span class="token string">"missing @ symbol"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token class-name">Ok</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre>
<p><strong>Why?</strong> Helper methods reduce boilerplate and ensure consistent error construction.</p>
<h3>Separate Recoverable from Unrecoverable Errors</h3>
<p>Use <code>Result</code> for recoverable errors and <a href="https://doc.rust-lang.org/std/macro.panic.html"><code>panic!</code></a> for unrecoverable ones:</p>
<pre class="language-rust"><code class="language-rust"><span class="token comment">// Recoverable: User might fix the input</span>
<span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function-definition function">parse_age</span><span class="token punctuation">(</span>input<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token keyword">str</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token class-name">Result</span><span class="token operator">&lt;</span><span class="token keyword">u32</span><span class="token punctuation">,</span> <span class="token class-name">ParseError</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
    input<span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">map_err</span><span class="token punctuation">(</span><span class="token closure-params"><span class="token closure-punctuation punctuation">|</span>_<span class="token closure-punctuation punctuation">|</span></span> <span class="token class-name">ParseError</span><span class="token punctuation">::</span><span class="token class-name">InvalidAge</span><span class="token punctuation">(</span>input<span class="token punctuation">.</span><span class="token function">to_string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>

<span class="token comment">// Unrecoverable: Programming error</span>
<span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function-definition function">get_config_value</span><span class="token punctuation">(</span>key<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token keyword">str</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token class-name">String</span> <span class="token punctuation">{</span>
    <span class="token constant">CONFIG</span><span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>key<span class="token punctuation">)</span>
        <span class="token punctuation">.</span><span class="token function">unwrap_or_else</span><span class="token punctuation">(</span><span class="token closure-params"><span class="token closure-punctuation punctuation">|</span><span class="token closure-punctuation punctuation">|</span></span> <span class="token macro property">panic!</span><span class="token punctuation">(</span><span class="token string">"Config key '{}' must be set"</span><span class="token punctuation">,</span> key<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre>
<p><strong>Why?</strong> This distinction clarifies error handling strategies and improves code readability.</p>
<hr>
<h2>Additional Libraries and Tools</h2>
<h3>Use <code>anyhow</code> for Application-Level Error Handling</h3>
<p>For applications (not libraries), consider using <a href="https://crates.io/crates/anyhow"><code>anyhow</code></a>:</p>
<pre class="language-rust"><code class="language-rust"><span class="token keyword">use</span> <span class="token namespace">anyhow<span class="token punctuation">::</span></span><span class="token punctuation">{</span><span class="token class-name">Context</span><span class="token punctuation">,</span> <span class="token class-name">Result</span><span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token keyword">fn</span> <span class="token function-definition function">load_config</span><span class="token punctuation">(</span>path<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token keyword">str</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token class-name">Result</span><span class="token operator">&lt;</span><span class="token class-name">Config</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">let</span> content <span class="token operator">=</span> <span class="token namespace">std<span class="token punctuation">::</span>fs<span class="token punctuation">::</span></span><span class="token function">read_to_string</span><span class="token punctuation">(</span>path<span class="token punctuation">)</span>
        <span class="token punctuation">.</span><span class="token function">context</span><span class="token punctuation">(</span><span class="token macro property">format!</span><span class="token punctuation">(</span><span class="token string">"Failed to read config from '{}'"</span><span class="token punctuation">,</span> path<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token operator">?</span><span class="token punctuation">;</span>

    <span class="token keyword">let</span> config<span class="token punctuation">:</span> <span class="token class-name">Config</span> <span class="token operator">=</span> <span class="token namespace">serde_json<span class="token punctuation">::</span></span><span class="token function">from_str</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>content<span class="token punctuation">)</span>
        <span class="token punctuation">.</span><span class="token function">context</span><span class="token punctuation">(</span><span class="token macro property">format!</span><span class="token punctuation">(</span><span class="token string">"Failed to parse config from '{}'"</span><span class="token punctuation">,</span> path<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token operator">?</span><span class="token punctuation">;</span>

    <span class="token class-name">Ok</span><span class="token punctuation">(</span>config<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre>
<p><strong>Why?</strong> <code>anyhow</code> simplifies error handling by providing a generic error type that can wrap any error, along with context.</p>
<h3>Enhanced Error Reporting with <code>miette</code></h3>
<p>For applications that need rich diagnostic error reporting try <a href="https://crates.io/crates/miette"><code>miette</code></a>:</p>
<pre class="language-rust"><code class="language-rust"><span class="token keyword">use</span> <span class="token namespace">miette<span class="token punctuation">::</span></span><span class="token punctuation">{</span><span class="token class-name">Diagnostic</span><span class="token punctuation">,</span> <span class="token class-name">Result</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token namespace">thiserror<span class="token punctuation">::</span></span><span class="token class-name">Error</span><span class="token punctuation">;</span>

<span class="token attribute attr-name">#[derive(Error, Debug, Diagnostic)]</span>
<span class="token attribute attr-name">#[error(<span class="token string">"Configuration validation failed"</span>)]</span>
<span class="token attribute attr-name">#[diagnostic(
    code(config::validation_failed),
    help(<span class="token string">"Check your configuration file syntax and required fields"</span>)
)]</span>
<span class="token keyword">pub</span> <span class="token keyword">struct</span> <span class="token type-definition class-name">ConfigValidationError</span> <span class="token punctuation">{</span>
    <span class="token attribute attr-name">#[source_code]</span>
    src<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token punctuation">,</span>

    <span class="token attribute attr-name">#[label(<span class="token string">"This field is invalid"</span>)]</span>
    invalid_field<span class="token punctuation">:</span> <span class="token namespace">miette<span class="token punctuation">::</span></span><span class="token class-name">SourceSpan</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>

<span class="token keyword">fn</span> <span class="token function-definition function">validate_config</span><span class="token punctuation">(</span>config_content<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token keyword">str</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token class-name">Result</span><span class="token operator">&lt;</span><span class="token class-name">Config</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
    <span class="token comment">// ... validation logic</span>
    <span class="token class-name">Err</span><span class="token punctuation">(</span><span class="token class-name">ConfigValidationError</span> <span class="token punctuation">{</span>
        src<span class="token punctuation">:</span> config_content<span class="token punctuation">.</span><span class="token function">to_string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
        invalid_field<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token number">42</span><span class="token punctuation">,</span> <span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">into</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token comment">// byte offset and length</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">?</span>
<span class="token punctuation">}</span>
</code></pre>
<p><strong>Why?</strong> <code>miette</code> provides beautiful, IDE-like error reports with source code snippets, suggestions, and structured diagnostic information. Useful for CLI tools and developer-facing applications.</p>
<h3>Error Tracing Integration</h3>
<p>Integrate errors with structured logging using <a href="https://crates.io/crates/tracing-error"><code>tracing-error</code></a>:</p>
<pre class="language-rust"><code class="language-rust"><span class="token keyword">use</span> <span class="token namespace">tracing_error<span class="token punctuation">::</span></span><span class="token class-name">ErrorLayer</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token namespace">tracing_subscriber<span class="token punctuation">::</span></span><span class="token punctuation">{</span><span class="token namespace">layer<span class="token punctuation">::</span></span><span class="token class-name">SubscriberExt</span><span class="token punctuation">,</span> <span class="token namespace">util<span class="token punctuation">::</span></span><span class="token class-name">SubscriberInitExt</span><span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token keyword">fn</span> <span class="token function-definition function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token class-name">Result</span><span class="token operator">&lt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
    <span class="token namespace">tracing_subscriber<span class="token punctuation">::</span></span><span class="token function">registry</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
        <span class="token punctuation">.</span><span class="token function">with</span><span class="token punctuation">(</span><span class="token class-name">ErrorLayer</span><span class="token punctuation">::</span><span class="token function">default</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
        <span class="token punctuation">.</span><span class="token function">with</span><span class="token punctuation">(</span><span class="token namespace">tracing_subscriber<span class="token punctuation">::</span>fmt<span class="token punctuation">::</span></span><span class="token function">layer</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
        <span class="token punctuation">.</span><span class="token function">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token comment">// Your application code</span>
    <span class="token class-name">Ok</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>

<span class="token comment">// In your error handling code</span>
<span class="token keyword">match</span> <span class="token function">operation</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token class-name">Ok</span><span class="token punctuation">(</span>result<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> result<span class="token punctuation">,</span>
    <span class="token class-name">Err</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
        <span class="token namespace">tracing<span class="token punctuation">::</span></span><span class="token macro property">error!</span><span class="token punctuation">(</span>
            error <span class="token operator">=</span> <span class="token operator">?</span>e<span class="token punctuation">,</span>
            operation <span class="token operator">=</span> <span class="token string">"daily_backup"</span><span class="token punctuation">,</span>
            <span class="token string">"Operation failed"</span>
        <span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> <span class="token class-name">Err</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span><span class="token function">into</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p><strong>Why?</strong> This allows capturing rich context about errors in logs, facilitating debugging and monitoring in production environments.</p>]]></content:encoded>
            <author>anton@azdanov.dev (Anton Ždanov)</author>
        </item>
        <item>
            <title><![CDATA[Automatically Restarting Your WiFi 5GHz Channel on Asus Merlin Routers]]></title>
            <link>https://www.azdanov.dev/articles/2025/asus-merlin-wifi-dfs-cron-restart</link>
            <guid isPermaLink="false">https://www.azdanov.dev/articles/2025/asus-merlin-wifi-dfs-cron-restart</guid>
            <pubDate>Tue, 04 Mar 2025 05:38:00 GMT</pubDate>
            <content:encoded><![CDATA[<p>Dynamic Frequency Selection (DFS) is a feature used in 5GHz WiFi networks to avoid interference with radar systems. However, this can cause your router to switch to a lower channel.</p>
<p>DFS channels are part of the 5GHz band and are shared with radar systems. When a radar signal is detected, the router must switch to a non-DFS channel to avoid interference. This can lead to a decrease in network performance, especially if the new channel is crowded. <sup><a href="#user-content-fn-1" id="user-content-fnref-1" data-footnote-ref="true" aria-describedby="footnote-label">1</a></sup> <sup><a href="#user-content-fn-2" id="user-content-fnref-2" data-footnote-ref="true" aria-describedby="footnote-label">2</a></sup></p>
<p>From personal experience, I've noticed that my Asus router sometimes switches to a non-DFS channel, but very rarely, since I don't live near an airport or a military base and I'm not entirely sure what triggers the switch.</p>
<h2>Setting Up Automatic Channel Checking</h2>
<p>To automate the process of checking and restarting the WiFi channel, you can use a script that periodically checks if the channel has changed and restarts the WiFi if necessary. Here's how you can set it up:</p>
<h3>Step 1: Create the <code>channel-ck.sh</code> Script</h3>
<p>First, SSH into your router and navigate to the <code>/jffs/scripts/</code> directory. Create a new script file named <code>channel-ck.sh</code>:</p>
<pre class="language-bash"><code class="language-bash">asus@RT-AX88U_Pro:/tmp/home/root<span class="token comment"># cd /jffs/scripts/</span>
asus@RT-AX88U_Pro:/jffs/scripts<span class="token comment"># vi channel-ck.sh</span>
</code></pre>
<p>Add the following content to the script:</p>
<pre class="language-bash"><code class="language-bash"><span class="token shebang important">#!/bin/sh</span>

logger -t <span class="token string">"channel_check"</span> <span class="token string">"Checking..."</span>

<span class="token assign-left variable">ifname</span><span class="token operator">=</span><span class="token string">"<span class="token variable"><span class="token variable">$(</span>nvram get wl1_ifname<span class="token variable">)</span></span>"</span>
<span class="token assign-left variable">targchanspec</span><span class="token operator">=</span><span class="token string">"<span class="token variable"><span class="token variable">$(</span>nvram get wl1_chanspec<span class="token variable">)</span></span>"</span>
<span class="token assign-left variable">targchan</span><span class="token operator">=</span><span class="token variable">${targchanspec<span class="token operator">%</span><span class="token operator">/</span>*}</span>
<span class="token assign-left variable">currchanspec</span><span class="token operator">=</span><span class="token string">"<span class="token variable"><span class="token variable">$(</span>wl -i $ifname chanspec <span class="token operator">|</span> <span class="token function">awk</span> <span class="token string">'{print $1}'</span><span class="token variable">)</span></span>"</span>
<span class="token assign-left variable">currchan</span><span class="token operator">=</span><span class="token variable">${currchanspec<span class="token operator">%</span><span class="token operator">/</span>*}</span>

<span class="token keyword">if</span> <span class="token punctuation">[</span> <span class="token string">"<span class="token variable">$targchan</span>"</span> <span class="token operator">!=</span> <span class="token string">"0"</span> <span class="token punctuation">]</span> <span class="token operator">&amp;&amp;</span> <span class="token punctuation">[</span> <span class="token string">"<span class="token variable">$currchan</span>"</span> <span class="token operator">!=</span> <span class="token string">"<span class="token variable">$targchan</span>"</span> <span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">then</span>
    logger -t <span class="token string">"channel_check"</span> <span class="token string">"Channel has changed from <span class="token variable">${targchan}</span> to <span class="token variable">${currchan}</span>. Restarting WiFi."</span>
    <span class="token function">service</span> restart_wireless
<span class="token keyword">fi</span>

logger -t <span class="token string">"channel_check"</span> <span class="token string">"Done."</span>
</code></pre>
<p>Make the script executable:</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">chmod</span> a+rx /jffs/scripts/channel-ck.sh
</code></pre>
<h3>Step 2: Schedule the Script with <code>cru</code></h3>
<p>You can use the <code>cru</code> command to schedule the script to run at specific intervals. This can be done by updating the <code>services-start</code> file or directly using the <code>cru</code> command.</p>
<p><strong>Option 1: Update <code>services-start</code> File</strong></p>
<p>Edit the <code>services-start</code> file in the <code>/jffs/scripts/</code> directory:</p>
<pre class="language-bash"><code class="language-bash">asus@RT-AX88U_Pro:/jffs/scripts<span class="token comment"># vi services-start</span>
</code></pre>
<p>Add the following lines to schedule the script:</p>
<pre class="language-bash"><code class="language-bash"><span class="token shebang important">#!/bin/sh</span>

<span class="token comment"># Workdays (Monday to Friday) at 20 minutes past every hour from 0-8 AM and 7-11 PM</span>
/usr/sbin/cru a channel_ck_weekdays <span class="token string">"20 0-8,19-23 * * 1-5 sh /jffs/scripts/channel-ck.sh"</span>

<span class="token comment"># Weekends (Saturday and Sunday) at 20 minutes past every hour</span>
/usr/sbin/cru a channel_ck_weekends <span class="token string">"20 * * * 6,0 sh /jffs/scripts/channel-ck.sh"</span>
</code></pre>
<p><strong>Option 2: Use <code>cru</code> Command Directly</strong></p>
<p>Alternatively, you can use the <code>cru</code> command directly in the terminal to set up the cron jobs:</p>
<pre class="language-bash"><code class="language-bash">/usr/sbin/cru a channel_ck_weekdays <span class="token string">"20 0-8,19-23 * * 1-5 sh /jffs/scripts/channel-ck.sh"</span>
/usr/sbin/cru a channel_ck_weekends <span class="token string">"20 * * * 6,0 sh /jffs/scripts/channel-ck.sh"</span>
</code></pre>
<h2>End</h2>
<p>By setting up this script and scheduling it with <code>cru</code>, you can ensure that your router automatically checks and restarts the WiFi 5GHz if it switches due to DFS. <sup><a href="#user-content-fn-3" id="user-content-fnref-3" data-footnote-ref="true" aria-describedby="footnote-label">3</a></sup> <sup><a href="#user-content-fn-4" id="user-content-fnref-4" data-footnote-ref="true" aria-describedby="footnote-label">4</a></sup></p>
<section data-footnotes="true" class="footnotes"><h2 class="sr-only" id="footnote-label">Footnotes</h2>
<ol>
<li id="user-content-fn-1">
<p><a href="https://www.asus.com/support/faq/1045936/#:~:text=DFS%20is,for%20radar.">[Wireless Router] What is DFS (Dynamic Frequency Selection)</a> <a href="#user-content-fnref-1" data-footnote-backref="" aria-label="Back to reference 1" class="data-footnote-backref">↩</a></p>
</li>
<li id="user-content-fn-2">
<p><a href="https://www.snbforums.com/threads/rt-ax86u-doesnt-switch-back-to-dfs-channel.77728/#:~:text=So%20I,detected%20radar.">RT-AX86U doesn't switch back to DFS channel - SNBForums</a> <a href="#user-content-fnref-2" data-footnote-backref="" aria-label="Back to reference 2" class="data-footnote-backref">↩</a></p>
</li>
<li id="user-content-fn-3">
<p><a href="https://github.com/RMerl/asuswrt-merlin.ng/wiki/User-scripts#:~:text=Full%20document,more%20information.">User scripts</a> <a href="#user-content-fnref-3" data-footnote-backref="" aria-label="Back to reference 3" class="data-footnote-backref">↩</a></p>
</li>
<li id="user-content-fn-4">
<p><a href="https://github.com/RMerl/asuswrt-merlin.ng/wiki/Scheduled-tasks-(cron-jobs)#:~:text=Full%20document,more%20information.">Scheduled tasks (cron jobs)</a> <a href="#user-content-fnref-4" data-footnote-backref="" aria-label="Back to reference 4" class="data-footnote-backref">↩</a></p>
</li>
</ol>
</section>]]></content:encoded>
            <author>anton@azdanov.dev (Anton Ždanov)</author>
        </item>
        <item>
            <title><![CDATA[How to Create a Virtual Display for Sunshine on Arch Linux]]></title>
            <link>https://www.azdanov.dev/articles/2025/how-to-create-a-virtual-display-for-sunshine-on-arch-linux</link>
            <guid isPermaLink="false">https://www.azdanov.dev/articles/2025/how-to-create-a-virtual-display-for-sunshine-on-arch-linux</guid>
            <pubDate>Fri, 24 Jan 2025 19:11:52 GMT</pubDate>
            <content:encoded><![CDATA[<p>If you're using Sunshine for remote game streaming and want to keep your monitor off while playing, creating a virtual display is a cost-effective alternative to using dummy HDMI or DP dongles. This guide will walk you through setting up a virtual display using an EDID file and enhancing your Sunshine setup with custom scripts.</p>
<p>See the original posts that inspired me to combine the found information:</p>
<ul>
<li><a href="https://www.reddit.com/r/linux_gaming/comments/199ylqz/streaming_with_sunshine_from_virtual_screens/">https://www.reddit.com/r/linux_gaming/comments/199ylqz/streaming_with_sunshine_from_virtual_screens/</a></li>
<li><a href="https://www.reddit.com/r/linuxmasterrace/comments/eraedc/after_an_evening_of_furious_googling_i_figured/">https://www.reddit.com/r/linuxmasterrace/comments/eraedc/after_an_evening_of_furious_googling_i_figured/</a></li>
<li><a href="https://www.reddit.com/r/pop_os/comments/soo7eh/how_to_permanently_load_custom_edid_from_boot_to/">https://www.reddit.com/r/pop_os/comments/soo7eh/how_to_permanently_load_custom_edid_from_boot_to/</a></li>
</ul>
<hr>
<h2>Why Use a Virtual Display?</h2>
<ul>
<li><strong>Cost-effective</strong>: No need to buy dummy plugs.</li>
<li><strong>Customizable resolutions</strong>: Stream in resolutions your physical monitor may not support.</li>
<li><strong>Convenience</strong>: Keep your monitor off while streaming.</li>
</ul>
<hr>
<h2>Step 1: Get an EDID File</h2>
<p>An EDID (Extended Display Identification Data) file simulates a monitor. You can download pre-made EDID files from the <a href="https://git.linuxtv.org/v4l-utils.git/tree/utils/edid-decode/data">v4l-utils repository</a>. Choose one that matches your desired resolution and features (e.g., 4K, HDR).</p>
<hr>
<h2>Step 2: Place the EDID File</h2>
<ol>
<li>Create a directory for EDID files:<!-- -->
<pre class="language-bash"><code class="language-bash"><span class="token function">sudo</span> <span class="token function">mkdir</span> -p /usr/lib/firmware/edid
</code></pre>
</li>
<li>Copy your chosen EDID file to this directory. For example:<!-- -->
<pre class="language-bash"><code class="language-bash"><span class="token function">sudo</span> <span class="token function">cp</span> samsung-q800t-hdmi2.1 /usr/lib/firmware/edid/
</code></pre>
</li>
</ol>
<hr>
<h2>Step 3: Configure Kernel Parameters</h2>
<ol>
<li>
<p>Identify your GPU's free HDMI or DP output:</p>
<pre class="language-bash"><code class="language-bash"><span class="token keyword">for</span> <span class="token for-or-select variable">p</span> <span class="token keyword">in</span> /sys/class/drm/*/status<span class="token punctuation">;</span> <span class="token keyword">do</span> <span class="token assign-left variable">con</span><span class="token operator">=</span><span class="token variable">${p<span class="token operator">%</span><span class="token operator">/</span>status}</span><span class="token punctuation">;</span> <span class="token builtin class-name">echo</span> -n <span class="token string">"<span class="token variable">${con<span class="token operator">#</span>*<span class="token operator">/</span>card?-}</span>: "</span><span class="token punctuation">;</span> <span class="token function">cat</span> <span class="token variable">$p</span><span class="token punctuation">;</span> <span class="token keyword">done</span>
</code></pre>
<p>Replace <code>HDMI-A-1</code> in the next step with the appropriate output.</p>
</li>
<li>
<p>Add the following kernel parameters (see <a href="https://wiki.archlinux.org/title/Kernel_parameters">arch wiki</a> or <a href="https://discovery.endeavouros.com/installation/systemd-boot/2022/12/">endeavour os discovery</a>):</p>
<pre class="language-bash"><code class="language-bash">drm.edid_firmware<span class="token operator">=</span>HDMI-A-1:edid/samsung-q800t-hdmi2.1 <span class="token assign-left variable">video</span><span class="token operator">=</span>HDMI-A-1:e
</code></pre>
</li>
<li>
<p>Update your <code>mkinitcpio.conf</code> file to include the EDID file:</p>
<pre class="language-bash"><code class="language-bash"><span class="token assign-left variable">FILES</span><span class="token operator">=</span><span class="token punctuation">(</span>/usr/lib/firmware/edid/samsung-q800t-hdmi2.1<span class="token punctuation">)</span>
</code></pre>
</li>
<li>
<p>Regenerate the initramfs:</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">sudo</span> mkinitcpio -P
</code></pre>
</li>
<li>
<p>Reboot your system.</p>
</li>
</ol>
<hr>
<h2>Step 4: Use Sunshine for Streaming</h2>
<p>After rebooting, Sunshine can use the virtual display for streaming. Ensure you configure Sunshine to capture the virtual display using KMS or wlroots capture.</p>
<hr>
<h2>Step 5: Automate with Custom Scripts</h2>
<p>You can enhance your setup by adding scripts to Sunshine. These scripts can improve your experience with sunshine by automating the resolution set up and toggling off and on of the main monitor display. Examples are available in <a href="https://gist.github.com/MrHighVoltage/78ca58218a569d253433fd4be883c6c3">this GitHub Gist</a>.</p>
<h3>Example Script Workflow:</h3>
<ul>
<li><strong>On Connect</strong>: Disable physical monitors and enable the virtual display.</li>
<li><strong>On Disconnect</strong>: Re-enable physical monitors and disable the virtual display.</li>
</ul>
<hr>
<h2>Conclusion</h2>
<p>By following these steps, you can create a virtual display for Sunshine on Arch Linux without spending extra money on dummy plugs. This setup is flexible, allowing you to stream in higher resolutions or HDR, and can be further automated with custom scripts for a seamless experience. For bonus points you can install and use wxedid to modify the edid file and adjust the display parameters such as hz or resolutions, but that is outside the scope of this article.</p>]]></content:encoded>
            <author>anton@azdanov.dev (Anton Ždanov)</author>
        </item>
        <item>
            <title><![CDATA[Solving VRR Issue on Linux with KDE and AMD GPU]]></title>
            <link>https://www.azdanov.dev/articles/2025/solving-vrr-issues-on-linux-with-kde-and-amd-gpu</link>
            <guid isPermaLink="false">https://www.azdanov.dev/articles/2025/solving-vrr-issues-on-linux-with-kde-and-amd-gpu</guid>
            <pubDate>Thu, 23 Jan 2025 19:00:01 GMT</pubDate>
            <content:encoded><![CDATA[<p>Recently, I ran into an issue with enabling Variable Refresh Rate (VRR) on my Linux setup. My monitor, a Dell U2724DE, is supposed to support VRR, but the option for Adaptive Sync simply wasn’t available in the KDE Plasma 6 settings. After a lot of troubleshooting, I finally resolved it, and I’m sharing my experience here to help others who might face the same problem.</p>
<h2>My Setup</h2>
<table><thead><tr><th>Component</th><th>Details</th></tr></thead><tbody><tr><td><strong>OS</strong></td><td>Endeavour OS (Arch Linux)</td></tr><tr><td><strong>Desktop</strong></td><td>KDE Plasma 6 (Wayland)</td></tr><tr><td><strong>GPU</strong></td><td>AMD Radeon 7900 XTX</td></tr><tr><td><strong>Monitor</strong></td><td>Dell U2724DE</td></tr><tr><td><strong>Kernel</strong></td><td>Linux 6.12.10-arch1-1</td></tr></tbody></table>
<h2>The Problem</h2>
<p>Despite my monitor advertising VRR support, the option to enable it in KDE was missing. I tried several things, including:</p>
<ul>
<li>
<p>Verifying VRR support in the monitor's EDID file.</p>
<pre class="language-bash"><code class="language-bash"><span class="token comment"># 1. Install the read-edid package</span>
<span class="token function">sudo</span> pacman -S read-edid
<span class="token comment"># 2. Use get-edid and parse-edid to read and decode the monitor's EDID</span>
<span class="token function">sudo</span> get-edid <span class="token operator">|</span> parse-edid
</code></pre>
</li>
<li>
<p>Updating drivers and ensuring my system was fully up-to-date.</p>
</li>
<li>
<p>Tweaking various settings in KDE and the AMD GPU configuration. And even trying the <a href="https://www.cablematters.com/pc-1398-154-cable-matters-8k-displayport-14-to-hdmi-cable-6ft-18m-with-4k-120hz-8k-60hz-unidirectional-324gbps-display-port-14-to-hdmi-8k-cable-in-black-for-rtx-40804090-rx-78007900-and-more-upc818707024515.aspx">CableMatters DisplayPort to HDMI Adapter</a> to no avail.</p>
</li>
</ul>
<p>The EDID file confirmed that my monitor does support VRR (<code>VertRefresh 48-120</code>), but nothing I tried worked. And the <code>kscreen-doctor --outputs</code> command was showing <code>Vrr: incapable</code> output.</p>
<h2>The Solution: Disabling MST</h2>
<p>After much trial and error, I discovered the culprit: <strong>MST (Multi-Stream Transport)</strong>. My monitor had MST enabled by default, which is typically used for <a href="https://www.cablematters.com/Blog/DisplayPort/what-is-multi-stream-transport">daisy-chaining multiple displays</a>, which I wasn't using. Disabling MST in the monitor’s settings immediately resolved the issue, and the VRR option became available in KDE.</p>
<h3>Steps to Disable MST</h3>
<ol>
<li>Open your monitor’s on-screen display (OSD) menu.</li>
<li>Navigate to the settings related to MST or DisplayPort configuration.</li>
<li>Disable MST (it might be labeled as "Dualport" or "Multi-Stream Transport").</li>
<li>Save the changes and restart your system (just to be sure).</li>
</ol>
<h2>Possible Cause</h2>
<p>This issue might be related to a bug in the AMD Radeon drivers or how MST interacts with VRR on Linux. MST can sometimes interfere with certain features, and it seems VRR is one of them in this case.</p>
<h2>Final Thoughts</h2>
<p>If you’re struggling to enable VRR on Linux and have a similar setup, check your monitor’s MST setting. Disabling it worked for me, and I hope it helps you too. While the root cause might be driver-related, I’m just happy to have VRR working now.</p>
<p>If you’ve encountered similar issues or have additional insights, feel free to <a href="mailto:anton@azdanov.dev">share them with me</a>!</p>]]></content:encoded>
            <author>anton@azdanov.dev (Anton Ždanov)</author>
        </item>
        <item>
            <title><![CDATA[My CKAD Journey: Getting Certified in Kubernetes]]></title>
            <link>https://www.azdanov.dev/articles/2024/my-ckad-journey-getting-certified-in-kubernetes</link>
            <guid isPermaLink="false">https://www.azdanov.dev/articles/2024/my-ckad-journey-getting-certified-in-kubernetes</guid>
            <pubDate>Fri, 18 Oct 2024 02:30:29 GMT</pubDate>
            <content:encoded><![CDATA[<h2>What is CKAD?</h2>
<p>The CKAD is a certificate from the Cloud Native Computing Foundation (CNCF). It checks if you can design, build, and manage applications for Kubernetes, which is a tool for running apps in a cloud environment. What's cool about this exam is it's all about doing, not just answering questions. You have to show you can actually work with Kubernetes.</p>
<aside style="margin-bottom:0" class="inline-flex flex-col items-center"><img alt="CKAD: Certified Kubernetes Application Developer" loading="lazy" width="1237" height="958" decoding="async" data-nimg="1" style="color:transparent" srcset="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fckad.113yu-35.ybto.png&amp;w=1920&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fckad.113yu-35.ybto.png&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fckad.113yu-35.ybto.png&amp;w=3840&amp;q=75"><p><a href="https://www.credly.com/badges/991bf428-28a3-42ee-b3bf-c6857b8e0392">CKAD: Certified Kubernetes Application
Developer</a></p></aside>
<h2>The Exam</h2>
<ul>
<li>Time: The exam lasts 2 hours.</li>
<li>You'll work on tasks like:<!-- -->
<ul>
<li>Building container images</li>
<li>Deploying apps</li>
<li>Keeping an eye on apps and fixing them if needed</li>
<li>Setting up the environment</li>
<li>Managing services and networks</li>
</ul>
</li>
</ul>
<p>I really liked that the exam is practical. Instead of choosing from answers, you work on tasks like you would at work. It's challenging because you're under time pressure.</p>
<h2>How I Prepared</h2>
<p>Here are some things that helped me get ready:</p>
<ul>
<li>GitHub: There are lots of free study materials and practice tasks from other developers on GitHub.<!-- -->
<ul>
<li><a href="https://github.com/dgkanatsios/CKAD-exercises">https://github.com/dgkanatsios/CKAD-exercises</a></li>
<li><a href="https://github.com/bmuschko/ckad-crash-course">https://github.com/bmuschko/ckad-crash-course</a></li>
</ul>
</li>
<li>Courses: I took some courses on Udemy that went through everything I needed to know. They had practice exercises too.<!-- -->
<ul>
<li><a href="https://www.udemy.com/course/certified-kubernetes-application-developer/">https://www.udemy.com/course/certified-kubernetes-application-developer/</a></li>
<li><a href="https://www.udemy.com/course/kubernetes-microservices/">https://www.udemy.com/course/kubernetes-microservices/</a></li>
</ul>
</li>
<li>Practice: I set up Kubernetes on my computer using minikube and practiced. You need to be comfortable with <code>kubectl</code> and learn tricks on how to speed up your workflow to be able to do the exam in 2 hours.<!-- -->
<ul>
<li><a href="https://killer.sh">https://killer.sh</a> is a good resource for a practice exam, but it is much more difficult than the real one. Good way to see how well you're doing under time pressure.</li>
</ul>
</li>
</ul>
<p>I might have prepared more than I needed to, but it was worth it. I learned a lot about Kubernetes, which will definitely help me in the future.</p>
<h2>What’s Next?</h2>
<p>I'd like to get CKA: Certified Kubernetes Administrator and CKS: Certified Kubernetes Security Specialist next. We'll see how it goes.</p>
<hr>
<p>If you have any further questions, feel free to reach out to me.</p>
<p>Thank you for reading.</p>]]></content:encoded>
            <author>anton@azdanov.dev (Anton Ždanov)</author>
        </item>
        <item>
            <title><![CDATA[How to Use Proton VPN WireGuard with NextDNS on Linux]]></title>
            <link>https://www.azdanov.dev/articles/2024/how-to-use-proton-vpn-wireguard-with-nextdns-on-linux</link>
            <guid isPermaLink="false">https://www.azdanov.dev/articles/2024/how-to-use-proton-vpn-wireguard-with-nextdns-on-linux</guid>
            <pubDate>Fri, 23 Aug 2024 14:21:20 GMT</pubDate>
            <content:encoded><![CDATA[<p>If you're using Linux and want to combine the security of Proton VPN with the advanced DNS features of NextDNS, here's a quick guide to set it up.</p>
<h2>Steps for updating the Proton VPN WireGuard configuration</h2>
<ol>
<li>Download your Proton VPN WireGuard config from the <a href="https://account.proton.me/u/0/vpn/WireGuard">Proton VPN WireGuard configuration</a>.</li>
<li>Get your NextDNS configuration ID and Endpoints from the <a href="https://my.nextdns.io">NextDNS dashboard</a>.</li>
<li>In the downloaded wireguard config remove the <code>DNS =</code> line from the <code>[Interface]</code> section.</li>
<li>Add a <code>PostUp</code> command to configure NextDNS using <code>resolvectl</code> and your NextDNS ID and Endpoints: <code>PostUp = resolvectl dns %i 172.16.80.142#ubuntu-1234a5.dns.nextdns.io 2001:db8:a0b:12f0::1#ubuntu-1234a5.dns.nextdns.io 172.16.83.142#ubuntu-1234a5.dns.nextdns.io 2001:db8:a0b:12f1::1#ubuntu-1234a5.dns.nextdns.io; resolvectl dnsovertls %i yes; resolvectl domain %i ~.</code></li>
<li>Save the modified config file.</li>
</ol>
<p>Here's how it might look:</p>
<pre class="language-text"><code class="language-text">[Interface]
# Key for GB#1
# Bouncing = 0
# NetShield = 0
# Moderate NAT = off
# NAT-PMP (Port Forwarding) = off
# VPN Accelerator = on
PrivateKey = &lt;PrivateKey&gt;
Address = &lt;Address&gt;
PostUp = resolvectl dns %i 172.16.80.142#ubuntu-1234a5.dns.nextdns.io 2001:db8:a0b:12f0::1#ubuntu-1234a5.dns.nextdns.io 172.16.83.142#ubuntu-1234a5.dns.nextdns.io 2001:db8:a0b:12f1::1#ubuntu-1234a5.dns.nextdns.io; resolvectl dnsovertls %i yes; resolvectl domain %i ~.

[Peer]
# GB#1
PublicKey = &lt;PublicKey&gt;
AllowedIPs = 0.0.0.0/0
Endpoint = &lt;Address&gt;
</code></pre>
<p><strong>NB: I removed personal values and used random ones for IPv4, IPv6 and NextDNS ID. Make sure to use your own.</strong></p>
<p>This setup leverages <code>systemd-resolved</code>, which some Linux distributions use by default. The <code>PostUp</code> command configures NextDNS when the WireGuard connection is established.</p>
<p>Now you can enjoy the combined benefits of Proton VPN's security and NextDNS's advanced filtering and analytics!</p>
<h2>Managing WireGuard Configuration and Connection</h2>
<h3>Configuration File Location</h3>
<p>After modifying your WireGuard configuration file, you should place it in the appropriate directory:</p>
<ol>
<li>Save the configuration file with a .conf extension (e.g., <code>wg0.conf</code>).</li>
<li>Move the file to <code>/etc/wireguard/</code>. You may need root privileges for this:<!-- -->
<pre class="language-text"><code class="language-text">sudo mv wg0.conf /etc/wireguard/
</code></pre>
</li>
</ol>
<h3>WireGuard CLI Commands</h3>
<p>Here are some useful WireGuard CLI commands to manage your VPN connection:</p>
<ol>
<li>
<p>Start the WireGuard connection:</p>
<pre class="language-text"><code class="language-text">sudo wg-quick up wg0
</code></pre>
</li>
<li>
<p>Stop the WireGuard connection:</p>
<pre class="language-text"><code class="language-text">sudo wg-quick down wg0
</code></pre>
</li>
<li>
<p>Check the status of your WireGuard interfaces:</p>
<pre class="language-text"><code class="language-text">sudo wg show
</code></pre>
</li>
</ol>
<h3>Enabling/Disabling Autostart on System Boot</h3>
<p>To enable autostart of your WireGuard connection on system boot:</p>
<ol>
<li>
<p>Enable the WireGuard service:</p>
<pre class="language-text"><code class="language-text">sudo systemctl enable wg-quick@wg0.service
</code></pre>
</li>
<li>
<p>Start the service immediately:</p>
<pre class="language-text"><code class="language-text">sudo systemctl start wg-quick@wg0.service
</code></pre>
</li>
</ol>
<p>To disable autostart:</p>
<ol>
<li>
<p>Disable the WireGuard service:</p>
<pre class="language-text"><code class="language-text">sudo systemctl disable wg-quick@wg0.service
</code></pre>
</li>
<li>
<p>Stop the service if it's currently running:</p>
<pre class="language-text"><code class="language-text">sudo systemctl stop wg-quick@wg0.service
</code></pre>
</li>
</ol>
<p>Remember to replace wg0 in these commands with the actual name of your configuration file (without the .conf extension) if it's different.</p>
<p>And that's about it. You're all set up to use Proton VPN WireGuard with NextDNS on Linux.</p>
<p>You can use <a href="https://ip.me">https://ip.me</a> to verify that your IP address is now that of the Proton VPN server you're connected to.
And <a href="https://test.nextdns.io">https://test.nextdns.io</a> or <a href="https://ping.nextdns.io">https://ping.nextdns.io</a> to verify that your DNS queries are now going through NextDNS.</p>
<hr>
<p>If you have any further questions or need help with this setup, feel free to send me an email. I'm always happy to help!</p>]]></content:encoded>
            <author>anton@azdanov.dev (Anton Ždanov)</author>
        </item>
        <item>
            <title><![CDATA[Implementing a Fixed Width Pagination in a Spring Boot App with Thymeleaf]]></title>
            <link>https://www.azdanov.dev/articles/2024/implementing-pagination-in-a-spring-boot-app-with-thymeleaf</link>
            <guid isPermaLink="false">https://www.azdanov.dev/articles/2024/implementing-pagination-in-a-spring-boot-app-with-thymeleaf</guid>
            <pubDate>Fri, 16 Aug 2024 15:44:25 GMT</pubDate>
            <content:encoded><![CDATA[<p>I encountered this issue while working on a Spring Boot project that required pagination support for large datasets. I found the problem non-trivial and required a lot of research and bug-fixing to get it right. Here are the results of my work.</p>
<p>I found several solutions which implemented a varying width pagination, but I didn't like that the pagination panel was changing its size during use.</p>
<p>So, here is an implementation of a fixed width pagination in a Spring Boot project that uses Thymeleaf.</p>
<table><thead><tr><th>Pagination with an ellipsis</th><th>Pagination with an ellipsis on both sides</th></tr></thead><tbody><tr><td><a href="/_next/static/media/pagination.0zldgros-t.ir.png"><img alt="Pagination with an ellipsis" loading="lazy" width="2880" height="1144" decoding="async" data-nimg="1" style="color:transparent" srcset="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fpagination.0zldgros-t.ir.png&amp;w=3840&amp;q=75 1x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fpagination.0zldgros-t.ir.png&amp;w=3840&amp;q=75"></a></td><td><a href="/_next/static/media/pagination-both.08r81jgdtginx.png"><img alt="Pagination on with ellipsis on both sides" loading="lazy" width="2880" height="1144" decoding="async" data-nimg="1" style="color:transparent" srcset="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fpagination-both.08r81jgdtginx.png&amp;w=3840&amp;q=75 1x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fpagination-both.08r81jgdtginx.png&amp;w=3840&amp;q=75"></a></td></tr></tbody></table>
<h2>Project</h2>
<p>You can find the project on <a href="https://github.com/azdanov/spring-pagination">https://github.com/azdanov/spring-pagination</a>.</p>
<p>These parts are covered in the current article:</p>
<pre class="language-plaintext"><code class="language-plaintext">src/main/java/dev/azdanov/pagination/user
├── UserController.java
├── UserService.java
├── UserRepository.java
src/main/resources/templates
├── users.html
├── fragments
│   └── pagination.html
src/main/java/dev/azdanov/pagination/util
├── PaginationUtils.java
├── PageItem.java
</code></pre>
<h2>UserController</h2>
<p>The <code>UserController</code> handles HTTP requests and interacts with the <code>UserService</code> to fetch paginated data. It uses <a href="https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/domain/Pageable.html">Pageable</a> to pass pagination information, such as page size and current page number, to the service for an offset based pagination. A <a href="https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/web/PagedModel.html">PagedModel</a> is returned to the view, because Page is not stable and can change its implementation between Spring versions.</p>
<pre class="language-java"><code class="language-java"><span class="token keyword">package</span> <span class="token namespace">dev<span class="token punctuation">.</span>azdanov<span class="token punctuation">.</span>pagination<span class="token punctuation">.</span>user</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token namespace">lombok<span class="token punctuation">.</span></span><span class="token class-name">RequiredArgsConstructor</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>data<span class="token punctuation">.</span>domain<span class="token punctuation">.</span></span><span class="token class-name">Pageable</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>data<span class="token punctuation">.</span>web<span class="token punctuation">.</span></span><span class="token class-name">PagedModel</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>stereotype<span class="token punctuation">.</span></span><span class="token class-name">Controller</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>ui<span class="token punctuation">.</span></span><span class="token class-name">Model</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>web<span class="token punctuation">.</span>bind<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">GetMapping</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>web<span class="token punctuation">.</span>bind<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">RequestMapping</span><span class="token punctuation">;</span>

<span class="token annotation punctuation">@Controller</span>
<span class="token annotation punctuation">@RequestMapping</span><span class="token punctuation">(</span><span class="token string">"/users"</span><span class="token punctuation">)</span>
<span class="token annotation punctuation">@RequiredArgsConstructor</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">UserController</span> <span class="token punctuation">{</span>

    <span class="token keyword">private</span> <span class="token keyword">final</span> <span class="token class-name">UserService</span> userService<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@GetMapping</span>
    <span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">listUsers</span><span class="token punctuation">(</span><span class="token class-name">Pageable</span> pageable<span class="token punctuation">,</span> <span class="token class-name">Model</span> model<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">PagedModel</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">UserDto</span><span class="token punctuation">&gt;</span></span> users <span class="token operator">=</span> userService<span class="token punctuation">.</span><span class="token function">getUsers</span><span class="token punctuation">(</span>pageable<span class="token punctuation">)</span><span class="token punctuation">;</span>

        model<span class="token punctuation">.</span><span class="token function">addAttribute</span><span class="token punctuation">(</span><span class="token string">"users"</span><span class="token punctuation">,</span> users<span class="token punctuation">)</span><span class="token punctuation">;</span>
        model<span class="token punctuation">.</span><span class="token function">addAttribute</span><span class="token punctuation">(</span><span class="token string">"pageable"</span><span class="token punctuation">,</span> pageable<span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">return</span> <span class="token string">"users"</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<h2>UserService</h2>
<p>The <code>UserService</code> fetches paginated user data from the repository and maps it to DTOs.</p>
<pre class="language-java"><code class="language-java"><span class="token keyword">package</span> <span class="token namespace">dev<span class="token punctuation">.</span>azdanov<span class="token punctuation">.</span>pagination<span class="token punctuation">.</span>user</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token namespace">lombok<span class="token punctuation">.</span></span><span class="token class-name">RequiredArgsConstructor</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>data<span class="token punctuation">.</span>domain<span class="token punctuation">.</span></span><span class="token class-name">Page</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>data<span class="token punctuation">.</span>domain<span class="token punctuation">.</span></span><span class="token class-name">Pageable</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>data<span class="token punctuation">.</span>web<span class="token punctuation">.</span></span><span class="token class-name">PagedModel</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>stereotype<span class="token punctuation">.</span></span><span class="token class-name">Service</span><span class="token punctuation">;</span>

<span class="token annotation punctuation">@Service</span>
<span class="token annotation punctuation">@RequiredArgsConstructor</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">UserService</span> <span class="token punctuation">{</span>

    <span class="token keyword">private</span> <span class="token keyword">final</span> <span class="token class-name">UserRepository</span> userRepository<span class="token punctuation">;</span>

    <span class="token keyword">public</span> <span class="token class-name">PagedModel</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">UserDto</span><span class="token punctuation">&gt;</span></span> <span class="token function">getUsers</span><span class="token punctuation">(</span><span class="token class-name">Pageable</span> pageable<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">Page</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">UserDto</span><span class="token punctuation">&gt;</span></span> users <span class="token operator">=</span> userRepository<span class="token punctuation">.</span><span class="token function">findAll</span><span class="token punctuation">(</span>pageable<span class="token punctuation">)</span>
            <span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>user <span class="token operator">-&gt;</span> <span class="token keyword">new</span> <span class="token class-name">UserDto</span><span class="token punctuation">(</span>user<span class="token punctuation">.</span><span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> user<span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> user<span class="token punctuation">.</span><span class="token function">getEmail</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">PagedModel</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span>users<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<h2>UserRepository</h2>
<p>The <code>UserRepository</code> extends <code>JpaRepository</code> to provide CRUD operations and pagination support.
Default methods like <code>findAll(Pageable pageable)</code> are used to fetch paginated data, so it's quite easy to implement pagination in Spring Data JPA.</p>
<pre class="language-java"><code class="language-java"><span class="token keyword">package</span> <span class="token namespace">dev<span class="token punctuation">.</span>azdanov<span class="token punctuation">.</span>pagination<span class="token punctuation">.</span>user</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>data<span class="token punctuation">.</span>jpa<span class="token punctuation">.</span>repository<span class="token punctuation">.</span></span><span class="token class-name">JpaRepository</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>stereotype<span class="token punctuation">.</span></span><span class="token class-name">Repository</span><span class="token punctuation">;</span>

<span class="token annotation punctuation">@Repository</span>
<span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">UserRepository</span> <span class="token keyword">extends</span> <span class="token class-name">JpaRepository</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">User</span><span class="token punctuation">,</span> <span class="token class-name">Long</span><span class="token punctuation">&gt;</span></span> <span class="token punctuation">{</span>
<span class="token punctuation">}</span>
</code></pre>
<h2>Thymeleaf Template</h2>
<p>The <code>users.html</code> template displays the list of users and includes the pagination controls.</p>
<p>As a side note, I use the <a href="https://ultraq.github.io/thymeleaf-layout-dialect/">Thymeleaf Layout Dialect</a> to create a layout structure with a main layout and separate pages. The <code>layout:decorate</code> attribute is used to apply the layout to the current template.</p>
<p>And Bootstrap 5.3 is used for styling.</p>
<pre class="language-html"><code class="language-html"><span class="token doctype"><span class="token punctuation">&lt;!</span><span class="token doctype-tag">DOCTYPE</span> <span class="token name">html</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>html</span>
  <span class="token attr-name"><span class="token namespace">xmlns:</span>th</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>http://www.thymeleaf.org<span class="token punctuation">"</span></span>
  <span class="token attr-name"><span class="token namespace">xmlns:</span>layout</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>http://www.ultraq.net.nz/thymeleaf/layout<span class="token punctuation">"</span></span>
  <span class="token attr-name"><span class="token namespace">layout:</span>decorate</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>~{layouts/main}<span class="token punctuation">"</span></span>
  <span class="token attr-name">lang</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>en<span class="token punctuation">"</span></span>
<span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>head</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>title</span><span class="token punctuation">&gt;</span></span>Users<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>title</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>head</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>body</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name"><span class="token namespace">layout:</span>fragment</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>content<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>mb-4<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Users<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>
        This table's pagination uses Spring Data JPA Pageable offset based
        pagination:
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span>
          <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://docs.spring.io/spring-data/jpa/reference/repositories/query-methods-details.html#repositories.special-parameters<span class="token punctuation">"</span></span>
          <span class="token punctuation">&gt;</span></span>Spring Data JPA - Paging, Iterating Large Results, Sorting &amp;
          Limiting<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span>
        <span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>table-responsive<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>table</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>table-striped table-hover table<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>thead</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>table-dark<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>tr</span><span class="token punctuation">&gt;</span></span>
              <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>th</span><span class="token punctuation">&gt;</span></span>ID<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>th</span><span class="token punctuation">&gt;</span></span>
              <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>th</span><span class="token punctuation">&gt;</span></span>Name<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>th</span><span class="token punctuation">&gt;</span></span>
              <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>th</span><span class="token punctuation">&gt;</span></span>Email<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>th</span><span class="token punctuation">&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>tr</span><span class="token punctuation">&gt;</span></span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>thead</span><span class="token punctuation">&gt;</span></span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>tbody</span><span class="token punctuation">&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>tr</span> <span class="token attr-name"><span class="token namespace">th:</span>each</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>user : ${users.content}<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
              <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>td</span> <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>${user.id}<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>td</span><span class="token punctuation">&gt;</span></span>
              <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>td</span> <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>${user.name}<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>td</span><span class="token punctuation">&gt;</span></span>
              <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>td</span> <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>${user.email}<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>td</span><span class="token punctuation">&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>tr</span><span class="token punctuation">&gt;</span></span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>tbody</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>table</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>

      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span>
        <span class="token attr-name"><span class="token namespace">th:</span>replace</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>~{fragments/pagination :: offset-pagination(${users}, ${pageable})}<span class="token punctuation">"</span></span>
      <span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>body</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>html</span><span class="token punctuation">&gt;</span></span>
</code></pre>
<h2>Pagination Fragment</h2>
<p>The <code>pagination.html</code> fragment handles the pagination controls and navigation. There are a lot of stuff going on, so let's break it down:</p>
<ul>
<li>The <code>pagedModel</code> and <code>pageable</code> objects are passed to the fragment.</li>
<li>Various helper variables are created to simplify the code with <code>th:with</code>.</li>
<li>An info text is displayed with the current page range and total elements.</li>
<li>It generates the pagination structure where the <code>PaginationUtils</code> class is used to calculate the page items.</li>
<li>It includes a select element to change the page size and some JavaScript to handle the page size change event (currentUrl is globally set).</li>
</ul>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>nav</span>
  <span class="token attr-name"><span class="token namespace">th:</span>fragment</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>offset-pagination(pagedModel, pageable)<span class="token punctuation">"</span></span>
  <span class="token attr-name"><span class="token namespace">th:</span>with</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>page=${pagedModel.getMetadata()}<span class="token punctuation">"</span></span>
  <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>pagination<span class="token punctuation">"</span></span>
  <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Page navigation<span class="token punctuation">"</span></span>
  <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>mt-2 mb-5<span class="token punctuation">"</span></span>
<span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>d-flex justify-content-between align-items-center<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span>
      <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>text-muted d-none d-sm-block text-nowrap<span class="token punctuation">"</span></span>
      <span class="token attr-name"><span class="token namespace">th:</span>with</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>start=${page.number * page.size + 1}, end=${T(java.lang.Math).min((page.number + 1) * page.size, page.totalElements)}<span class="token punctuation">"</span></span>
    <span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>|${start}-${end} of ${page.totalElements}|<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>

    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ul</span>
      <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>pagination mb-0<span class="token punctuation">"</span></span>
      <span class="token attr-name"><span class="token namespace">th:</span>if</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>${!pagedModel.getContent().isEmpty() &amp;&amp; page.totalPages &gt; 1}<span class="token punctuation">"</span></span>
      <span class="token attr-name"><span class="token namespace">th:</span>with</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>currentPage = ${page.number}, totalPages = ${page.totalPages}<span class="token punctuation">"</span></span>
    <span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>page-item<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">th:</span>classappend</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>${currentPage == 0} ? <span class="token punctuation">'</span>disabled<span class="token punctuation">'</span><span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span>
          <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>page-link<span class="token punctuation">"</span></span>
          <span class="token attr-name"><span class="token namespace">th:</span>tabindex</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>${currentPage == 0} ? <span class="token punctuation">'</span>-1<span class="token punctuation">'</span> : <span class="token punctuation">'</span>0<span class="token punctuation">'</span><span class="token punctuation">"</span></span>
          <span class="token attr-name"><span class="token namespace">th:</span>href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>@{${currentUrl}(page=${currentPage - 1}, size=${pageable.pageSize})}<span class="token punctuation">"</span></span>
          <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Previous<span class="token punctuation">"</span></span>
        <span class="token punctuation">&gt;</span></span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">aria-hidden</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>true<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token entity named-entity" title="«">&amp;laquo;</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">&gt;</span></span>

      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span>
        <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>page-item<span class="token punctuation">"</span></span>
        <span class="token attr-name"><span class="token namespace">th:</span>each</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>pageItem : ${T(dev.azdanov.pagination.util.PaginationUtils).getPageItems(page)}<span class="token punctuation">"</span></span>
        <span class="token attr-name"><span class="token namespace">th:</span>classappend</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>${pageItem.pageNumber == currentPage + 1} ? <span class="token punctuation">'</span>active<span class="token punctuation">'</span><span class="token punctuation">"</span></span>
      <span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span>
          <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>page-link<span class="token punctuation">"</span></span>
          <span class="token attr-name"><span class="token namespace">th:</span>href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>@{${currentUrl}(page=${pageItem.pageNumber - 1}, size=${pageable.pageSize})}<span class="token punctuation">"</span></span>
          <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>${pageItem.isEllipsis() ? <span class="token punctuation">'</span><span class="token entity named-entity" title="…">&amp;hellip;</span><span class="token punctuation">'</span> : pageItem.pageNumber}<span class="token punctuation">"</span></span>
          <span class="token attr-name"><span class="token namespace">th:</span>aria-label</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>${<span class="token punctuation">'</span>Page <span class="token punctuation">'</span> + pageItem.pageNumber}<span class="token punctuation">"</span></span>
        <span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">&gt;</span></span>

      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span>
        <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>page-item<span class="token punctuation">"</span></span>
        <span class="token attr-name"><span class="token namespace">th:</span>classappend</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>${currentPage == totalPages - 1} ? <span class="token punctuation">'</span>disabled<span class="token punctuation">'</span><span class="token punctuation">"</span></span>
      <span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span>
          <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>page-link<span class="token punctuation">"</span></span>
          <span class="token attr-name"><span class="token namespace">th:</span>tabindex</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>${currentPage == totalPages - 1} ? <span class="token punctuation">'</span>-1<span class="token punctuation">'</span> : <span class="token punctuation">'</span>0<span class="token punctuation">'</span><span class="token punctuation">"</span></span>
          <span class="token attr-name"><span class="token namespace">th:</span>href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>@{${currentUrl}(page=${currentPage + 1}, size=${pageable.pageSize})}<span class="token punctuation">"</span></span>
          <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Next<span class="token punctuation">"</span></span>
        <span class="token punctuation">&gt;</span></span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">aria-hidden</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>true<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token entity named-entity" title="»">&amp;raquo;</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ul</span><span class="token punctuation">&gt;</span></span>

    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>d-flex align-items-center<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span>
        <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>text-muted d-none d-sm-block pe-2 text-nowrap<span class="token punctuation">"</span></span>
        <span class="token attr-name">for</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>paginationSize<span class="token punctuation">"</span></span>
      <span class="token punctuation">&gt;</span></span>
        Page size
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>select</span>
        <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>form-select form-select w-auto text-center<span class="token punctuation">"</span></span>
        <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>paginationSize<span class="token punctuation">"</span></span>
        <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>paginationSize<span class="token punctuation">"</span></span>
      <span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>option</span>
          <span class="token attr-name"><span class="token namespace">th:</span>each</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>size : ${ { 5, 10, 20, 50} }<span class="token punctuation">"</span></span>
          <span class="token attr-name"><span class="token namespace">th:</span>value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>${size}<span class="token punctuation">"</span></span>
          <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>${size}<span class="token punctuation">"</span></span>
          <span class="token attr-name"><span class="token namespace">th:</span>selected</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>${page.size == size}<span class="token punctuation">"</span></span>
        <span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>option</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>select</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>

  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span> <span class="token attr-name"><span class="token namespace">th:</span>inline</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>javascript<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token script"><span class="token language-javascript">
    <span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token method function property-access">addEventListener</span><span class="token punctuation">(</span><span class="token string">"DOMContentLoaded"</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> paginationSizeSelect <span class="token operator">=</span> <span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token method function property-access">getElementById</span><span class="token punctuation">(</span><span class="token string">"paginationSize"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">const</span> currentUrl <span class="token operator">=</span> <span class="token comment">/*[[${currentUrl}]]*/</span> <span class="token string">""</span><span class="token punctuation">;</span>

      paginationSizeSelect<span class="token punctuation">.</span><span class="token method function property-access">addEventListener</span><span class="token punctuation">(</span><span class="token string">"change"</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">const</span> newSize <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token property-access">value</span><span class="token punctuation">;</span>
        <span class="token keyword">const</span> url <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">URL</span><span class="token punctuation">(</span><span class="token dom variable">window</span><span class="token punctuation">.</span><span class="token property-access">location</span><span class="token punctuation">.</span><span class="token property-access">origin</span> <span class="token operator">+</span> currentUrl<span class="token punctuation">)</span><span class="token punctuation">;</span>

        url<span class="token punctuation">.</span><span class="token property-access">searchParams</span><span class="token punctuation">.</span><span class="token method function property-access">set</span><span class="token punctuation">(</span><span class="token string">"page"</span><span class="token punctuation">,</span> <span class="token string">"0"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        url<span class="token punctuation">.</span><span class="token property-access">searchParams</span><span class="token punctuation">.</span><span class="token method function property-access">set</span><span class="token punctuation">(</span><span class="token string">"size"</span><span class="token punctuation">,</span> newSize<span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token dom variable">window</span><span class="token punctuation">.</span><span class="token property-access">location</span><span class="token punctuation">.</span><span class="token property-access">href</span> <span class="token operator">=</span> url<span class="token punctuation">.</span><span class="token method function property-access">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  </span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>nav</span><span class="token punctuation">&gt;</span></span>
</code></pre>
<h2>PaginationUtils</h2>
<p>The <code>PaginationUtils</code> class generates the pagination structure, including ellipses for large datasets.</p>
<p>I found an algorithm online: <a href="https://gist.github.com/kottenator/9d936eb3e4e3c3e02598?permalink_comment_id=5146730#gistcomment-5146730">https://gist.github.com/kottenator/9d936eb3e4e3c3e02598?permalink_comment_id=5146730#gistcomment-5146730</a></p>
<p>Credits to the author: <a href="https://gist.github.com/pk936">https://gist.github.com/pk936</a>. I modified it to fit my needs.</p>
<p>Although it had a small bug, where for smaller page sizes it showed the ellipsis on the right side, even though it could display all the pages. I added some additional checks to fix the issue.</p>
<p>I liked this implementation because it has fixed width and doesn't expand or shrink as you navigate through the pages, compared to other solutions I found.</p>
<pre class="language-java"><code class="language-java"><span class="token keyword">package</span> <span class="token namespace">dev<span class="token punctuation">.</span>azdanov<span class="token punctuation">.</span>pagination<span class="token punctuation">.</span>util</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>data<span class="token punctuation">.</span>web<span class="token punctuation">.</span></span><span class="token class-name">PagedModel</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>lang<span class="token punctuation">.</span></span><span class="token class-name">NonNull</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span><span class="token class-name">ArrayList</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span><span class="token class-name">List</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span>stream<span class="token punctuation">.</span></span><span class="token class-name">IntStream</span><span class="token punctuation">;</span>

<span class="token keyword">public</span> <span class="token keyword">final</span> <span class="token keyword">class</span> <span class="token class-name">PaginationUtils</span> <span class="token punctuation">{</span>

    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token keyword">int</span> CENTER_PAGES <span class="token operator">=</span> <span class="token number">3</span><span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token keyword">int</span> ELLIPSIS_THRESHOLD <span class="token operator">=</span> <span class="token number">2</span><span class="token punctuation">;</span>

    <span class="token keyword">private</span> <span class="token class-name">PaginationUtils</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">PageItem</span><span class="token punctuation">&gt;</span></span> <span class="token function">getPageItems</span><span class="token punctuation">(</span><span class="token annotation punctuation">@NonNull</span> <span class="token class-name">PagedModel<span class="token punctuation">.</span>PageMetadata</span> metadata<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">int</span> currentPage <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span> <span class="token punctuation">(</span>metadata<span class="token punctuation">.</span><span class="token function">number</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">int</span> totalPages <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span> metadata<span class="token punctuation">.</span><span class="token function">totalPages</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">return</span> <span class="token function">calculatePagination</span><span class="token punctuation">(</span>currentPage<span class="token punctuation">,</span> totalPages<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">PageItem</span><span class="token punctuation">&gt;</span></span> <span class="token function">calculatePagination</span><span class="token punctuation">(</span><span class="token keyword">int</span> currentPage<span class="token punctuation">,</span> <span class="token keyword">int</span> totalPages<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>totalPages <span class="token operator">&lt;=</span> CENTER_PAGES <span class="token operator">+</span> ELLIPSIS_THRESHOLD <span class="token operator">*</span> <span class="token number">2</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">return</span> <span class="token function">createFullPagination</span><span class="token punctuation">(</span>totalPages<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        <span class="token keyword">int</span> startPage <span class="token operator">=</span> <span class="token class-name">Math</span><span class="token punctuation">.</span><span class="token function">max</span><span class="token punctuation">(</span>currentPage <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">int</span> endPage <span class="token operator">=</span> <span class="token class-name">Math</span><span class="token punctuation">.</span><span class="token function">min</span><span class="token punctuation">(</span>currentPage <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">,</span> totalPages<span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">boolean</span> showLeftEllipsis <span class="token operator">=</span> startPage <span class="token operator">&gt;</span> ELLIPSIS_THRESHOLD<span class="token punctuation">;</span>
        <span class="token keyword">boolean</span> showRightEllipsis <span class="token operator">=</span> endPage <span class="token operator">&lt;</span> totalPages <span class="token operator">-</span> ELLIPSIS_THRESHOLD<span class="token punctuation">;</span>

        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>showLeftEllipsis <span class="token operator">&amp;&amp;</span> showRightEllipsis<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">return</span> <span class="token function">createLeftPagination</span><span class="token punctuation">(</span>totalPages<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>showLeftEllipsis <span class="token operator">&amp;&amp;</span> <span class="token operator">!</span>showRightEllipsis<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">return</span> <span class="token function">createRightPagination</span><span class="token punctuation">(</span>totalPages<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>showLeftEllipsis <span class="token operator">&amp;&amp;</span> showRightEllipsis<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">return</span> <span class="token function">createCenterPagination</span><span class="token punctuation">(</span>startPage<span class="token punctuation">,</span> endPage<span class="token punctuation">,</span> totalPages<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        <span class="token keyword">return</span> <span class="token function">createFullPagination</span><span class="token punctuation">(</span>totalPages<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">PageItem</span><span class="token punctuation">&gt;</span></span> <span class="token function">createLeftPagination</span><span class="token punctuation">(</span><span class="token keyword">int</span> lastPage<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">int</span> end <span class="token operator">=</span> CENTER_PAGES <span class="token operator">+</span> ELLIPSIS_THRESHOLD<span class="token punctuation">;</span>

        <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">PageItem</span><span class="token punctuation">&gt;</span></span> pages <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ArrayList</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token function">range</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> end<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        pages<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">PageItem</span><span class="token punctuation">(</span>end <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        pages<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">PageItem</span><span class="token punctuation">(</span>lastPage<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">return</span> pages<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">PageItem</span><span class="token punctuation">&gt;</span></span> <span class="token function">createRightPagination</span><span class="token punctuation">(</span><span class="token keyword">int</span> lastPage<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">int</span> start <span class="token operator">=</span> lastPage <span class="token operator">-</span> CENTER_PAGES <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">;</span>

        <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">PageItem</span><span class="token punctuation">&gt;</span></span> pages <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ArrayList</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        pages<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">PageItem</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        pages<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">PageItem</span><span class="token punctuation">(</span>start <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        pages<span class="token punctuation">.</span><span class="token function">addAll</span><span class="token punctuation">(</span><span class="token function">range</span><span class="token punctuation">(</span>start<span class="token punctuation">,</span> lastPage<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">return</span> pages<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">PageItem</span><span class="token punctuation">&gt;</span></span> <span class="token function">createCenterPagination</span><span class="token punctuation">(</span><span class="token keyword">int</span> startPage<span class="token punctuation">,</span> <span class="token keyword">int</span> endPage<span class="token punctuation">,</span> <span class="token keyword">int</span> lastPage<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">PageItem</span><span class="token punctuation">&gt;</span></span> pages <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ArrayList</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        pages<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">PageItem</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        pages<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">PageItem</span><span class="token punctuation">(</span>startPage <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        pages<span class="token punctuation">.</span><span class="token function">addAll</span><span class="token punctuation">(</span><span class="token function">range</span><span class="token punctuation">(</span>startPage<span class="token punctuation">,</span> endPage<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        pages<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">PageItem</span><span class="token punctuation">(</span>endPage <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        pages<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">PageItem</span><span class="token punctuation">(</span>lastPage<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">return</span> pages<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">PageItem</span><span class="token punctuation">&gt;</span></span> <span class="token function">createFullPagination</span><span class="token punctuation">(</span><span class="token keyword">int</span> lastPage<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> <span class="token function">range</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> lastPage<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">PageItem</span><span class="token punctuation">&gt;</span></span> <span class="token function">range</span><span class="token punctuation">(</span><span class="token keyword">int</span> start<span class="token punctuation">,</span> <span class="token keyword">int</span> end<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> <span class="token class-name">IntStream</span><span class="token punctuation">.</span><span class="token function">rangeClosed</span><span class="token punctuation">(</span>start<span class="token punctuation">,</span> end<span class="token punctuation">)</span>
            <span class="token punctuation">.</span><span class="token function">mapToObj</span><span class="token punctuation">(</span>i <span class="token operator">-&gt;</span> <span class="token keyword">new</span> <span class="token class-name">PageItem</span><span class="token punctuation">(</span>i<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
            <span class="token punctuation">.</span><span class="token function">toList</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<h2>PageItem</h2>
<p>The <code>PageItem</code> class represents a single page in the pagination component. It helps us to distinguish between regular pages and ellipses. Another way is to return <code>-1</code> instead of creating a new class, but then in the Thymeleaf fragment it is impossible to distinguish between a regular page and an ellipsis to make it a navigable link.</p>
<pre class="language-java"><code class="language-java"><span class="token keyword">package</span> <span class="token namespace">dev<span class="token punctuation">.</span>azdanov<span class="token punctuation">.</span>pagination<span class="token punctuation">.</span>util</span><span class="token punctuation">;</span>

<span class="token keyword">public</span> <span class="token keyword">record</span> <span class="token class-name">PageItem</span><span class="token punctuation">(</span><span class="token keyword">int</span> pageNumber<span class="token punctuation">,</span> <span class="token keyword">boolean</span> isEllipsis<span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
</code></pre>
<h2>Conclusion</h2>
<p>I hope this article helps you with implementing a pagination in your projects. If you have any questions or suggestions, feel free to contact me.</p>
<p>Thank you for reading!</p>]]></content:encoded>
            <author>anton@azdanov.dev (Anton Ždanov)</author>
        </item>
        <item>
            <title><![CDATA[Setting up an AWS CDK GitHub Actions pipeline for a Spring Boot app]]></title>
            <link>https://www.azdanov.dev/articles/2023/setting-up-aws-cdk-github-actions-pipeline-for-spring-boot</link>
            <guid isPermaLink="false">https://www.azdanov.dev/articles/2023/setting-up-aws-cdk-github-actions-pipeline-for-spring-boot</guid>
            <pubDate>Wed, 08 Nov 2023 16:14:59 GMT</pubDate>
            <content:encoded><![CDATA[<p>I'd like to discuss what I've learned in <strong>Chapter 1</strong> of the <a href="https://stratospheric.dev/">Stratospheric</a> book.</p>
<p>In the repository <a href="https://github.com/stratospheric-dev/hello-stratospheric">stratospheric-dev/hello-stratospheric</a>, you can check all the parts
of the pipeline.</p>
<p>The repository consists of three major areas:</p>
<ul>
<li>GitHub Actions for workflows.</li>
<li>AWS CDK to manage AWS resources.</li>
<li>Spring Boot (Docker) for publishing a new image.</li>
</ul>
<h2>GitHub Actions pipeline overview</h2>
<p>For the pipeline, GitHub Actions can be used. There are many ways it can be organized, but in general, we want to have an
automated deployment into a staging environment when a branch is merged. For changing the repository or network stack,
it is fine to trigger them manually via a workflow.</p>
<p>Here's what it might look like. (Examples are from the Stratospheric demo repository)</p>
<p>Manual Steps:</p>
<ol>
<li>Bootstrap AWS CDK.</li>
<li>Create the AWS CDK repository stack (ECR) for a specific app.</li>
<li>Created the AWS CDK network stack (VPC, IGW, ELB, ECS).</li>
</ol>
<p><a href="https://github.com/stratospheric-dev/hello-stratospheric/blob/main/.github/workflows/01-bootstrap.yml">01-bootstrap.yml</a> <br>
<a href="https://github.com/stratospheric-dev/hello-stratospheric/blob/main/.github/workflows/02-create-environment.yml">02-create-environment.yml</a></p>
<p>Automated Steps (on branch merge):</p>
<ol>
<li>Test and build the Spring Boot app.</li>
<li>Create and push a Docker image into the AWS CDK repository stack.</li>
<li>Deploy the AWS CDK service stack.</li>
</ol>
<p><a href="https://github.com/stratospheric-dev/hello-stratospheric/blob/main/.github/workflows/03-build-and-deploy.yml">03-build-and-deploy.yml</a></p>
<p>As we can see, the node.js npm is executing the AWS CDK, making the GitHub Actions configuration files quite easy to read.</p>
<h2>AWS CDK overview</h2>
<p>The AWS CDK project can be found in <a href="https://github.com/stratospheric-dev/hello-stratospheric/tree/main/cdk">main/cdk</a>. It
uses Node.js <code>package.json</code> file to expose available deployments, and <a href="https://github.com/stratospheric-dev/hello-stratospheric/blob/main/cdk/cdk.json">cdk.json</a>
to provide parameters.</p>
<p>One interesting feature of ASW CDK is the ability to abstract and encapsulate deployment code into a construct library, which
can be reused in different projects and teams.</p>
<p>The <a href="https://github.com/stratospheric-dev/cdk-constructs/tree/main">stratospheric-dev/cdk-constructs</a> library
will be used to import the <code>DockerRepository</code>, <code>Network</code>, <code>ApplicationEnvironment</code>, and <code>Service</code> constructs inside Java files which will
create a single or multiple grouped AWS resources.</p>
<h2>Spring Boot overview</h2>
<p>Two things need to happen for the Spring Boot app.</p>
<p>First, the test and build steps need to produce a <code>jar</code> file, and then the docker image must be created, tagged, and pushed into ECR.</p>
<ol>
<li>Test and build the app.</li>
<li>Create the docker image. <a href="https://github.com/stratospheric-dev/hello-stratospheric/blob/main/Dockerfile">Dockerfile</a></li>
<li>Tag the images and push them to ECR.</li>
</ol>
<h2>Conclusion</h2>
<p>This is a rough outline of the steps needed for an automated AWS CDK pipeline. The hardest part is the AWS CDK,
where knowledge of individual resources, settings, and how they integrate together is important for a successful deployment.</p>
<p>As a side note, <a href="https://learn.cantrill.io/p/aws-certified-solutions-architect-associate-saa-c03">Cantrill - AWS Certified Solutions Architect - Associate (SAA-C03)</a> is an excellent
resource to get started with AWS, either to prepare for the exam or to gain general AWS knowledge.</p>]]></content:encoded>
            <author>anton@azdanov.dev (Anton Ždanov)</author>
        </item>
        <item>
            <title><![CDATA[Starting to learn about AWS CDK with a Spring Boot app]]></title>
            <link>https://www.azdanov.dev/articles/2023/learning-about-aws-cdk-and-spring-boot</link>
            <guid isPermaLink="false">https://www.azdanov.dev/articles/2023/learning-about-aws-cdk-and-spring-boot</guid>
            <pubDate>Tue, 07 Nov 2023 07:40:18 GMT</pubDate>
            <content:encoded><![CDATA[<p>For a long time, I've been curious about how to host a Spring Boot application in the cloud, such as AWS or Azure.
I've had some experience with AWS, but it was with the serverless approach, where you don't have to worry about the infrastructure.
Same with Azure, where App Service is a quick and easy way to host an app, but it abstracts away a lot of things.</p>
<h2>Stratospheric: From Zero to Production with Spring Boot and AWS</h2>
<p>I've found a book called <a href="https://stratospheric.dev/">Stratospheric</a> about learning <a href="https://aws.amazon.com/cdk/">AWS CDK</a> for a Spring Boot app.
It was in my backlog, but I finally started going through it.</p>
<p>This book provides a step-by-step guide on how to build a Spring Boot app and deploy it to AWS. It explains
the concepts of CloudFormation, and then it shows how to use AWS CDK to create the infrastructure for the app.</p>
<p>I've yet to finish the book, but I've already learned more about using AWS CDK and AWS in general.
I had limited experience with CloudFormation, which I didn't know how to use correctly, and no experience with AWS CDK. Previously, I only used the
<a href="https://www.serverless.com/">Serverless Framework</a> and <a href="https://www.terraform.io/">Terraform</a> to deploy my apps to AWS.</p>
<h2>Next Steps</h2>
<p>As I continue reading the book, I'll write more about my experience with AWS CDK, AWS, and Spring Boot.</p>]]></content:encoded>
            <author>anton@azdanov.dev (Anton Ždanov)</author>
        </item>
        <item>
            <title><![CDATA[Getting Microsoft Certified: Azure Developer Associate (AZ-204)]]></title>
            <link>https://www.azdanov.dev/articles/2023/getting-microsoft-certified-azure-developer-associate</link>
            <guid isPermaLink="false">https://www.azdanov.dev/articles/2023/getting-microsoft-certified-azure-developer-associate</guid>
            <pubDate>Wed, 26 Jul 2023 18:11:43 GMT</pubDate>
            <content:encoded><![CDATA[<p>This exam proved to be much more difficult than AZ-104. Even though I am a developer and already passed AZ-104 beforehand, some questions were very tricky. I had to read them multiple times to understand what they are asking for.
Often enough, I just had to randomly guess the answer, because I didn't know the correct one. I was very surprised to see that I passed the exam with a score of 820/1000.</p>
<p>I think it was a good idea to pass AZ-104 first, because it gave me a good understanding of the Azure ecosystem. I would recommend doing the same.
Also, there seems to be a lack of good preparation material for AZ-204. The official Microsoft Learn barely covers the exam topics, considering how tricky the questions were.</p>
<p>I liked the topics covered in the exam, because they were not part of the AZ-104. The queue, event grid and service bus topics were very interesting to learn about.
Security is still and identity management is still quite tricky for me, but I am getting there. And I'd argue that Cosmos DB is the most difficult topic of all.
Cosmos DB can be very easy to start with, but there are many features and not so much overall experience or material to learn from. So learning relational SQL is much easier and worthwhile.</p>
<aside class="inline-flex flex-col items-center"><img alt="Microsoft Certified: Azure Developer Associate (AZ-204) certificate." loading="lazy" width="300" height="300" decoding="async" data-nimg="1" style="color:transparent" src="/_next/static/media/microsoft-certified-associate-badge.0qy2c1n1pgu1u.svg"><p><a href="https://learn.microsoft.com/api/credentials/share/en-us/azdanov/8A43495F02BE1A3E?sharingId=E18AE6457FBDE5E3">Microsoft
Certificate</a></p></aside>
<h2>Preparation</h2>
<p>I have used the following resources:</p>
<ul>
<li><a href="https://www.udemy.com/course/azure-certification-1/">Udemy - AZ-204: Developing Solutions for Microsoft Azure</a> - A course from Alan Rodrigues. It was okay, but very tedious and code examples were not so good. But it covers a lot of topics if you can stomach sitting through 27 hours of video.</li>
<li><a href="https://www.udemy.com/course/microsoft-azure-for-net-developers/">Udemy - Microsoft Azure for .NET Developers</a> - A course by Trevoir Williams. It was exceptional and engaging. Sadly it only covers a small portion of the exam topics. Yet I highly recommend it, because it covers how to use some of the services in .NET in a very practical way.</li>
<li><a href="https://learn.microsoft.com/en-us/certifications/exams/az-204/">Microsoft Learn: Exam AZ-204: Microsoft Azure Developer Associate</a> - Official training material, with free a sandbox to practice hands-on.</li>
<li><a href="https://www.measureup.com/microsoft-practice-test-az-204-developing-solutions-for-microsoft-azure.html">MeasureUp: Microsoft Practice Test AZ-204: Microsoft Azure Developer</a> - Some additional practice exams. They were better than AZ-104, but I'd recommend to find additional practice tests on other resources.</li>
</ul>
<h2>Final thoughts</h2>
<p>Take much more time than you think you would need for AZ-204. Preferably, if you can, take AZ-104 beforehand. I recommend doing <a href="https://learn.cloudlee.io/">cloudlee AZ-104</a> and <a href="https://www.youtube.com/playlist?list=PLlVtbbG169nGlGPWs9xaLKT1KfwqREHbs">John Savill AZ-104</a> courses. This should give you general picture about Azure and prepare you for AZ-104/204.
After that, just reading documentation and following the exam guidelines would be the best way to prepare, apart from the resources I mentioned above (udemy, microsoft learn, measureup).</p>
<p>It took me a few weeks to finally write this blog post because this exam kicked my butt, and I had to take some time off. I am glad I passed it, but I was so certain that I failed during exam that it was quite a rollercoaster of emotions.</p>
<p>The Next one for me will be <a href="https://learn.microsoft.com/en-us/certifications/devops-engineer/">AZ-400</a>, but I will take a break for a while. Change gears and study some C# and ASP.NET Core.</p>]]></content:encoded>
            <author>anton@azdanov.dev (Anton Ždanov)</author>
        </item>
        <item>
            <title><![CDATA[Getting Microsoft Certified: Azure Administrator Associate (AZ-104)]]></title>
            <link>https://www.azdanov.dev/articles/2023/getting-microsoft-certified-azure-administrator-associate</link>
            <guid isPermaLink="false">https://www.azdanov.dev/articles/2023/getting-microsoft-certified-azure-administrator-associate</guid>
            <pubDate>Wed, 14 Jun 2023 02:36:25 GMT</pubDate>
            <content:encoded><![CDATA[<p>Next step accomplished, the Microsoft Certified: Azure Administrator Associate (AZ-104) exam has been successfully passed.
The exam itself was a mixed experience, with some questions being very easy, and some being very tricky. I have spent around
40 days to prepare for it (almost full-time and no days off), and I got 860/1000 score.</p>
<p>There were a bunch of questions about older Azure services, which I have never used, so I had to guess the answers,
e.g., general-purpose v1 / blob storage (those will be deprecated soon). Or very specific questions which I couldn't find afterward
even though I tried to find an answer in the documentation (virtual machine scale sets update domain related). And some questions were very basic,
just selecting an appropriate service to use out of a list of options that should've been only in AZ-900.</p>
<p>I did enjoy the questions that required me to think more based on an example picture and figure out what's wrong with it, or to
choose an appropriate solution. Or reading an ARM template or a Policy definition. I liked questions that you can logically
think through and find the answer, instead of just memorizing some fact from documentation.</p>
<p>I would say that it was beneficial to pass AZ-900 first, to get a general understanding of Azure services, and to see
how the exam itself is done. But I don't see myself doing any other 900-level exams in the future, only if I have a free voucher.</p>
<aside class="inline-flex flex-col items-center"><img alt="Microsoft Certified: Azure Administrator Associate (AZ-104) certificate." loading="lazy" width="300" height="300" decoding="async" data-nimg="1" style="color:transparent" src="/_next/static/media/microsoft-certified-associate-badge.0qy2c1n1pgu1u.svg"><p><a href="https://learn.microsoft.com/api/credentials/share/en-us/azdanov/7D93516BE16A069?sharingId=E18AE6457FBDE5E3">Microsoft
Certificate</a></p></aside>
<h2>Preparation</h2>
<p>I have used the following resources:</p>
<ul>
<li><a href="https://learn.cloudlee.io/p/az-104-microsoft-azure-administrator">Cloudlee: AZ-104 Microsoft Azure Administrator</a> - Course is 23 hours long, and it covers all the topics in the exam. I went through this course 2 times, so good it was. I highly recommend it.</li>
<li><a href="https://learn.microsoft.com/en-us/certifications/exams/az-104/">Microsoft Learn: Exam AZ-104: Microsoft Azure Administrator Associate</a> - Official training material, with free a sandbox to practice hands-on.</li>
<li><a href="https://www.youtube.com/playlist?list=PLlVtbbG169nGlGPWs9xaLKT1KfwqREHbs">YouTube: John Savill's AZ-104 Azure Administrator Study List</a> - Another really amazing playlist on YouTube by John Savill.</li>
<li><a href="https://portal.tutorialsdojo.com/courses/az-104-microsoft-azure-administrator-practice-exams/">Tutorials Dojo: AZ-104 Microsoft Azure Administrator Practice Exams</a> - Very useful practice exams by Tutorials Dojo.</li>
<li><a href="https://www.measureup.com/microsoft-practice-test-az-104-microsoft-azure-administrator.html/">MeasureUp: Microsoft Practice Test AZ-104: Microsoft Azure Administrator</a> - Some additional practice exams. I wouldn't recommend, too expensive and lots of irrelevant and difficult questions.</li>
</ul>
<p>The next step for me is to get the <a href="https://learn.microsoft.com/en-us/certifications/azure-developer/">Microsoft Certified: Azure Developer Associate (AZ-204)</a> certificate.</p>
<h2>Final thoughts</h2>
<p>Why do I want to get certified? I don't think that it's a good way to prove your knowledge (it's too easy to find exam dumps
and memorize the answers without understanding why), but it's a good way to structure your learning process. It forces you to learn things that you
wouldn't learn otherwise (how would I find out that <a href="https://learn.microsoft.com/en-us/azure/backup/backup-azure-about-mars">MARS</a> exists on my own 😄?),
and it gives you a deeper dive of the services that Azure provides.</p>
<p>I remember, when I was using AWS at my previous job, I was exposed and limited to only a few services, and I didn't know what else AWS
could offer and didn't have time to learn more about the services that were being used or if there was a better alternative or
some architectural pattern. Only recently I've learned about <a href="https://aws.amazon.com/architecture/well-architected/">AWS Well-Architected Framework</a>,
and I see great value in learning how to use cloud services properly. Azure has a similar <a href="https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/">Microsoft Cloud Adoption Framework for Azure</a>
and <a href="https://learn.microsoft.com/en-us/azure/well-architected/">Azure Well-Architected Framework</a> which I would like to go over one day.</p>
<p>In the end, I'd like to find a job that uses cloud technologies extensively, and hopefully using Azure. I'm not sure how
valuable the certificate itself will be, but studying and following the exam structure is helping me to get the experience needed
for the job.</p>]]></content:encoded>
            <author>anton@azdanov.dev (Anton Ždanov)</author>
        </item>
        <item>
            <title><![CDATA[Free Azure DevOps Parallel Jobs for Public and Private Repositories]]></title>
            <link>https://www.azdanov.dev/articles/2023/free-azure-devops-parallel-jobs</link>
            <guid isPermaLink="false">https://www.azdanov.dev/articles/2023/free-azure-devops-parallel-jobs</guid>
            <pubDate>Sat, 06 May 2023 06:51:50 GMT</pubDate>
            <content:encoded><![CDATA[<p>As someone who started learning Azure DevOps, I encountered a problem with the free tier of Azure DevOps.</p>
<p>When logging in and creating a new organization, I navigated to <code>Organization Settings &gt; Parallel Jobs</code> and saw that
for Microsoft-hosted agents I have zero parallel jobs and for self-hosted agents I have one parallel job.
Which meant that you can create your own VM and run your own agent on it, but for that you'll need to pay for the VM.</p>
<p>To get the free Microsoft-hosted agent, you'll need to fill out a form and wait for the approval: <a href="https://aka.ms/azpipelines-parallelism-request">https://aka.ms/azpipelines-parallelism-request</a></p>
<p>I had a billing setup for my Azure account, which I also used for Azure DevOps, but maybe it wasn't necessary.</p>
<p>And you can read more about the configuration of parallel jobs here, and current request process for free grant: <a href="https://aka.ms/microsofthosted">https://aka.ms/microsofthosted</a></p>]]></content:encoded>
            <author>anton@azdanov.dev (Anton Ždanov)</author>
        </item>
        <item>
            <title><![CDATA[Getting Microsoft Certified: Azure Fundamentals (AZ-900)]]></title>
            <link>https://www.azdanov.dev/articles/2023/getting-microsoft-certified-azure-fundamentals</link>
            <guid isPermaLink="false">https://www.azdanov.dev/articles/2023/getting-microsoft-certified-azure-fundamentals</guid>
            <pubDate>Wed, 03 May 2023 12:29:08 GMT</pubDate>
            <content:encoded><![CDATA[<p>The first major step on my way to learn and use Azure was to pass the Microsoft Certified: Azure Fundamentals (AZ-900) exam.
Exam itself is not hard, but it requires a lot of preparations and memorization and luck, since some questions I didn't
encounter while preparing. I have passed it on the first try, but I wouldn't say that it was a breeze.</p>
<p>I have spent around 10 days to prepare for it, with a final score of 925/1000. I have several years of experience with
software development, and I have used AWS in production, so I was familiar with the concepts of cloud computing and cloud services.</p>
<aside class="inline-flex flex-col items-center"><img alt="Microsoft Certified: Azure Fundamentals (AZ-900) certificate." loading="lazy" width="300" height="300" decoding="async" data-nimg="1" style="color:transparent" src="/_next/static/media/microsoft-certified-fundamentals-badge.0vn69w5xzdiqm.svg"><p><a href="https://learn.microsoft.com/api/credentials/share/en-us/azdanov/294B5745E8FCEC01?sharingId=E18AE6457FBDE5E3">Microsoft
Certificate</a></p></aside>
<h2>Preparation</h2>
<p>I have used the following resources:</p>
<ul>
<li><a href="https://learn.microsoft.com/en-us/certifications/exams/az-900/">Microsoft Learn: Exam AZ-900: Microsoft Azure Fundamentals</a> - Official training material, with free a sandbox to practice hands-on.</li>
<li><a href="https://www.youtube.com/playlist?list=PLlVtbbG169nED0_vMEniWBQjSoxTsBYS3">YouTube: John Savill's AZ-900 Azure Fundamentals Certification Course</a> - A really amazing course on YouTube by John Savill.</li>
<li><a href="https://portal.tutorialsdojo.com/courses/az-900-microsoft-azure-fundamentals-practice-exams/">Tutorials Dojo: AZ-900 Microsoft Azure Fundamentals Practice Exams</a> - Very useful practice exams by Tutorials Dojo.</li>
</ul>
<p>At the same time, I've found an interesting YouTube channel that focuses on Azure, DevOps, Terraform, and other
related topics — <a href="https://www.youtube.com/@azure-terraformer">Azure Terraformer</a> by Mark Tinderholt. His videos are very useful and informative,
for those interested in learning how to use Terraform with Azure ecosystem, and I highly recommend checking them out. Although it
is about more advanced topics, it is still very helpful in starting to prepare for <a href="https://learn.microsoft.com/en-us/certifications/azure-administrator/">AZ-104</a>
and <a href="https://learn.microsoft.com/en-us/certifications/devops-engineer/">AZ-400</a> exams.</p>
<p>The next step for me is to get the <a href="https://learn.microsoft.com/en-us/certifications/azure-administrator/">Microsoft Certified: Azure Administrator
Associate (AZ-104)</a> certificate.</p>]]></content:encoded>
            <author>anton@azdanov.dev (Anton Ždanov)</author>
        </item>
        <item>
            <title><![CDATA[How to host a static website on AWS S3, CloudFront and Route53 using Terraform]]></title>
            <link>https://www.azdanov.dev/articles/2023/aws-terraform-static-website</link>
            <guid isPermaLink="false">https://www.azdanov.dev/articles/2023/aws-terraform-static-website</guid>
            <pubDate>Tue, 18 Apr 2023 07:02:24 GMT</pubDate>
            <content:encoded><![CDATA[<p>In this article, I'd like to share my experience of hosting a static website on AWS S3, CloudFront and Route53 using Terraform.
It will use a custom domain name, and it will be secured with a TLS certificate.</p>
<p><strong>Update:</strong>
You can also watch a handy code review of the terraform project on YouTube by Azure Terraformer.
<a href="https://www.youtube.com/watch?v=taVEy7Rinoo">Terraform Code Review: File Structure &amp; Naming Conventions</a>.</p>
<h2>Prerequisites</h2>
<h3>AWS Account</h3>
<p>You'll need an AWS account to host your website. If you don't have one, you can create one for free.</p>
<ul>
<li><a href="https://aws.amazon.com/premiumsupport/knowledge-center/create-and-activate-aws-account/">Create an AWS account</a></li>
<li><a href="https://docs.aws.amazon.com/accounts/latest/reference/welcome-first-time-user.html">Getting started: Are you a first-time AWS user?</a></li>
<li><a href="https://aws.amazon.com/blogs/security/getting-started-follow-security-best-practices-as-you-configure-your-aws-resources/">Getting Started: Follow Security Best Practices as You Configure Your AWS Resources</a></li>
<li><a href="https://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/checklistforunwantedcharges.html">Avoiding unexpected charges</a></li>
<li><a href="https://repost.aws/knowledge-center/what-is-free-tier">What is the AWS Free Tier, and how do I use it?</a></li>
</ul>
<p>Just to reiterate, you should follow the best practices when working with AWS:</p>
<ol>
<li>Create a separate <a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/id_users_create.html">IAM user</a> and don't use the root account.</li>
<li><a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa_enable.html#id_credentials_mfa_enable-overview">Enable MFA</a> for both the root account and the IAM user (or even better <a href="https://aws.amazon.com/iam/identity-center/">use SSO</a>).</li>
<li>Create an <a href="https://docs.aws.amazon.com/cost-management/latest/userguide/budgets-managing-costs.html?icmpid=docs_costmanagement_hp-budgets-overview">AWS Budget</a>
to alert you when your costs exceed a certain threshold.</li>
</ol>
<h3>AWS CLI</h3>
<p>You'll need to set up the AWS CLI and to configure your AWS credentials. If you don't have it installed, you can download it from the <a href="https://aws.amazon.com/cli/">official website</a>.</p>
<h3>Terraform</h3>
<p>You'll need Terraform to provision the infrastructure. If you don't have it installed, you can download it from the <a href="https://www.terraform.io/downloads.html">official website</a>.</p>
<h3>Domain Name</h3>
<p>You'll need a domain name to host your website. If you don't have one, you can buy one from a domain registrar.
In this article, I'll be using <a href="https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/domain-register.html?icmpid=docs_console_unmapped">Route53</a> to manage my domain,
because it will simplify the Terraform configuration.</p>
<p>There are ways to connect or migrate an existing domain name, but it's out of scope for this article.</p>
<p>We will be using a domain for the CloudFront distribution, and a TLS certificate.</p>
<h2>Setup</h2>
<p>After you've set up your AWS account, AWS CLI and Terraform, you can start provisioning the infrastructure.</p>
<p>I'll be using my Demo Next.js app as an example. You can find the source code on <a href="https://github.com/azdanov/aws-terraform-static-website-demo">GitHub</a>.</p>
<h3>Setting up Terraform</h3>
<p>Before we start, it's a good idea to manually create a DynamoDB table for Terraform state locking and an S3 bucket for Terraform remote state storage.</p>
<pre class="language-bash"><code class="language-bash"><span class="token comment"># Create an S3 bucket for Terraform remote state storage</span>
aws s3api create-bucket --bucket azdanov-aws-static-website-demo-terraform-state --region us-east-1

<span class="token comment"># Disable public access to the S3 bucket</span>
aws s3api put-public-access-block --bucket azdanov-aws-static-website-demo-terraform-state --public-access-block-configuration <span class="token string">"BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true"</span>

<span class="token comment"># Create a DynamoDB table for Terraform state locking</span>
aws dynamodb create-table --table-name azdanov-aws-static-website-demo-terraform-lock-table --region us-east-1 --attribute-definitions <span class="token assign-left variable">AttributeName</span><span class="token operator">=</span>LockID,AttributeType<span class="token operator">=</span>S --key-schema <span class="token assign-left variable">AttributeName</span><span class="token operator">=</span>LockID,KeyType<span class="token operator">=</span>HASH --provisioned-throughput <span class="token assign-left variable">ReadCapacityUnits</span><span class="token operator">=</span><span class="token number">1</span>,WriteCapacityUnits<span class="token operator">=</span><span class="token number">1</span>
</code></pre>
<h3>Writing Terraform file</h3>
<p>Now, we can start writing the Terraform file. You can easily copy it from the <a href="https://github.com/azdanov/aws-terraform-static-website-demo/blob/main/infrastructure/main.tf">GitHub repository</a>.</p>
<pre class="language-hcl"><code class="language-hcl"><span class="token keyword">terraform</span> <span class="token punctuation">{</span>
  <span class="token keyword">required_providers</span> <span class="token punctuation">{</span>
    <span class="token property">aws</span> <span class="token punctuation">=</span> <span class="token punctuation">{</span>
      <span class="token property">source</span>  <span class="token punctuation">=</span> <span class="token string">"hashicorp/aws"</span>
      <span class="token property">version</span> <span class="token punctuation">=</span> <span class="token string">"~&gt; 4.63"</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
  <span class="token keyword">backend<span class="token type variable"> "s3" </span></span><span class="token punctuation">{</span>
    <span class="token property">bucket</span>         <span class="token punctuation">=</span> <span class="token string">"azdanov-aws-static-website-demo-terraform-state"</span>
    <span class="token property">key</span>            <span class="token punctuation">=</span> <span class="token string">"terraform.tfstate"</span>
    <span class="token property">region</span>         <span class="token punctuation">=</span> <span class="token string">"us-east-1"</span>
    <span class="token property">dynamodb_table</span> <span class="token punctuation">=</span> <span class="token string">"azdanov-aws-static-website-demo-terraform-lock-table"</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token keyword">provider<span class="token type variable"> "aws" </span></span><span class="token punctuation">{</span>
  <span class="token property">region</span> <span class="token punctuation">=</span> <span class="token string">"us-east-1"</span>
<span class="token punctuation">}</span>

<span class="token keyword">variable<span class="token type variable"> "domain_name" </span></span><span class="token punctuation">{</span>
  <span class="token property">type</span>        <span class="token punctuation">=</span> string
  <span class="token property">description</span> <span class="token punctuation">=</span> <span class="token string">"The domain name for the website, e.g. example.com. Must already be registered with Route53."</span>
<span class="token punctuation">}</span>

<span class="token keyword">locals</span> <span class="token punctuation">{</span>
  <span class="token property">origin_id</span> <span class="token punctuation">=</span> <span class="token string">"<span class="token interpolation"><span class="token punctuation">$</span><span class="token punctuation">{</span><span class="token keyword">var</span><span class="token punctuation">.</span><span class="token type variable">domain_name</span><span class="token punctuation">}</span></span>-<span class="token interpolation"><span class="token punctuation">$</span><span class="token punctuation">{</span><span class="token function">sha1</span><span class="token punctuation">(</span><span class="token keyword">var</span><span class="token punctuation">.</span><span class="token type variable">domain_name</span><span class="token punctuation">)</span><span class="token punctuation">}</span></span>"</span>
<span class="token punctuation">}</span>

<span class="token comment"># Route53 zone</span>
<span class="token keyword">data <span class="token type variable">"aws_route53_zone"</span></span> <span class="token string">"zone"</span> <span class="token punctuation">{</span>
  <span class="token property">name</span> <span class="token punctuation">=</span> var.domain_name
<span class="token punctuation">}</span>


<span class="token comment"># S3 bucket</span>
<span class="token keyword">resource <span class="token type variable">"aws_s3_bucket"</span></span> <span class="token string">"bucket"</span> <span class="token punctuation">{</span>
  <span class="token property">bucket</span> <span class="token punctuation">=</span> substr(local.origin_id, <span class="token number">0</span>, <span class="token number">63</span>)

  <span class="token property">tags</span> <span class="token punctuation">=</span> <span class="token punctuation">{</span>
    <span class="token property">Name</span> <span class="token punctuation">=</span> var.domain_name
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token keyword">resource <span class="token type variable">"aws_s3_bucket_public_access_block"</span></span> <span class="token string">"access"</span> <span class="token punctuation">{</span>
  <span class="token property">bucket</span> <span class="token punctuation">=</span> aws_s3_bucket.bucket.id

  <span class="token property">block_public_acls</span>       <span class="token punctuation">=</span> <span class="token boolean">true</span>
  <span class="token property">block_public_policy</span>     <span class="token punctuation">=</span> <span class="token boolean">true</span>
  <span class="token property">ignore_public_acls</span>      <span class="token punctuation">=</span> <span class="token boolean">true</span>
  <span class="token property">restrict_public_buckets</span> <span class="token punctuation">=</span> <span class="token boolean">true</span>
<span class="token punctuation">}</span>


<span class="token comment"># ACM certificate</span>
<span class="token keyword">resource <span class="token type variable">"aws_acm_certificate"</span></span> <span class="token string">"certificate"</span> <span class="token punctuation">{</span>
  <span class="token property">domain_name</span>       <span class="token punctuation">=</span> var.domain_name
  <span class="token property">validation_method</span> <span class="token punctuation">=</span> <span class="token string">"DNS"</span>

  <span class="token keyword">lifecycle</span> <span class="token punctuation">{</span>
    <span class="token property">create_before_destroy</span> <span class="token punctuation">=</span> <span class="token boolean">true</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token keyword">resource <span class="token type variable">"aws_route53_record"</span></span> <span class="token string">"acm_record"</span> <span class="token punctuation">{</span>
  <span class="token property">for_each</span> <span class="token punctuation">=</span> <span class="token punctuation">{</span>
    for dvo in aws_acm_certificate.certificate.domain_validation_options : <span class="token property">dvo.domain_name</span> <span class="token punctuation">=</span>&gt; <span class="token punctuation">{</span>
      <span class="token property">name</span>   <span class="token punctuation">=</span> dvo.resource_record_name
      <span class="token property">record</span> <span class="token punctuation">=</span> dvo.resource_record_value
      <span class="token property">type</span>   <span class="token punctuation">=</span> dvo.resource_record_type
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>

  <span class="token property">allow_overwrite</span> <span class="token punctuation">=</span> <span class="token boolean">true</span>
  <span class="token property">name</span>            <span class="token punctuation">=</span> each.value.name
  <span class="token property">records</span>         <span class="token punctuation">=</span> <span class="token punctuation">[</span>each.value.record<span class="token punctuation">]</span>
  <span class="token property">ttl</span>             <span class="token punctuation">=</span> <span class="token number">60</span>
  <span class="token property">type</span>            <span class="token punctuation">=</span> each.value.type
  <span class="token property">zone_id</span>         <span class="token punctuation">=</span> data.aws_route53_zone.zone.zone_id
<span class="token punctuation">}</span>

<span class="token keyword">resource <span class="token type variable">"aws_acm_certificate_validation"</span></span> <span class="token string">"validation"</span> <span class="token punctuation">{</span>
  <span class="token property">certificate_arn</span>         <span class="token punctuation">=</span> aws_acm_certificate.certificate.arn
  <span class="token property">validation_record_fqdns</span> <span class="token punctuation">=</span> <span class="token punctuation">[</span>for record in aws_route53_record.acm_record : record.fqdn<span class="token punctuation">]</span>
<span class="token punctuation">}</span>


<span class="token comment"># CloudFront distribution</span>
<span class="token keyword">resource <span class="token type variable">"aws_cloudfront_origin_access_control"</span></span> <span class="token string">"oac"</span> <span class="token punctuation">{</span>
  <span class="token property">name</span>                              <span class="token punctuation">=</span> <span class="token string">"<span class="token interpolation"><span class="token punctuation">$</span><span class="token punctuation">{</span><span class="token keyword">var</span><span class="token punctuation">.</span><span class="token type variable">domain_name</span><span class="token punctuation">}</span></span> access control"</span>
  <span class="token property">description</span>                       <span class="token punctuation">=</span> <span class="token string">"Cloudfront access control for the <span class="token interpolation"><span class="token punctuation">$</span><span class="token punctuation">{</span><span class="token keyword">var</span><span class="token punctuation">.</span><span class="token type variable">domain_name</span><span class="token punctuation">}</span></span> distribution."</span>
  <span class="token property">origin_access_control_origin_type</span> <span class="token punctuation">=</span> <span class="token string">"s3"</span>
  <span class="token property">signing_behavior</span>                  <span class="token punctuation">=</span> <span class="token string">"always"</span>
  <span class="token property">signing_protocol</span>                  <span class="token punctuation">=</span> <span class="token string">"sigv4"</span>
<span class="token punctuation">}</span>

<span class="token keyword">data <span class="token type variable">"aws_cloudfront_cache_policy"</span></span> <span class="token string">"cache_policy"</span> <span class="token punctuation">{</span>
  <span class="token property">name</span> <span class="token punctuation">=</span> <span class="token string">"Managed-CachingOptimized"</span>
<span class="token punctuation">}</span>

<span class="token keyword">data <span class="token type variable">"aws_cloudfront_origin_request_policy"</span></span> <span class="token string">"origin_request_policy"</span> <span class="token punctuation">{</span>
  <span class="token property">name</span> <span class="token punctuation">=</span> <span class="token string">"Managed-CORS-S3Origin"</span>
<span class="token punctuation">}</span>

<span class="token keyword">data <span class="token type variable">"aws_cloudfront_response_headers_policy"</span></span> <span class="token string">"response_headers_policy"</span> <span class="token punctuation">{</span>
  <span class="token property">name</span> <span class="token punctuation">=</span> <span class="token string">"Managed-SecurityHeadersPolicy"</span>
<span class="token punctuation">}</span>

<span class="token keyword">resource <span class="token type variable">"aws_cloudfront_distribution"</span></span> <span class="token string">"distribution"</span> <span class="token punctuation">{</span>
  <span class="token property">enabled</span>             <span class="token punctuation">=</span> <span class="token boolean">true</span>
  <span class="token property">is_ipv6_enabled</span>     <span class="token punctuation">=</span> <span class="token boolean">true</span>
  <span class="token property">default_root_object</span> <span class="token punctuation">=</span> <span class="token string">"index.html"</span>
  <span class="token property">http_version</span>        <span class="token punctuation">=</span> <span class="token string">"http2and3"</span>
  <span class="token property">price_class</span>         <span class="token punctuation">=</span> <span class="token string">"PriceClass_100"</span>
  <span class="token property">retain_on_delete</span>    <span class="token punctuation">=</span> <span class="token boolean">false</span>
  <span class="token property">wait_for_deployment</span> <span class="token punctuation">=</span> <span class="token boolean">false</span>
  <span class="token property">aliases</span>             <span class="token punctuation">=</span> <span class="token punctuation">[</span>var.domain_name<span class="token punctuation">]</span>

  <span class="token keyword">origin</span> <span class="token punctuation">{</span>
    <span class="token property">domain_name</span>              <span class="token punctuation">=</span> aws_s3_bucket.bucket.bucket_regional_domain_name
    <span class="token property">origin_access_control_id</span> <span class="token punctuation">=</span> aws_cloudfront_origin_access_control.oac.id
    <span class="token property">origin_id</span>                <span class="token punctuation">=</span> local.origin_id
  <span class="token punctuation">}</span>

  <span class="token keyword">custom_error_response</span> <span class="token punctuation">{</span>
    <span class="token property">error_code</span>         <span class="token punctuation">=</span> <span class="token string">"403"</span>
    <span class="token property">response_code</span>      <span class="token punctuation">=</span> <span class="token string">"200"</span>
    <span class="token property">response_page_path</span> <span class="token punctuation">=</span> <span class="token string">"/index.html"</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">default_cache_behavior</span> <span class="token punctuation">{</span>
    <span class="token property">compress</span>                   <span class="token punctuation">=</span> <span class="token boolean">true</span>
    <span class="token property">viewer_protocol_policy</span>     <span class="token punctuation">=</span> <span class="token string">"redirect-to-https"</span>
    <span class="token property">allowed_methods</span>            <span class="token punctuation">=</span> <span class="token punctuation">[</span><span class="token string">"GET"</span>, <span class="token string">"HEAD"</span><span class="token punctuation">]</span>
    <span class="token property">cached_methods</span>             <span class="token punctuation">=</span> <span class="token punctuation">[</span><span class="token string">"GET"</span>, <span class="token string">"HEAD"</span><span class="token punctuation">]</span>
    <span class="token property">target_origin_id</span>           <span class="token punctuation">=</span> local.origin_id
    <span class="token property">cache_policy_id</span>            <span class="token punctuation">=</span> data.aws_cloudfront_cache_policy.cache_policy.id
    <span class="token property">origin_request_policy_id</span>   <span class="token punctuation">=</span> data.aws_cloudfront_origin_request_policy.origin_request_policy.id
    <span class="token property">response_headers_policy_id</span> <span class="token punctuation">=</span> data.aws_cloudfront_response_headers_policy.response_headers_policy.id
  <span class="token punctuation">}</span>

  <span class="token keyword">restrictions</span> <span class="token punctuation">{</span>
    <span class="token keyword">geo_restriction</span> <span class="token punctuation">{</span>
      <span class="token property">restriction_type</span> <span class="token punctuation">=</span> <span class="token string">"none"</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">viewer_certificate</span> <span class="token punctuation">{</span>
    <span class="token property">cloudfront_default_certificate</span> <span class="token punctuation">=</span> <span class="token boolean">false</span>
    <span class="token property">acm_certificate_arn</span>            <span class="token punctuation">=</span> aws_acm_certificate.certificate.arn
    <span class="token property">minimum_protocol_version</span>       <span class="token punctuation">=</span> <span class="token string">"TLSv1.2_2021"</span>
    <span class="token property">ssl_support_method</span>             <span class="token punctuation">=</span> <span class="token string">"sni-only"</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token keyword">resource <span class="token type variable">"aws_route53_record"</span></span> <span class="token string">"cloudfront_record"</span> <span class="token punctuation">{</span>
  <span class="token property">zone_id</span> <span class="token punctuation">=</span> data.aws_route53_zone.zone.zone_id
  <span class="token property">name</span>    <span class="token punctuation">=</span> var.domain_name
  <span class="token property">type</span>    <span class="token punctuation">=</span> <span class="token string">"A"</span>

  <span class="token keyword">alias</span> <span class="token punctuation">{</span>
    <span class="token property">evaluate_target_health</span> <span class="token punctuation">=</span> <span class="token boolean">false</span>
    <span class="token property">name</span>                   <span class="token punctuation">=</span> aws_cloudfront_distribution.distribution.domain_name
    <span class="token property">zone_id</span>                <span class="token punctuation">=</span> aws_cloudfront_distribution.distribution.hosted_zone_id
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token keyword">data <span class="token type variable">"aws_iam_policy_document"</span></span> <span class="token string">"document"</span> <span class="token punctuation">{</span>
  <span class="token keyword">statement</span> <span class="token punctuation">{</span>
    <span class="token property">actions</span>   <span class="token punctuation">=</span> <span class="token punctuation">[</span><span class="token string">"s3:GetObject"</span><span class="token punctuation">]</span>
    <span class="token property">resources</span> <span class="token punctuation">=</span> <span class="token punctuation">[</span><span class="token string">"<span class="token interpolation"><span class="token punctuation">$</span><span class="token punctuation">{</span>aws_s3_bucket<span class="token punctuation">.</span>bucket<span class="token punctuation">.</span>arn<span class="token punctuation">}</span></span>/*"</span><span class="token punctuation">]</span>

    <span class="token keyword">principals</span> <span class="token punctuation">{</span>
      <span class="token property">type</span>        <span class="token punctuation">=</span> <span class="token string">"Service"</span>
      <span class="token property">identifiers</span> <span class="token punctuation">=</span> <span class="token punctuation">[</span><span class="token string">"cloudfront.amazonaws.com"</span><span class="token punctuation">]</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">condition</span> <span class="token punctuation">{</span>
      <span class="token property">test</span>     <span class="token punctuation">=</span> <span class="token string">"StringEquals"</span>
      <span class="token property">variable</span> <span class="token punctuation">=</span> <span class="token string">"AWS:SourceArn"</span>
      <span class="token property">values</span>   <span class="token punctuation">=</span> <span class="token punctuation">[</span>aws_cloudfront_distribution.distribution.arn<span class="token punctuation">]</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token keyword">resource <span class="token type variable">"aws_s3_bucket_policy"</span></span> <span class="token string">"policy"</span> <span class="token punctuation">{</span>
  <span class="token property">bucket</span> <span class="token punctuation">=</span> aws_s3_bucket.bucket.id
  <span class="token property">policy</span> <span class="token punctuation">=</span> data.aws_iam_policy_document.document.json
<span class="token punctuation">}</span>
</code></pre>
<h3>Running Terraform</h3>
<p>Now, we can start provisioning the infrastructure.</p>
<pre class="language-bash"><code class="language-bash"><span class="token comment"># Initialize Terraform</span>
terraform init

<span class="token comment"># Create a plan</span>
terraform plan

<span class="token comment"># Apply the plan</span>
terraform apply
</code></pre>
<p>This will take a few minutes to complete. Once it's done, we can manually upload our static website to the S3 bucket.
You'll need to have the AWS CLI installed and configured and to copy the newly created S3 bucket name and CloudFront distribution ID.</p>
<pre class="language-bash"><code class="language-bash"><span class="token comment"># Remove the old files from S3 bucket</span>
aws s3 <span class="token function">rm</span> s3://<span class="token operator">&lt;</span>bucket-name<span class="token operator">&gt;</span> --recursive

<span class="token comment"># Upload the website to the S3 bucket</span>
aws s3 <span class="token function">sync</span> ./<span class="token operator">&lt;</span>dist-dir<span class="token operator">&gt;</span> s3://<span class="token operator">&lt;</span>bucket-name<span class="token operator">&gt;</span>

<span class="token comment"># Invalidate the CloudFront cache</span>
aws cloudfront create-invalidation --distribution-id <span class="token operator">&lt;</span>distribution-id<span class="token operator">&gt;</span> --paths <span class="token string">"/*"</span>
</code></pre>
<p>This should make our website available at the domain name we specified.</p>
<p>We could've made uploading of website as part of the Terraform script, but it isn't the responsibility of Terraform to manage the content of the bucket.
A better approach would be to use a CI/CD pipeline to automate the process of building and deploying the website, alongside keeping the infrastructure up to date.</p>
<h2>Aside: Using external domain registrar</h2>
<p>If you're using a domain registrar other than Route53, you'll need to create a CNAME record pointing to the CloudFront distribution
and a CNAME record for the ACM certificate. For that you'll need to modify the Terraform script and remove the <code>aws_route53_record</code> resources.</p>
<h3>Tear down</h3>
<p>When we're done with the website, we can tear down the infrastructure by running:</p>
<pre class="language-bash"><code class="language-bash">terraform destroy
</code></pre>
<p>This will remove all the resources we created. For the S3 buckets and DynamoDB table you will have to do a manual cleanup.</p>
<h2>Conclusion</h2>
<p>In this article, we've learned how to deploy a static website to AWS S3 and CloudFront. This process can be simplified by using
<a href="https://vercel.com/">Vercel</a> or <a href="https://www.netlify.com/">Netlify</a>, but their free plans have some limitations,
so it's good to know how to host on your own.</p>
<p>I didn't cover the process of writing the terraform script in detail, but I hope that this article will give you a good starting point for your own projects.
My recommendation is to use the <a href="https://registry.terraform.io/providers/hashicorp/aws/latest/docs">Terraform AWS docs</a> to figure out the available options.
Also, manually setting up the infrastructure and then writing the Terraform scripts is a good way to learn how Terraform works and what is required to provision the resources.</p>
<p>If you have any questions or suggestions, feel free to contact me.</p>]]></content:encoded>
            <author>anton@azdanov.dev (Anton Ždanov)</author>
        </item>
        <item>
            <title><![CDATA[Learning about dependency injection in C# and .NET]]></title>
            <link>https://www.azdanov.dev/articles/2023/learning-about-dependeny-injection-in-csharp-and-dotnet</link>
            <guid isPermaLink="false">https://www.azdanov.dev/articles/2023/learning-about-dependeny-injection-in-csharp-and-dotnet</guid>
            <pubDate>Wed, 12 Apr 2023 10:28:57 GMT</pubDate>
            <content:encoded><![CDATA[<p>Another course finished on my journey in learning C# and .NET. It was about one of the most important things in
modern software development - dependency injection. I've learned how to use it in C# and .NET, and how to
implement it in a real-world application. One chapter was about more advanced topics, such as using
<a href="https://github.com/khellang/Scrutor">Scrutor</a> to automatically register services.</p>
<blockquote>
<p>Scrutor — Assembly scanning and decoration extensions for Microsoft.Extensions.DependencyInjection</p>
</blockquote>
<p>It reminded me of the Spring Framework in Java, which has a similar feature called
<a href="https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-scanning-autodetection">@ComponentScan</a>.
It allows you to automatically register services in the container, which is very useful when you have a lot of
services and don't want to register them manually. Although one of the downsides of this approach is that it
can be hard to understand what services are registered in the container. And there is no quick way to find out
just by looking at the code as in <code>Program.cs</code> or <code>Startup.cs</code>.</p>
<p>As a side note, in Spring Boot, you don't have to explicitly specify this annotation because it's automatically
enabled when using <a href="https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#using.using-the-springbootapplication-annotation">@SpringBootApplication</a>.</p>
<p>The course I took was from <a href="https://nickchapsas.com/p/from-zero-to-hero-dependency-injection-in-net">Nick Chapsas - From Zero to Hero:
Dependency injection in .NET with C#</a>, a well-known YouTube instructor with many years of experience building production APIs in .NET.
I already finished his course about <a href="https://www.azdanov.dev/articles/2023/first-steps-restful-api-dotnet">REST APIs in .NET</a>, and I wasn't disappointed in the new course also.</p>
<p>The course covered some topics, including:</p>
<ul>
<li>Basic dependency injection and use cases</li>
<li>How to use ServiceCollection and ServiceProvider with different lifetimes</li>
<li>Resolving dependencies in different scenarios and projects</li>
<li>Advanced topics, such as using ServiceDescriptor, Add vs. TryAdd, Open Generics, and deep dive into lifetime scopes, etc.</li>
<li>Advanced techniques about custom scopes, decorators, avoiding service locator, and more</li>
<li>Introduction to Scrutor and ways it can simplify service registration with potential pitfalls</li>
<li>Creating your own minimal dependency injection framework by using a Dictionary</li>
</ul>
<p>After completing the course, I got another certificate. Here it is:</p>
<img alt="Certificate for completing From Zero to Hero: Dependency injection in .NET with C#" loading="lazy" width="1666" height="1338" decoding="async" data-nimg="1" style="color:transparent" srcset="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fdependency-injection-csharp-certificate.0ki_ag-o3y4ah.png&amp;w=1920&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fdependency-injection-csharp-certificate.0ki_ag-o3y4ah.png&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fdependency-injection-csharp-certificate.0ki_ag-o3y4ah.png&amp;w=3840&amp;q=75">
<p>It was a valuable investment to learn more about dependency injection in .NET and C#. If you have any questions or feedback, feel free to contact me.</p>]]></content:encoded>
            <author>anton@azdanov.dev (Anton Ždanov)</author>
        </item>
        <item>
            <title><![CDATA[Learning to build RESTful APIs with C# and .NET 7]]></title>
            <link>https://www.azdanov.dev/articles/2023/first-steps-restful-api-dotnet</link>
            <guid isPermaLink="false">https://www.azdanov.dev/articles/2023/first-steps-restful-api-dotnet</guid>
            <pubDate>Wed, 22 Mar 2023 19:11:39 GMT</pubDate>
            <content:encoded><![CDATA[<p>I started learning C# and .NET a few weeks ago and finished a course on building a modern RESTful API. I would like to share that I've finished a GitHub project and have a certificate from the website.</p>
<p>The course I took was from <a href="https://nickchapsas.com/p/from-zero-to-hero-rest-apis-in-asp-net-core">Nick Chapsas - From Zero to Hero:
REST APIs in .NET</a>, a well-known YouTube instructor with many years of experience building production APIs in .NET. It taught me how to create a REST API end-to-end from scratch using the latest .NET 7, Dapper and other libraries. The course uses the C# (obviously), which is one of my favorites and the reasons for switching from Java and Node.js.</p>
<p>The REST API I built is a simple movie app that allows users to create, read, update and delete movies and ratings associated with a movie. It uses ASP.NET, Dapper for data access, PostgreSQL
for database storage, and Swagger for documentation.</p>
<p>I've made a GitHub project that contains all the source code and instructions on how to run it locally. You can find it here: <a href="https://github.com/azdanov/MoviesApp">https://github.com/azdanov/MoviesApp</a></p>
<p>The course covered a bunch of topics, including:</p>
<ul>
<li>Basics of HTTP verbs and CRUD</li>
<li>Building a RESTful API with data validation</li>
<li>Authentication and authorization</li>
<li>User-specific actions</li>
<li>Filtering, sorting, pagination, versioning and swagger</li>
<li>Building an SDK and consuming the API</li>
<li>Minimal API</li>
</ul>
<p>After completing the course, I got a certificate, nice surprise. Here it is:</p>
<img alt="Certificate for completing From Zero to Hero:
REST APIs in .NET" loading="lazy" width="1906" height="1314" decoding="async" data-nimg="1" style="color:transparent" srcset="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fnick-chapsas-restful-certificate_imageoptim.02beb~0zku58~.png&amp;w=1920&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fnick-chapsas-restful-certificate_imageoptim.02beb~0zku58~.png&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fnick-chapsas-restful-certificate_imageoptim.02beb~0zku58~.png&amp;w=3840&amp;q=75">
<p>I really enjoyed this course and can recommend it to anyone who wants to learn how to create REST APIs with .NET 7 and C#. If you have any questions or feedback, feel free to contact me.</p>]]></content:encoded>
            <author>anton@azdanov.dev (Anton Ždanov)</author>
        </item>
        <item>
            <title><![CDATA[Using XACT_ABORT and NOCOUNT in SQL Server Procedures]]></title>
            <link>https://www.azdanov.dev/articles/2023/using-xact-abort-and-nocount-in-sql-server</link>
            <guid isPermaLink="false">https://www.azdanov.dev/articles/2023/using-xact-abort-and-nocount-in-sql-server</guid>
            <pubDate>Tue, 07 Mar 2023 13:39:09 GMT</pubDate>
            <content:encoded><![CDATA[<p>While learning about SQL Server stored procedures, I came across two statements that I had never seen before: XACT_ABORT and NOCOUNT.
I was curious about what they do, so I decided to learn more and to share my findings.</p>
<p>Generally speaking, XACT_ABORT is a transaction option that determines whether the transaction is rolled back when certain additional errors occur which isn't turned on for backwards compatibility and
NOCOUNT is a session option that determines whether the number of rows affected by a statement is returned to the client.</p>
<ul>
<li><strong>XACT_ABORT</strong> - Good for avoiding unexpected behavior connected to rolling back a transactions</li>
<li><strong>NOCOUNT</strong> - Good for performance if the procedure is used in a loop by eliminating a network call</li>
</ul>
<p>Here's a small example:</p>
<pre class="language-sql"><code class="language-sql"><span class="token keyword">CREATE</span> <span class="token keyword">PROCEDURE</span> <span class="token keyword">insert</span>
  <span class="token variable">@a</span> <span class="token keyword">int</span><span class="token punctuation">,</span>
  <span class="token variable">@b</span> <span class="token keyword">int</span>
<span class="token keyword">AS</span>
  <span class="token keyword">SET</span> XACT_ABORT<span class="token punctuation">,</span> NOCOUNT <span class="token keyword">ON</span><span class="token punctuation">;</span>
  <span class="token keyword">INSERT</span> <span class="token keyword">INTO</span> <span class="token keyword">table</span> <span class="token punctuation">(</span>a<span class="token punctuation">,</span> b<span class="token punctuation">)</span> <span class="token keyword">VALUES</span> <span class="token punctuation">(</span><span class="token variable">@a</span><span class="token punctuation">,</span> <span class="token variable">@b</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<p>Main resource that I used to learn more about these statements were from an article by <a href="https://www.sommarskog.se/error_handling/Part1.html">Erland Sommarskog - Error and Transaction Handling in SQL Server</a>.</p>]]></content:encoded>
            <author>anton@azdanov.dev (Anton Ždanov)</author>
        </item>
        <item>
            <title><![CDATA[Migrating to Next.js]]></title>
            <link>https://www.azdanov.dev/articles/2023/migrating-to-nextjs</link>
            <guid isPermaLink="false">https://www.azdanov.dev/articles/2023/migrating-to-nextjs</guid>
            <pubDate>Sun, 05 Mar 2023 09:51:39 GMT</pubDate>
            <content:encoded><![CDATA[<p>After a long time of using <a href="https://gohugo.io/">Hugo</a>, I decided to migrate my blog to <a href="https://nextjs.org/">Next.js</a>. There was nothing particularly wrong with Hugo,
but I wanted to try something new, and I was curious about Next.js. I also wanted to try out <a href="https://tailwindcss.com/">Tailwind CSS</a>, which I had heard a lot about.
I had a chance to use it at work, and I liked it a lot. And having a personal website is a perfect candidate for trying out new things.</p>
<p>For the theme, I decided to use <a href="https://tailwindui.com/">Tailwind UI</a> Spotlight, which is a paid theme offered as part
of Tailwind UI that is a component library made with Tailwind CSS. I modified it a bit to fit my needs. And will probably
continue to adjust it to my needs as I go.</p>
<p>Overall, I am very happy with the result. I like the way Next.js works and the theme looks fabulous. As a bonus, the
project uses the same language everywhere, which is a big plus. It was a bit difficult when there were some Go-specific
things while using Hugo.</p>
<h2>Aside: React Hydration Error</h2>
<p>While migrating I encountered this error:</p>
<pre class="language-text"><code class="language-text">Unhandled Runtime Error
Error: Hydration failed because the initial UI does not match what was rendered on the server.

See more info here: https://nextjs.org/docs/messages/react-hydration-error
</code></pre>
<p>Which documentation was very helpful in providing an example <code>Invalid HTML may cause hydration mismatch such as div inside p.</code>.</p>
<p>Unknowingly I previously had a <code>ul</code> inside a <code>p</code> tag, which caused the error, it wasn't a valid HTML, yet it is allowed for backwards compatibility.
An easy fix is to extract the <code>ul</code> from the <code>p</code> tag.</p>
<pre class="language-html"><code class="language-html"><span class="token comment">&lt;!-- Error --&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>
  Text
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ul</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">&gt;</span></span>First<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">&gt;</span></span>Second<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">&gt;</span></span>Third<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ul</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
<span class="token comment">&lt;!-- No error --&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>
  Text
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ul</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">&gt;</span></span>First<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">&gt;</span></span>Second<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">&gt;</span></span>Third<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ul</span><span class="token punctuation">&gt;</span></span>
</code></pre>
<p>I'm quite surprised and happy that Next.js helped me to learn more about writing correct HTML markup.</p>]]></content:encoded>
            <author>anton@azdanov.dev (Anton Ždanov)</author>
        </item>
        <item>
            <title><![CDATA[What is Cloud?]]></title>
            <link>https://www.azdanov.dev/articles/2022/what-is-cloud</link>
            <guid isPermaLink="false">https://www.azdanov.dev/articles/2022/what-is-cloud</guid>
            <pubDate>Sun, 16 Oct 2022 17:30:00 GMT</pubDate>
            <content:encoded><![CDATA[<p>Essential characteristics of a cloud according to <a href="https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-145.pdf">NIST Special Publication 800-145</a>:</p>
<ol>
<li><strong>On-demand Self-Service</strong>. Can provision capabilities as needed <em>without requiring human interaction</em> with each service provider.</li>
<li><strong>Broad Network Access</strong>. Capabilities are available over the <em>network</em> and accessed through <em>standard mechanisms</em> that promote use by heterogeneous thin or thick client platforms (e.g., mobile phones, laptops, and workstations).</li>
<li><strong>Resource Pooling</strong>. The provider's computing resources are <em>pooled</em> to serve multiple consumers using a <em>multi-tenant model</em>, with different physical and virtual resources dynamically assigned and reassigned according to consumer demand. There is a sense of <em>location independence</em> in that the customer generally has no <em>control</em> or <em>knowledge</em> over the exact <em>location</em> of the provided resources but may be able to specify location at a higher level of abstraction (e.g., country, state, or datacenter). Examples of resources include storage, processing, memory, and network bandwidth.</li>
<li><strong>Rapid Elasticity</strong>. Capabilities can be <em>elastically provisioned</em> and <em>released</em>, in some cases automatically, to scale <em>rapidly</em> outward and inward commensurate with demand. To the consumer, the capabilities available for provisioning often <em>appear</em> to be <em>unlimited</em> and can be appropriated in any quantity at any time.</li>
<li><strong>Measured Service</strong>. Cloud systems automatically control and optimize resource use by leveraging a metering capability at some level of abstraction appropriate to the type of service (e.g., storage, processing, bandwidth, and active user accounts). Resource usage can be <em>monitored</em>, <em>controlled</em>, <em>reported</em> and <em>billed</em> providing transparency for both the provider and consumer of the utilized service.</li>
</ol>
<p>Summary:</p>
<ol>
<li><strong>On-demand Self-Service</strong>: Create and terminate resources through UI/CLI without human interaction.</li>
<li><strong>Broad Network Access</strong>: Access resources over any network and any device using standard methods.</li>
<li><strong>Resource Pooling</strong>: Due to combining of resources, the provider can offer resources at a lower cost.</li>
<li><strong>Rapid Elasticity</strong>: Automatically scale resources up and down based on demand.</li>
<li><strong>Measured Service</strong>: Usage of resources is measured and billed for what you consume.</li>
</ol>]]></content:encoded>
            <author>anton@azdanov.dev (Anton Ždanov)</author>
        </item>
        <item>
            <title><![CDATA[Easy Development Certificates (SSL/TLS) for Spring Boot]]></title>
            <link>https://www.azdanov.dev/articles/2021/easy-development-certificate-for-spring-boot</link>
            <guid isPermaLink="false">https://www.azdanov.dev/articles/2021/easy-development-certificate-for-spring-boot</guid>
            <pubDate>Sat, 15 May 2021 20:17:18 GMT</pubDate>
            <content:encoded><![CDATA[<p>Lately I've been digging into Spring Security by reading a book "Spring Security in Action" by Laurentiu Spilca.</p>
<p>In the 2nd chapter we are given an example of how to use HTTPS with spring boot:</p>
<ol>
<li>
<p>Generate a certificate: <code>openssl req -newkey rsa:2048 -x509 -keyout key.pem -out cert.pem -days 365</code></p>
</li>
<li>
<p>Convert it to 'p12' format: <code>openssl pkcs12 -export -in cert.pem -inkey key.pem -out certificate.p12 -name "certificate"</code></p>
</li>
<li>
<p>Copy the generated 'certificate.p12' file inside 'src/main/resources' directory.</p>
</li>
<li>
<p>Update 'application.properties':</p>
<pre class="language-properties"><code class="language-properties"><span class="token attr-name">server.ssl.key-store-type</span><span class="token punctuation">=</span><span class="token attr-value">PKCS12</span>
<span class="token attr-name">server.ssl.key-store</span><span class="token punctuation">=</span><span class="token attr-value">classpath:certificate.p12</span>
<span class="token attr-name">server.ssl.key-store-password</span><span class="token punctuation">=</span><span class="token attr-value">12345</span>
</code></pre>
</li>
</ol>
<p>One problem with this approach is that such certificates are not recognized by browsers, which will show an indicator that "this certificate is not trustworthy".</p>
<p>An easy workaround involves using a tool <strong>mkcert</strong>: <a href="https://github.com/FiloSottile/mkcert">https://github.com/FiloSottile/mkcert</a></p>
<p>With simple installation for macOS as an example:</p>
<pre class="language-bash"><code class="language-bash"><span class="token comment"># Install</span>
brew <span class="token function">install</span> mkcert
brew <span class="token function">install</span> nss <span class="token comment"># if you use Firefox</span>

<span class="token comment"># Setup local certificate authority (CA)</span>
mkcert -install

<span class="token comment"># Generate certificate</span>
mkcert -pkcs12 localhost <span class="token number">127.0</span>.0.1
</code></pre>
<p>This will generate a new p12 ('localhost+2.p12') certificate for localhost and 127.0.0.1 in current directory that will be registered in local certificate authority (CA) which will keep browsers happy when doing local development.</p>
<p>The rest of the steps is the same, copy into 'src/main/resources' and update 'application.properties'.</p>]]></content:encoded>
            <author>anton@azdanov.dev (Anton Ždanov)</author>
        </item>
        <item>
            <title><![CDATA[Multiple PostgreSQL Databases in Docker]]></title>
            <link>https://www.azdanov.dev/articles/2021/multiple-postgres-databases-in-docker</link>
            <guid isPermaLink="false">https://www.azdanov.dev/articles/2021/multiple-postgres-databases-in-docker</guid>
            <pubDate>Fri, 07 May 2021 14:06:12 GMT</pubDate>
            <content:encoded><![CDATA[<p>When using Postgres in docker-compose sometimes I have a need to create multiple databases for a demo project, but sadly only a <code>POSTGRES_DB</code> environment variable is available for a single database.</p>
<p>Luckily, it's possible to define an initialization script that can help us out.
The only inconvenience is in mounting a whole directory, since there is no easy way to mount a single file in Docker.</p>
<p>Here's how my <code>docker-compose.yml</code> looks:</p>
<ul>
<li>A directory <code>pg-init-scripts</code> that contains the initialization script is mounted into the docker container</li>
<li>A custom environment variable <code>POSTGRES_MULTIPLE_DATABASES</code> is created with database names to be initialized</li>
</ul>
<pre class="language-yml"><code class="language-yml"><span class="token key atrule">version</span><span class="token punctuation">:</span> <span class="token string">"3.8"</span>
<span class="token key atrule">services</span><span class="token punctuation">:</span>
  <span class="token key atrule">postgres</span><span class="token punctuation">:</span>
    <span class="token key atrule">image</span><span class="token punctuation">:</span> <span class="token string">"postgres:13.2-alpine"</span>
    <span class="token key atrule">container_name</span><span class="token punctuation">:</span> postgres
    <span class="token key atrule">ports</span><span class="token punctuation">:</span>
      <span class="token punctuation">-</span> 5432<span class="token punctuation">:</span><span class="token number">5432</span>
    <span class="token key atrule">volumes</span><span class="token punctuation">:</span>
      <span class="token punctuation">-</span> ./pg<span class="token punctuation">-</span>init<span class="token punctuation">-</span>scripts<span class="token punctuation">:</span>/docker<span class="token punctuation">-</span>entrypoint<span class="token punctuation">-</span>initdb.d
    <span class="token key atrule">environment</span><span class="token punctuation">:</span>
      <span class="token punctuation">-</span> POSTGRES_USER=postgres
      <span class="token punctuation">-</span> POSTGRES_PASSWORD=root
      <span class="token punctuation">-</span> POSTGRES_MULTIPLE_DATABASES=accounts<span class="token punctuation">,</span>bills<span class="token punctuation">,</span>deposits
</code></pre>
<p>Now inside <code>pg-init-scripts</code> directory there is a script <code>create_dbs.sh</code>:</p>
<ul>
<li>Inside the script <code>POSTGRES_USER</code> is used as root user</li>
<li>While <code>POSTGRES_MULTIPLE_DATABASES</code> is split on <code>,</code></li>
</ul>
<pre class="language-bash"><code class="language-bash"><span class="token shebang important">#!/bin/bash</span>

<span class="token builtin class-name">set</span> -e
<span class="token builtin class-name">set</span> -u

<span class="token keyword">function</span> <span class="token function-name function">create_user_and_database</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token builtin class-name">local</span> <span class="token assign-left variable">database</span><span class="token operator">=</span><span class="token variable">$1</span>
    <span class="token builtin class-name">echo</span> <span class="token string">"Creating user and database '<span class="token variable">$database</span>'"</span>
    psql -v <span class="token assign-left variable">ON_ERROR_STOP</span><span class="token operator">=</span><span class="token number">1</span> --username <span class="token string">"<span class="token variable">$POSTGRES_USER</span>"</span> <span class="token operator">&lt;&lt;-</span><span class="token string">EOSQL
      CREATE USER <span class="token variable">$database</span>;
      CREATE DATABASE <span class="token variable">$database</span>;
      GRANT ALL PRIVILEGES ON DATABASE <span class="token variable">$database</span> TO <span class="token variable">$database</span>;
EOSQL</span>
<span class="token punctuation">}</span>

<span class="token keyword">if</span> <span class="token punctuation">[</span> -n <span class="token string">"<span class="token variable">$POSTGRES_MULTIPLE_DATABASES</span>"</span> <span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">then</span>
    <span class="token builtin class-name">echo</span> <span class="token string">"Creating databases: <span class="token variable">$POSTGRES_MULTIPLE_DATABASES</span>"</span>
    <span class="token keyword">for</span> <span class="token for-or-select variable">db</span> <span class="token keyword">in</span> <span class="token variable"><span class="token variable">$(</span><span class="token builtin class-name">echo</span> <span class="token string">"<span class="token variable">$POSTGRES_MULTIPLE_DATABASES</span>"</span> <span class="token operator">|</span> <span class="token function">tr</span> <span class="token string">','</span> <span class="token string">' '</span><span class="token variable">)</span></span><span class="token punctuation">;</span> <span class="token keyword">do</span>
        create_user_and_database <span class="token string">"<span class="token variable">$db</span>"</span>
    <span class="token keyword">done</span>
    <span class="token builtin class-name">echo</span> <span class="token string">"Multiple databases created"</span>
<span class="token keyword">fi</span>
</code></pre>
<p>Try it out and see if it helps you.</p>
<p>Here's the reference to PostgreSQL Docker image: <a href="https://hub.docker.com/_/postgres/">https://hub.docker.com/_/postgres/</a> with more information about initialization scripts.</p>]]></content:encoded>
            <author>anton@azdanov.dev (Anton Ždanov)</author>
        </item>
        <item>
            <title><![CDATA[Migrating to Hugo]]></title>
            <link>https://www.azdanov.dev/articles/2021/migrating-to-hugo</link>
            <guid isPermaLink="false">https://www.azdanov.dev/articles/2021/migrating-to-hugo</guid>
            <pubDate>Mon, 03 May 2021 15:16:39 GMT</pubDate>
            <content:encoded><![CDATA[<p>My last update to this website was a migration from <a href="https://www.gatsbyjs.com/">Gatsby</a> with a custom made theme to <a href="https://www.11ty.dev/">11ty</a> with modified <a href="https://github.com/google/eleventy-high-performance-blog">eleventy-high-performance-blog</a> theme. And while it was very educational and inspiring to see what kind of performance improvements were possible the theme itself became a bit difficult to manage, requiring a lot of maintenance.</p>
<p>After trying out Go for hobby projects I've been intrigued with a static site generator <a href="https://gohugo.io/">Hugo</a> and decided to try it with a custom theme <a href="https://github.com/rhazdon/hugo-theme-hello-friend-ng">hello-friend-ng</a>.</p>
<p>The end result was very satisfying. It was easy to setup, build time is lightning fast and thus far, I assume, maintenance will be also minimal.</p>
<p>Let's see if I will focus more time on writing and less on resolving merge conflicts or npm updates for my website. 😄</p>]]></content:encoded>
            <author>anton@azdanov.dev (Anton Ždanov)</author>
        </item>
        <item>
            <title><![CDATA[Configuring EhCache 3 and Event Listeners in Spring Boot]]></title>
            <link>https://www.azdanov.dev/articles/2020/configuring-ehcache-3-and-event-listeners-in-spring-boot</link>
            <guid isPermaLink="false">https://www.azdanov.dev/articles/2020/configuring-ehcache-3-and-event-listeners-in-spring-boot</guid>
            <pubDate>Sat, 19 Sep 2020 06:32:29 GMT</pubDate>
            <content:encoded><![CDATA[<p><strong>TLDR:</strong> You can jump straight to an example project <a href="https://github.com/azdanov/ehcache-config-demo">azdanov/ehcache-config-demo</a>.</p>
<p>Spring offers amazing caching utilities. Throw in some <code>@EnableCaching</code>, <code>@Cacheable</code>, <code>@CacheEvict</code> on and the results will be cached. You can read more about Spring Caching on <a href="https://www.baeldung.com/spring-cache-tutorial">https://www.baeldung.com/spring-cache-tutorial</a>.</p>
<p>The problem that I encountered was figuring out how to use EhCache 3 (<code>org.ehcache</code>) and inside Spring Boot with Java Based Configuration. A lot of how-to guides were either showing <code>ehcache.xml</code> or an older EhCache 2 (<code>net.sf.ehcache</code>) configuration convention.</p>
<p>Let's see how to do configure EhCache 3 <mark>programmatically</mark>.</p>
<h2>Setup</h2>
<p>First step is adding required dependencies to the project (Maven/Gradle):</p>
<pre class="language-xml"><code class="language-xml"><span class="token comment">&lt;!-- pom.xml --&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependencies</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>org.springframework.boot<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>spring-boot-starter-cache<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>org.ehcache<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>ehcache<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>version</span><span class="token punctuation">&gt;</span></span>3.9.0<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>version</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>javax.cache<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>cache-api<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>version</span><span class="token punctuation">&gt;</span></span>1.1.1<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>version</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependencies</span><span class="token punctuation">&gt;</span></span>
</code></pre>
<p>or</p>
<pre class="language-groovy"><code class="language-groovy"><span class="token comment">// build.gradle</span>
dependencies <span class="token punctuation">{</span>
  implementation <span class="token string">'org.springframework.boot:spring-boot-starter-cache'</span>
  implementation <span class="token string">'org.ehcache:ehcache:3.9.0'</span>
  implementation <span class="token string">'javax.cache:cache-api:1.1.1'</span>
<span class="token punctuation">}</span>
</code></pre>
<h2>Configuration</h2>
<p>Next step would be creating a configuration class:</p>
<pre class="language-java"><code class="language-java"><span class="token keyword">package</span> <span class="token namespace">org<span class="token punctuation">.</span>js<span class="token punctuation">.</span>azdanov<span class="token punctuation">.</span>ehcacheconfigdemo<span class="token punctuation">.</span>configuration</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>ehcache<span class="token punctuation">.</span>config<span class="token punctuation">.</span>builders<span class="token punctuation">.</span></span><span class="token class-name">CacheConfigurationBuilder</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>ehcache<span class="token punctuation">.</span>config<span class="token punctuation">.</span>builders<span class="token punctuation">.</span></span><span class="token class-name">ExpiryPolicyBuilder</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>ehcache<span class="token punctuation">.</span>config<span class="token punctuation">.</span>builders<span class="token punctuation">.</span></span><span class="token class-name">ResourcePoolsBuilder</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>ehcache<span class="token punctuation">.</span>jsr107<span class="token punctuation">.</span></span><span class="token class-name">Eh107Configuration</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>boot<span class="token punctuation">.</span>autoconfigure<span class="token punctuation">.</span>cache<span class="token punctuation">.</span></span><span class="token class-name">JCacheManagerCustomizer</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>cache<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">EnableCaching</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>context<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">Bean</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>context<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">Configuration</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token namespace">javax<span class="token punctuation">.</span>cache<span class="token punctuation">.</span></span><span class="token class-name">Cache</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">javax<span class="token punctuation">.</span>cache<span class="token punctuation">.</span></span><span class="token class-name">CacheManager</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">javax<span class="token punctuation">.</span>cache<span class="token punctuation">.</span>configuration<span class="token punctuation">.</span></span><span class="token class-name">CacheEntryListenerConfiguration</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">javax<span class="token punctuation">.</span>cache<span class="token punctuation">.</span>configuration<span class="token punctuation">.</span></span><span class="token class-name">Factory</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">javax<span class="token punctuation">.</span>cache<span class="token punctuation">.</span>configuration<span class="token punctuation">.</span></span><span class="token class-name">FactoryBuilder</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">javax<span class="token punctuation">.</span>cache<span class="token punctuation">.</span>configuration<span class="token punctuation">.</span></span><span class="token class-name">MutableCacheEntryListenerConfiguration</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">javax<span class="token punctuation">.</span>cache<span class="token punctuation">.</span>event<span class="token punctuation">.</span></span><span class="token class-name">CacheEntryEventFilter</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>time<span class="token punctuation">.</span></span><span class="token class-name">Duration</span><span class="token punctuation">;</span>

<span class="token annotation punctuation">@EnableCaching</span>
<span class="token annotation punctuation">@Configuration</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">CacheConfiguration</span> <span class="token punctuation">{</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token class-name">Factory</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span> <span class="token keyword">extends</span> <span class="token class-name">CacheEntryEventFilter</span><span class="token punctuation">&lt;</span><span class="token class-name">Integer</span><span class="token punctuation">,</span> <span class="token class-name">Integer</span><span class="token punctuation">&gt;</span><span class="token punctuation">&gt;</span></span> NO_FILTER <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token keyword">boolean</span> IS_OLD_VALUE_REQUIRED <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token keyword">boolean</span> IS_SYNCHRONOUS <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span>

    <span class="token comment">// (1)</span>
    <span class="token keyword">private</span> <span class="token keyword">final</span> <span class="token class-name"><span class="token namespace">javax<span class="token punctuation">.</span>cache<span class="token punctuation">.</span>configuration<span class="token punctuation">.</span></span>Configuration</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Integer</span><span class="token punctuation">,</span> <span class="token class-name">Integer</span><span class="token punctuation">&gt;</span></span> jcacheConfiguration <span class="token operator">=</span>
        <span class="token class-name">Eh107Configuration</span><span class="token punctuation">.</span><span class="token function">fromEhcacheCacheConfiguration</span><span class="token punctuation">(</span>
            <span class="token class-name">CacheConfigurationBuilder</span>
                <span class="token punctuation">.</span><span class="token function">newCacheConfigurationBuilder</span><span class="token punctuation">(</span><span class="token class-name">Integer</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token class-name">Integer</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token class-name">ResourcePoolsBuilder</span><span class="token punctuation">.</span><span class="token function">heap</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
                <span class="token punctuation">.</span><span class="token function">withExpiry</span><span class="token punctuation">(</span><span class="token class-name">ExpiryPolicyBuilder</span><span class="token punctuation">.</span><span class="token function">timeToLiveExpiration</span><span class="token punctuation">(</span><span class="token class-name">Duration</span><span class="token punctuation">.</span><span class="token function">ofMinutes</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
                <span class="token punctuation">.</span><span class="token function">build</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
        <span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token class-name">CacheEntryListenerConfiguration</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Integer</span><span class="token punctuation">,</span> <span class="token class-name">Integer</span><span class="token punctuation">&gt;</span></span> listenerConfiguration <span class="token operator">=</span>
        <span class="token keyword">new</span> <span class="token class-name">MutableCacheEntryListenerConfiguration</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span>
            <span class="token class-name">FactoryBuilder</span><span class="token punctuation">.</span><span class="token function">factoryOf</span><span class="token punctuation">(</span><span class="token class-name">CacheListener</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
            NO_FILTER<span class="token punctuation">,</span>
            IS_OLD_VALUE_REQUIRED<span class="token punctuation">,</span>
            IS_SYNCHRONOUS<span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token comment">// (2)</span>
    <span class="token annotation punctuation">@Bean</span>
    <span class="token keyword">public</span> <span class="token class-name">JCacheManagerCustomizer</span> <span class="token function">cacheManagerCustomizer</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> cm <span class="token operator">-&gt;</span> <span class="token punctuation">{</span>
            <span class="token function">createCache</span><span class="token punctuation">(</span>cm<span class="token punctuation">,</span> <span class="token string">"worker1"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token function">createCache</span><span class="token punctuation">(</span>cm<span class="token punctuation">,</span> <span class="token string">"worker2"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">createCache</span><span class="token punctuation">(</span><span class="token class-name">CacheManager</span> cm<span class="token punctuation">,</span> <span class="token class-name">String</span> cacheName<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">Cache</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Integer</span><span class="token punctuation">,</span> <span class="token class-name">Integer</span><span class="token punctuation">&gt;</span></span> cache <span class="token operator">=</span> cm<span class="token punctuation">.</span><span class="token function">getCache</span><span class="token punctuation">(</span>cacheName<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>cache <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            cm<span class="token punctuation">.</span><span class="token function">createCache</span><span class="token punctuation">(</span>cacheName<span class="token punctuation">,</span> jcacheConfiguration<span class="token punctuation">)</span>
                <span class="token punctuation">.</span><span class="token function">registerCacheEntryListener</span><span class="token punctuation">(</span>listenerConfiguration<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<ol>
<li>Here's the configuration itself, which can be modified to read the values from an <code>application.properties</code> file or any other resource.</li>
<li>Inside <code>JCacheManagerCustomizer</code> bean the individual cache creation happens.</li>
</ol>
<p>I've added some extras where a cache event listener will be registered for each created cache.</p>
<p>Here's how a listener class might look like:</p>
<pre class="language-java"><code class="language-java"><span class="token keyword">package</span> <span class="token namespace">org<span class="token punctuation">.</span>js<span class="token punctuation">.</span>azdanov<span class="token punctuation">.</span>ehcacheconfigdemo<span class="token punctuation">.</span>configuration</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token namespace">lombok<span class="token punctuation">.</span>extern<span class="token punctuation">.</span>slf4j<span class="token punctuation">.</span></span><span class="token class-name">Slf4j</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token namespace">javax<span class="token punctuation">.</span>cache<span class="token punctuation">.</span>event<span class="token punctuation">.</span></span><span class="token class-name">CacheEntryCreatedListener</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">javax<span class="token punctuation">.</span>cache<span class="token punctuation">.</span>event<span class="token punctuation">.</span></span><span class="token class-name">CacheEntryEvent</span><span class="token punctuation">;</span>

<span class="token annotation punctuation">@Slf4j</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">CacheListener</span> <span class="token keyword">implements</span> <span class="token class-name">CacheEntryCreatedListener</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Integer</span><span class="token punctuation">,</span> <span class="token class-name">Integer</span><span class="token punctuation">&gt;</span></span> <span class="token punctuation">{</span>

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">onCreated</span><span class="token punctuation">(</span><span class="token keyword">final</span> <span class="token class-name">Iterable</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">CacheEntryEvent</span><span class="token punctuation">&lt;</span><span class="token operator">?</span> <span class="token keyword">extends</span> <span class="token class-name">Integer</span><span class="token punctuation">,</span> <span class="token operator">?</span> <span class="token keyword">extends</span> <span class="token class-name">Integer</span><span class="token punctuation">&gt;</span><span class="token punctuation">&gt;</span></span> cacheEntryEvents<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">CacheEntryEvent</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span> <span class="token keyword">extends</span> <span class="token class-name">Integer</span><span class="token punctuation">,</span> <span class="token operator">?</span> <span class="token keyword">extends</span> <span class="token class-name">Integer</span><span class="token punctuation">&gt;</span></span> entryEvent <span class="token operator">:</span> cacheEntryEvents<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            log<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">"Cached key: {}, with value: {}"</span><span class="token punctuation">,</span> entryEvent<span class="token punctuation">.</span><span class="token function">getKey</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> entryEvent<span class="token punctuation">.</span><span class="token function">getValue</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>Now for the last step let's mark methods inside a service with previously defined cache names:</p>
<pre class="language-java"><code class="language-java"><span class="token keyword">package</span> <span class="token namespace">org<span class="token punctuation">.</span>js<span class="token punctuation">.</span>azdanov<span class="token punctuation">.</span>ehcacheconfigdemo<span class="token punctuation">.</span>service</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token namespace">lombok<span class="token punctuation">.</span></span><span class="token class-name">RequiredArgsConstructor</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>cache<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">Cacheable</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>stereotype<span class="token punctuation">.</span></span><span class="token class-name">Service</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span><span class="token class-name">Random</span><span class="token punctuation">;</span>

<span class="token annotation punctuation">@RequiredArgsConstructor</span>
<span class="token annotation punctuation">@Service</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">WorkerService</span> <span class="token punctuation">{</span>

    <span class="token keyword">private</span> <span class="token keyword">final</span> <span class="token class-name">Random</span> random<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Cacheable</span><span class="token punctuation">(</span>value <span class="token operator">=</span> <span class="token string">"worker1"</span><span class="token punctuation">,</span> key <span class="token operator">=</span> <span class="token string">"#bound"</span><span class="token punctuation">)</span>
    <span class="token keyword">public</span> <span class="token keyword">int</span> <span class="token function">getFirstWork</span><span class="token punctuation">(</span><span class="token keyword">int</span> bound<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> random<span class="token punctuation">.</span><span class="token function">nextInt</span><span class="token punctuation">(</span>bound<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token annotation punctuation">@Cacheable</span><span class="token punctuation">(</span>value <span class="token operator">=</span> <span class="token string">"worker2"</span><span class="token punctuation">,</span> key <span class="token operator">=</span> <span class="token string">"#bound"</span><span class="token punctuation">)</span>
    <span class="token keyword">public</span> <span class="token keyword">int</span> <span class="token function">getSecondWork</span><span class="token punctuation">(</span><span class="token keyword">int</span> bound<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> random<span class="token punctuation">.</span><span class="token function">nextInt</span><span class="token punctuation">(</span>bound<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<h2>Last step</h2>
<p>It's time to see if this works or not with a simple sanity-check 'test':</p>
<pre class="language-java"><code class="language-java"><span class="token keyword">package</span> <span class="token namespace">org<span class="token punctuation">.</span>js<span class="token punctuation">.</span>azdanov<span class="token punctuation">.</span>ehcacheconfigdemo</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token namespace">lombok<span class="token punctuation">.</span>extern<span class="token punctuation">.</span>slf4j<span class="token punctuation">.</span></span><span class="token class-name">Slf4j</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>js<span class="token punctuation">.</span>azdanov<span class="token punctuation">.</span>ehcacheconfigdemo<span class="token punctuation">.</span>service<span class="token punctuation">.</span></span><span class="token class-name">WorkerService</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>beans<span class="token punctuation">.</span>factory<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">Autowired</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>boot<span class="token punctuation">.</span></span><span class="token class-name">SpringApplication</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>boot<span class="token punctuation">.</span>autoconfigure<span class="token punctuation">.</span></span><span class="token class-name">SpringBootApplication</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>boot<span class="token punctuation">.</span>context<span class="token punctuation">.</span>event<span class="token punctuation">.</span></span><span class="token class-name">ApplicationReadyEvent</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>cache<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">EnableCaching</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>context<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">Bean</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>context<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">Configuration</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>context<span class="token punctuation">.</span>event<span class="token punctuation">.</span></span><span class="token class-name">EventListener</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span><span class="token class-name">Random</span><span class="token punctuation">;</span>

<span class="token annotation punctuation">@Slf4j</span>
<span class="token annotation punctuation">@EnableCaching</span>
<span class="token annotation punctuation">@Configuration</span>
<span class="token annotation punctuation">@SpringBootApplication</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">EhcacheConfigDemoApplication</span> <span class="token punctuation">{</span>

    <span class="token annotation punctuation">@Autowired</span>
    <span class="token class-name">WorkerService</span> workerService<span class="token punctuation">;</span>

    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">SpringApplication</span><span class="token punctuation">.</span><span class="token function">run</span><span class="token punctuation">(</span><span class="token class-name">EhcacheConfigDemoApplication</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">,</span> args<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token annotation punctuation">@Bean</span>
    <span class="token class-name">Random</span> <span class="token function">random</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Random</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token annotation punctuation">@EventListener</span><span class="token punctuation">(</span><span class="token class-name">ApplicationReadyEvent</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">afterStartup</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        log<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">"Running!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        log<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">"getFirstWork(100): {}"</span><span class="token punctuation">,</span> workerService<span class="token punctuation">.</span><span class="token function">getFirstWork</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        log<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">"getFirstWork(50): {}"</span><span class="token punctuation">,</span> workerService<span class="token punctuation">.</span><span class="token function">getFirstWork</span><span class="token punctuation">(</span><span class="token number">50</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        log<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">"getFirstWork(100): {}"</span><span class="token punctuation">,</span> workerService<span class="token punctuation">.</span><span class="token function">getFirstWork</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        log<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">"getFirstWork(50): {}"</span><span class="token punctuation">,</span> workerService<span class="token punctuation">.</span><span class="token function">getFirstWork</span><span class="token punctuation">(</span><span class="token number">50</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        log<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">"getSecondWork(100): {}"</span><span class="token punctuation">,</span> workerService<span class="token punctuation">.</span><span class="token function">getSecondWork</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        log<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">"getSecondWork(50): {}"</span><span class="token punctuation">,</span> workerService<span class="token punctuation">.</span><span class="token function">getSecondWork</span><span class="token punctuation">(</span><span class="token number">50</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        log<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">"getSecondWork(100): {}"</span><span class="token punctuation">,</span> workerService<span class="token punctuation">.</span><span class="token function">getSecondWork</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        log<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">"getSecondWork(50): {}"</span><span class="token punctuation">,</span> workerService<span class="token punctuation">.</span><span class="token function">getSecondWork</span><span class="token punctuation">(</span><span class="token number">50</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>This is the result I got in the terminal:</p>
<pre class="language-text"><code class="language-text">Running!
Cached key: 100, with value: 8
getFirstWork(100): 8
Cached key: 50, with value: 29
getFirstWork(50): 29
getFirstWork(100): 8
getFirstWork(50): 29
Cached key: 100, with value: 6
getSecondWork(100): 6
Cached key: 50, with value: 33
getSecondWork(50): 33
getSecondWork(100): 6
getSecondWork(50): 33
</code></pre>
<p>Seems to be working 🙂</p>]]></content:encoded>
            <author>anton@azdanov.dev (Anton Ždanov)</author>
        </item>
        <item>
            <title><![CDATA[Migrating to 11ty]]></title>
            <link>https://www.azdanov.dev/articles/2020/migrating-to-11ty</link>
            <guid isPermaLink="false">https://www.azdanov.dev/articles/2020/migrating-to-11ty</guid>
            <pubDate>Sat, 12 Sep 2020 12:44:11 GMT</pubDate>
            <content:encoded><![CDATA[<p>After getting hired I have been busy at work. Learning all the new things to become productive and productive team member.</p>
<p>Sadly this led to neglecting my website for a while... Not any longer.</p>
<p>I have decided to freshen up my blog and moving away from <a href="https://www.gatsbyjs.com/">Gatsby</a>.
The main reason is simplicity, because <a href="https://www.11ty.dev/">11ty</a> offers simple solution for a simple blog without the complexity of GraphQL or React.</p>
<p>Special thanks to <a href="https://x.com/cramforce">cramforce</a> for creating <a href="https://github.com/google/eleventy-high-performance-blog">eleventy-high-performance-blog</a> starter kit.</p>]]></content:encoded>
            <author>anton@azdanov.dev (Anton Ždanov)</author>
        </item>
        <item>
            <title><![CDATA[Huge Milestone: Getting Hired]]></title>
            <link>https://www.azdanov.dev/articles/2019/huge-milestone-getting-hired</link>
            <guid isPermaLink="false">https://www.azdanov.dev/articles/2019/huge-milestone-getting-hired</guid>
            <pubDate>Sun, 02 Jun 2019 21:07:06 GMT</pubDate>
            <content:encoded><![CDATA[<img alt="balloons" loading="lazy" width="1200" height="630" decoding="async" data-nimg="1" style="color:transparent" srcset="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fballoons.0y-~ubtwandh~.png&amp;w=1200&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fballoons.0y-~ubtwandh~.png&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fballoons.0y-~ubtwandh~.png&amp;w=3840&amp;q=75">
<p>After ~3 years of studying, building, learning and pushing forward every day, I've decided that my knowledge has reached the level adequate for working in professional development.</p>
<p>I've started sending out my résumé to local companies, and to my delight, I didn't have to wait long. Several offered a chance for an interview by building a small test project. The interviews went well, and I had to choose which role and technology stack to work with.</p>
<p>In the end, the company that I'm working for is using a Java and Vue.js stack for their projects. My role is as a Full Stack Developer.</p>
<h2>Encouragements</h2>
<p>For those who are studying either in a university or on their own, the only advice I can give is not to give up. Sooner or later you will reach your set goals. And the only way there is one step at a time.</p>]]></content:encoded>
            <author>anton@azdanov.dev (Anton Ždanov)</author>
        </item>
        <item>
            <title><![CDATA[Interview Exercises: The TDD Way]]></title>
            <link>https://www.azdanov.dev/articles/2019/interview_exercises_tdd_way</link>
            <guid isPermaLink="false">https://www.azdanov.dev/articles/2019/interview_exercises_tdd_way</guid>
            <pubDate>Sat, 27 Apr 2019 10:35:28 GMT</pubDate>
            <content:encoded><![CDATA[<img alt="TDD" loading="lazy" width="1200" height="630" decoding="async" data-nimg="1" style="color:transparent" srcset="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Ftdd.01hptpyr8et5k.png&amp;w=1200&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Ftdd.01hptpyr8et5k.png&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Ftdd.01hptpyr8et5k.png&amp;w=3840&amp;q=75">
<p>I'll be honest with you, I suck at algorithms and data structures. Trying to figure the proper approach is a difficult and brain-frying endeavor. And don't get me started on the recursion, which makes everything 10x more challenging to reason about.</p>
<p><a href="https://github.com/azdanov/php-interview-exercises">GitHub for PHP Interview Exercises</a></p>
<p>Luckily things get easier with experience, repetition and simple know-how. Old challenges that seemed insurmountable become easier to reason about. That's why I love to return and rehearse some basic algorithms and data structures from time to time. It just makes you feel better when you finally understand how a linked list works, or a tree traversal is accomplished.</p>
<h2>Test-driven development</h2>
<p><a href="https://en.wikipedia.org/wiki/Test-driven_development">Wikipedia for TDD</a></p>
<p>This time I wanted to try a TDD approach (more or less.) By writing a test first, and the implementation with possible refactor it is easier to solve a problem. Instead of staring into an empty code editor you start writing and thinking about the problem.</p>
<p>To write a proper test you need to:</p>
<ul>
<li>Understand the problem (What is my goal)</li>
<li>Explore test cases (Find proper input and output)</li>
</ul>
<p>And already half of the problem is solved. Now what rests is to create a solution.</p>
<p>What we can do now is:</p>
<ul>
<li>Break the problem down into smaller chunks &amp; solve it</li>
<li>Simplify once all the test are green</li>
<li>Look &amp; Refactor for performance (Remember that premature optimization is bad)</li>
</ul>
<p>Problem-solving is an important skill to hone for a developer. By practicing on smaller chunks of code it is easier to gauge one's level and simply stay motivated.</p>
<p>Happy coding!</p>]]></content:encoded>
            <author>anton@azdanov.dev (Anton Ždanov)</author>
        </item>
        <item>
            <title><![CDATA[Must watch videos 1]]></title>
            <link>https://www.azdanov.dev/articles/2019/must-watch-videos-1</link>
            <guid isPermaLink="false">https://www.azdanov.dev/articles/2019/must-watch-videos-1</guid>
            <pubDate>Fri, 05 Apr 2019 21:31:48 GMT</pubDate>
            <content:encoded><![CDATA[<img alt="video" loading="lazy" width="1200" height="630" decoding="async" data-nimg="1" style="color:transparent" srcset="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fvideo.0mbv_p06l-bfs.png&amp;w=1200&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fvideo.0mbv_p06l-bfs.png&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fvideo.0mbv_p06l-bfs.png&amp;w=3840&amp;q=75">
<p>I would like to start a collection of useful videos that I've found online.</p>
<p>Although they are centered around Laravel, the ideas are easy to adopt in any other framework.</p>
<p>Here goes the first batch!</p>
<h2>Matt Stauffer - Patterns that pay off</h2>
<p><a href="https://www.youtube.com/watch?v=enTb2E4vEos"><img src="https://img.youtube.com/vi/enTb2E4vEos/0.jpg" alt="Matt Stauffer - Patterns that pay off"></a></p>
<h2>Jeffrey Way - Slay the Beast: Nine considerations to get your app back on track</h2>
<p><a href="https://www.youtube.com/watch?v=Npm5LruYA7A"><img src="https://img.youtube.com/vi/Npm5LruYA7A/0.jpg" alt="Jeffrey Way - Slay the Beast: Nine considerations to get your app back on track"></a></p>
<h2>Adam Wathan - Resisting Complexity</h2>
<p><a href="https://www.youtube.com/watch?v=dfgtKb-VpRk"><img src="https://img.youtube.com/vi/dfgtKb-VpRk/0.jpg" alt="Adam Wathan - Resisting Complexity"></a></p>
<h2>Adam Wathan - Cruddy by design</h2>
<p><a href="https://www.youtube.com/watch?v=MF0jFKvS4SI"><img src="https://img.youtube.com/vi/MF0jFKvS4SI/0.jpg" alt="Adam Wathan - Cruddy by design"></a></p>]]></content:encoded>
            <author>anton@azdanov.dev (Anton Ždanov)</author>
        </item>
        <item>
            <title><![CDATA[Trying out Go]]></title>
            <link>https://www.azdanov.dev/articles/2019/trying_out_go</link>
            <guid isPermaLink="false">https://www.azdanov.dev/articles/2019/trying_out_go</guid>
            <pubDate>Wed, 03 Apr 2019 14:58:05 GMT</pubDate>
            <content:encoded><![CDATA[<img alt="Go" loading="lazy" width="1200" height="630" decoding="async" data-nimg="1" style="color:transparent" srcset="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fgo.0znqho~ihmg1q.png&amp;w=1200&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fgo.0znqho~ihmg1q.png&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fgo.0znqho~ihmg1q.png&amp;w=3840&amp;q=75">
<p>For a while I've been curious about Go and its relevance to Web development.</p>
<p>I've heard a lot of good things about the performance, its rich standard library and how it has become a first language for many PHP and Node developers.</p>
<p>So let's have a go at Go!</p>
<h2>CLI App</h2>
<p>You can view the code hosted on GitHub at <a href="https://github.com/azdanov/images">azdanov/images</a>.</p>
<p>Here's the finished version, since this is not a tutorial I will not explain what each part of the code does.</p>
<pre class="language-go"><code class="language-go"><span class="token keyword">package</span> main

<span class="token keyword">import</span> <span class="token punctuation">(</span>
	<span class="token string">"bufio"</span>
	<span class="token string">"encoding/base64"</span>
	<span class="token string">"fmt"</span>
	<span class="token string">"log"</span>
	<span class="token string">"mime"</span>
	<span class="token string">"os"</span>
	<span class="token string">"path/filepath"</span>
<span class="token punctuation">)</span>

<span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token keyword">if</span> <span class="token function">len</span><span class="token punctuation">(</span>os<span class="token punctuation">.</span>Args<span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">1</span> <span class="token punctuation">{</span>
		log<span class="token punctuation">.</span><span class="token function">Fatal</span><span class="token punctuation">(</span><span class="token string">"No arguments specified."</span><span class="token punctuation">)</span>
	<span class="token punctuation">}</span>

	image <span class="token operator">:=</span> os<span class="token punctuation">.</span>Args<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span>

	file<span class="token punctuation">,</span> err <span class="token operator">:=</span> os<span class="token punctuation">.</span><span class="token function">Open</span><span class="token punctuation">(</span>image<span class="token punctuation">)</span>
	<span class="token keyword">if</span> os<span class="token punctuation">.</span><span class="token function">IsNotExist</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span>
		log<span class="token punctuation">.</span><span class="token function">Fatal</span><span class="token punctuation">(</span><span class="token string">"File not found."</span><span class="token punctuation">)</span>
	<span class="token punctuation">}</span>

	mimeType <span class="token operator">:=</span> mime<span class="token punctuation">.</span><span class="token function">TypeByExtension</span><span class="token punctuation">(</span>filepath<span class="token punctuation">.</span><span class="token function">Ext</span><span class="token punctuation">(</span>os<span class="token punctuation">.</span>Args<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

	supported <span class="token operator">:=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token builtin">string</span><span class="token punctuation">{</span>
		<span class="token string">"image/svg"</span><span class="token punctuation">,</span>
		<span class="token string">"image/svg+xml"</span><span class="token punctuation">,</span>
		<span class="token string">"image/gif"</span><span class="token punctuation">,</span>
		<span class="token string">"image/jpeg"</span><span class="token punctuation">,</span>
		<span class="token string">"image/png"</span><span class="token punctuation">,</span>
	<span class="token punctuation">}</span>

	<span class="token keyword">if</span> <span class="token operator">!</span><span class="token function">inSlice</span><span class="token punctuation">(</span>mimeType<span class="token punctuation">,</span> supported<span class="token punctuation">)</span> <span class="token punctuation">{</span>
		log<span class="token punctuation">.</span><span class="token function">Fatal</span><span class="token punctuation">(</span><span class="token string">"Image type not supported."</span><span class="token punctuation">)</span>
	<span class="token punctuation">}</span>

	info<span class="token punctuation">,</span> <span class="token boolean">_</span> <span class="token operator">:=</span> file<span class="token punctuation">.</span><span class="token function">Stat</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
	buf <span class="token operator">:=</span> <span class="token function">make</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token builtin">byte</span><span class="token punctuation">,</span> info<span class="token punctuation">.</span><span class="token function">Size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

	fReader <span class="token operator">:=</span> bufio<span class="token punctuation">.</span><span class="token function">NewReader</span><span class="token punctuation">(</span>file<span class="token punctuation">)</span>
	<span class="token boolean">_</span><span class="token punctuation">,</span> <span class="token boolean">_</span> <span class="token operator">=</span> fReader<span class="token punctuation">.</span><span class="token function">Read</span><span class="token punctuation">(</span>buf<span class="token punctuation">)</span>

	data <span class="token operator">:=</span> fmt<span class="token punctuation">.</span><span class="token function">Sprintf</span><span class="token punctuation">(</span>
		<span class="token string">"data:%s;base64,%s"</span><span class="token punctuation">,</span>
		mimeType<span class="token punctuation">,</span>
		base64<span class="token punctuation">.</span>StdEncoding<span class="token punctuation">.</span><span class="token function">EncodeToString</span><span class="token punctuation">(</span>buf<span class="token punctuation">)</span>
	<span class="token punctuation">)</span>

	fmt<span class="token punctuation">.</span><span class="token function">Print</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span>
<span class="token punctuation">}</span>

<span class="token keyword">func</span> <span class="token function">inSlice</span><span class="token punctuation">(</span>a <span class="token builtin">string</span><span class="token punctuation">,</span> list <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token builtin">string</span><span class="token punctuation">)</span> <span class="token builtin">bool</span> <span class="token punctuation">{</span>
	<span class="token keyword">for</span> <span class="token boolean">_</span><span class="token punctuation">,</span> b <span class="token operator">:=</span> <span class="token keyword">range</span> list <span class="token punctuation">{</span>
		<span class="token keyword">if</span> a <span class="token operator">==</span> b <span class="token punctuation">{</span>
			<span class="token keyword">return</span> <span class="token boolean">true</span>
		<span class="token punctuation">}</span>
	<span class="token punctuation">}</span>
	<span class="token keyword">return</span> <span class="token boolean">false</span>
<span class="token punctuation">}</span>
</code></pre>
<p>Original was made in PHP:</p>
<pre class="language-php"><code class="language-php"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span>

<span class="token keyword">declare</span><span class="token punctuation">(</span>strict_types<span class="token operator">=</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token function">array_shift</span><span class="token punctuation">(</span><span class="token global">$argv</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token variable">$image</span> <span class="token operator">=</span> <span class="token function">array_shift</span><span class="token punctuation">(</span><span class="token global">$argv</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token variable">$image</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token function">fwrite</span><span class="token punctuation">(</span><span class="token constant">STDERR</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'No arguments specified.'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">die</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token function">file_exists</span><span class="token punctuation">(</span><span class="token variable">$image</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token function">fwrite</span><span class="token punctuation">(</span><span class="token constant">STDERR</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'File not found.'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">die</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token variable">$mime</span> <span class="token operator">=</span> <span class="token function">mime_content_type</span><span class="token punctuation">(</span><span class="token variable">$image</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token variable">$supported</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'image/svg'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'image/svg+xml'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'image/gif'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'image/jpeg'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'image/png'</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token function">in_array</span><span class="token punctuation">(</span><span class="token variable">$mime</span><span class="token punctuation">,</span> <span class="token variable">$supported</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token function">fwrite</span><span class="token punctuation">(</span><span class="token constant">STDERR</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'Image type not supported.'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">die</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$mime</span> <span class="token operator">===</span> <span class="token string single-quoted-string">'image/svg'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token variable">$mime</span> <span class="token operator">.=</span> <span class="token string single-quoted-string">'+xml'</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token variable">$data</span> <span class="token operator">=</span> <span class="token function">file_get_contents</span><span class="token punctuation">(</span><span class="token variable">$image</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">die</span><span class="token punctuation">(</span><span class="token string double-quoted-string">"data:${mime};base64,"</span> <span class="token operator">.</span> <span class="token function">base64_encode</span><span class="token punctuation">(</span><span class="token variable">$data</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</span></code></pre>
<p>And for fun here's Node:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token punctuation">{</span> existsSync<span class="token punctuation">,</span> readFileSync <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"fs"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> <span class="token punctuation">{</span> extname <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"path"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>process<span class="token punctuation">.</span><span class="token property-access">argv</span><span class="token punctuation">.</span><span class="token property-access">length</span> <span class="token operator">==</span> <span class="token number">2</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  process<span class="token punctuation">.</span><span class="token property-access">stderr</span><span class="token punctuation">.</span><span class="token method function property-access">write</span><span class="token punctuation">(</span><span class="token string">"No arguments specified."</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  process<span class="token punctuation">.</span><span class="token method function property-access">exit</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">const</span> image <span class="token operator">=</span> process<span class="token punctuation">.</span><span class="token property-access">argv</span><span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">;</span>

<span class="token keyword control-flow">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token function">existsSync</span><span class="token punctuation">(</span>image<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  process<span class="token punctuation">.</span><span class="token property-access">stderr</span><span class="token punctuation">.</span><span class="token method function property-access">write</span><span class="token punctuation">(</span><span class="token string">"File not found."</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  process<span class="token punctuation">.</span><span class="token method function property-access">exit</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">const</span> extension <span class="token operator">=</span> <span class="token function">extname</span><span class="token punctuation">(</span>image<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">substr</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> supported <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">"image/svg+xml"</span><span class="token punctuation">,</span> <span class="token string">"image/gif"</span><span class="token punctuation">,</span> <span class="token string">"image/jpeg"</span><span class="token punctuation">,</span> <span class="token string">"image/png"</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> mime <span class="token operator">=</span> supported<span class="token punctuation">.</span><span class="token method function property-access">find</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">s</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> s<span class="token punctuation">.</span><span class="token method function property-access">includes</span><span class="token punctuation">(</span>extension<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword control-flow">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>mime<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  process<span class="token punctuation">.</span><span class="token property-access">stderr</span><span class="token punctuation">.</span><span class="token method function property-access">write</span><span class="token punctuation">(</span><span class="token string">"Image type not supported."</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  process<span class="token punctuation">.</span><span class="token method function property-access">exit</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">const</span> data <span class="token operator">=</span> <span class="token function">readFileSync</span><span class="token punctuation">(</span>image<span class="token punctuation">)</span><span class="token punctuation">;</span>
process<span class="token punctuation">.</span><span class="token property-access">stdout</span><span class="token punctuation">.</span><span class="token method function property-access">write</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">data:</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>mime<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">;base64,</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>data<span class="token punctuation">.</span><span class="token method function property-access">toString</span><span class="token punctuation">(</span><span class="token string">"Base64"</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<h2>Benchmark</h2>
<p>I was curious how much Go would outperform PHP and Node, and was pleasantly surprised.</p>
<p><a href="https://github.com/sharkdp/hyperfine">hyperfine</a> was used for the benchmarks.</p>
<table><thead><tr><th style="text-align:center">PHP (PHP 7.3.3)</th><th style="text-align:center">Go (go1.12.1 darwin/amd64)</th><th style="text-align:center">Node (v11.13.0)</th></tr></thead><tbody><tr><td style="text-align:center">User: 20.6ms, System: 9.8ms <br> 74 runs</td><td style="text-align:center">User: 5.1ms, System: 2.2ms <br> 286 runs</td><td style="text-align:center">User: 72.9ms, System: 18.7ms <br> 30 runs</td></tr><tr><td style="text-align:center"><a href="https://user-images.githubusercontent.com/6123841/55442537-becd1c00-55b7-11e9-8d53-5ab7d3f207ad.png"><img width="250" alt="Screenshot 2019-04-03 at 02 24 04" src="https://user-images.githubusercontent.com/6123841/55442537-becd1c00-55b7-11e9-8d53-5ab7d3f207ad.png"></a></td><td style="text-align:center"><a href="https://user-images.githubusercontent.com/6123841/55442538-becd1c00-55b7-11e9-96c8-3591b8695f36.png"><img width="250" alt="Screenshot 2019-04-03 at 02 25 08" src="https://user-images.githubusercontent.com/6123841/55442538-becd1c00-55b7-11e9-96c8-3591b8695f36.png"></a></td><td style="text-align:center"><a href="https://user-images.githubusercontent.com/6123841/55445574-b16a5e80-55c4-11e9-84af-aa0c6bfca89c.png"><img width="250" alt="Screenshot 2019-04-03 at 03 57 33" src="https://user-images.githubusercontent.com/6123841/55445574-b16a5e80-55c4-11e9-84af-aa0c6bfca89c.png"></a></td></tr></tbody></table>
<h2>Finish</h2>
<p>I didn't expect Node to be that slow compared to PHP. I guess PHP is performant enough for most Web related tasks.</p>
<p>So in conclusion Go is really an interesting language, there is a good reason it's called the <code>C</code> language of the web.</p>]]></content:encoded>
            <author>anton@azdanov.dev (Anton Ždanov)</author>
        </item>
        <item>
            <title><![CDATA[SCSS: A spacing utility]]></title>
            <link>https://www.azdanov.dev/articles/2019/scss-spacing-utility</link>
            <guid isPermaLink="false">https://www.azdanov.dev/articles/2019/scss-spacing-utility</guid>
            <pubDate>Mon, 18 Mar 2019 22:18:23 GMT</pubDate>
            <content:encoded><![CDATA[<img alt="SASS" loading="lazy" width="1200" height="630" decoding="async" data-nimg="1" style="color:transparent" srcset="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fsass.0tcf9~kqk2dmu.png&amp;w=1200&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fsass.0tcf9~kqk2dmu.png&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fsass.0tcf9~kqk2dmu.png&amp;w=3840&amp;q=75">
<p>In <a href="https://tailwindcss.com/">Tailwind CSS</a> there is an amazing utility for adding <a href="https://tailwindcss.com/docs/spacing/#app">padding and margin</a> which makes spatial positioning of element a joy.</p>
<p>While working with <a href="https://bulma.io/">Bulma</a> I've started to miss previously provided handy functionality.</p>
<p>This snippet should remedy this:</p>
<pre class="language-scss"><code class="language-scss"><span class="token property"><span class="token variable">$sizeUnit</span></span><span class="token punctuation">:</span> rem<span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$marginKey</span></span><span class="token punctuation">:</span> <span class="token string">"m"</span><span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$paddingKey</span></span><span class="token punctuation">:</span> <span class="token string">"p"</span><span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$separator</span></span><span class="token punctuation">:</span> <span class="token string">"-"</span><span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$sizes</span></span><span class="token punctuation">:</span> <span class="token punctuation">(</span>
  <span class="token punctuation">(</span><span class="token string">"0"</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token punctuation">(</span><span class="token string">"1"</span><span class="token punctuation">,</span> <span class="token number">0.125</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token punctuation">(</span><span class="token string">"2"</span><span class="token punctuation">,</span> <span class="token number">0.25</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token punctuation">(</span><span class="token string">"3"</span><span class="token punctuation">,</span> <span class="token number">0.5</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token punctuation">(</span><span class="token string">"4"</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token punctuation">(</span><span class="token string">"5"</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token punctuation">(</span><span class="token string">"6"</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token punctuation">(</span><span class="token string">"7"</span><span class="token punctuation">,</span> <span class="token number">5.5</span><span class="token punctuation">)</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$positions</span></span><span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token string">"t"</span><span class="token punctuation">,</span> <span class="token string">"top"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token string">"r"</span><span class="token punctuation">,</span> <span class="token string">"right"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token string">"b"</span><span class="token punctuation">,</span> <span class="token string">"bottom"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token string">"l"</span><span class="token punctuation">,</span> <span class="token string">"left"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">@function</span> <span class="token function">sizeUnitValue</span><span class="token punctuation">(</span><span class="token variable">$key</span><span class="token punctuation">,</span> <span class="token variable">$value</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">@return</span> <span class="token function">if</span><span class="token punctuation">(</span><span class="token variable">$key</span> <span class="token operator">==</span> <span class="token string">"none"</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token variable">$value</span> <span class="token operator">+</span> <span class="token variable">$sizeUnit</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">@each</span> <span class="token selector"><span class="token variable">$size</span> in <span class="token variable">$sizes</span> </span><span class="token punctuation">{</span>
  <span class="token property"><span class="token variable">$sizeKey</span></span><span class="token punctuation">:</span> <span class="token function">nth</span><span class="token punctuation">(</span><span class="token variable">$size</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property"><span class="token variable">$sizeValue</span></span><span class="token punctuation">:</span> <span class="token function">nth</span><span class="token punctuation">(</span><span class="token variable">$size</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token selector">.<span class="token variable">#{$marginKey}</span><span class="token variable">#{$separator}</span><span class="token variable">#{$sizeKey}</span> </span><span class="token punctuation">{</span>
    <span class="token property">margin</span><span class="token punctuation">:</span> <span class="token function">sizeUnitValue</span><span class="token punctuation">(</span><span class="token variable">$sizeKey</span><span class="token punctuation">,</span> <span class="token variable">$sizeValue</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token selector">.<span class="token variable">#{$paddingKey}</span><span class="token variable">#{$separator}</span><span class="token variable">#{$sizeKey}</span> </span><span class="token punctuation">{</span>
    <span class="token property">padding</span><span class="token punctuation">:</span> <span class="token function">sizeUnitValue</span><span class="token punctuation">(</span><span class="token variable">$sizeKey</span><span class="token punctuation">,</span> <span class="token variable">$sizeValue</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token keyword">@each</span> <span class="token selector"><span class="token variable">$position</span> in <span class="token variable">$positions</span> </span><span class="token punctuation">{</span>
    <span class="token property"><span class="token variable">$posKey</span></span><span class="token punctuation">:</span> <span class="token function">nth</span><span class="token punctuation">(</span><span class="token variable">$position</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token property"><span class="token variable">$posValue</span></span><span class="token punctuation">:</span> <span class="token function">nth</span><span class="token punctuation">(</span><span class="token variable">$position</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token selector">.<span class="token variable">#{$marginKey}</span><span class="token variable">#{$posKey}</span><span class="token variable">#{$separator}</span><span class="token variable">#{$sizeKey}</span> </span><span class="token punctuation">{</span>
      <span class="token property">margin-<span class="token variable">#{$posValue}</span></span><span class="token punctuation">:</span> <span class="token function">sizeUnitValue</span><span class="token punctuation">(</span><span class="token variable">$sizeKey</span><span class="token punctuation">,</span> <span class="token variable">$sizeValue</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token selector">.<span class="token variable">#{$paddingKey}</span><span class="token variable">#{$posKey}</span><span class="token variable">#{$separator}</span><span class="token variable">#{$sizeKey}</span> </span><span class="token punctuation">{</span>
      <span class="token property">padding-<span class="token variable">#{$posValue}</span></span><span class="token punctuation">:</span> <span class="token function">sizeUnitValue</span><span class="token punctuation">(</span><span class="token variable">$sizeKey</span><span class="token punctuation">,</span> <span class="token variable">$sizeValue</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>This will generate:</p>
<pre class="language-css"><code class="language-css"><span class="token comment">/* ... */</span>
<span class="token selector"><span class="token class">.m-1</span></span> <span class="token punctuation">{</span>
  <span class="token property">margin</span><span class="token punctuation">:</span> <span class="token number">0.125</span><span class="token unit">rem</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector"><span class="token class">.p-1</span></span> <span class="token punctuation">{</span>
  <span class="token property">padding</span><span class="token punctuation">:</span> <span class="token number">0.125</span><span class="token unit">rem</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector"><span class="token class">.mt-1</span></span> <span class="token punctuation">{</span>
  <span class="token property">margin-top</span><span class="token punctuation">:</span> <span class="token number">0.125</span><span class="token unit">rem</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector"><span class="token class">.pt-1</span></span> <span class="token punctuation">{</span>
  <span class="token property">padding-top</span><span class="token punctuation">:</span> <span class="token number">0.125</span><span class="token unit">rem</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector"><span class="token class">.mr-1</span></span> <span class="token punctuation">{</span>
  <span class="token property">margin-right</span><span class="token punctuation">:</span> <span class="token number">0.125</span><span class="token unit">rem</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector"><span class="token class">.pr-1</span></span> <span class="token punctuation">{</span>
  <span class="token property">padding-right</span><span class="token punctuation">:</span> <span class="token number">0.125</span><span class="token unit">rem</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector"><span class="token class">.mb-1</span></span> <span class="token punctuation">{</span>
  <span class="token property">margin-bottom</span><span class="token punctuation">:</span> <span class="token number">0.125</span><span class="token unit">rem</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector"><span class="token class">.pb-1</span></span> <span class="token punctuation">{</span>
  <span class="token property">padding-bottom</span><span class="token punctuation">:</span> <span class="token number">0.125</span><span class="token unit">rem</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector"><span class="token class">.ml-1</span></span> <span class="token punctuation">{</span>
  <span class="token property">margin-left</span><span class="token punctuation">:</span> <span class="token number">0.125</span><span class="token unit">rem</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector"><span class="token class">.pl-1</span></span> <span class="token punctuation">{</span>
  <span class="token property">padding-left</span><span class="token punctuation">:</span> <span class="token number">0.125</span><span class="token unit">rem</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">/* ... */</span>
</code></pre>
<p>Quite useful.</p>]]></content:encoded>
            <author>anton@azdanov.dev (Anton Ždanov)</author>
        </item>
        <item>
            <title><![CDATA[Materialized Views in a Database]]></title>
            <link>https://www.azdanov.dev/articles/2019/materialized-view</link>
            <guid isPermaLink="false">https://www.azdanov.dev/articles/2019/materialized-view</guid>
            <pubDate>Sun, 10 Mar 2019 12:58:12 GMT</pubDate>
            <content:encoded><![CDATA[<img alt="study" loading="lazy" width="1200" height="630" decoding="async" data-nimg="1" style="color:transparent" srcset="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fstudy.0pvgn-5savw_c.png&amp;w=1200&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fstudy.0pvgn-5savw_c.png&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fstudy.0pvgn-5savw_c.png&amp;w=3840&amp;q=75">
<p>For example there is a dashboard for a fictitious logistics company, they have a multitude of workers, each frequently visiting the website.</p>
<img alt="page" loading="lazy" width="2562" height="1634" decoding="async" data-nimg="1" style="color:transparent" srcset="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fpage.0m81.n033iphz.png&amp;w=3840&amp;q=75 1x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fpage.0m81.n033iphz.png&amp;w=3840&amp;q=75">
<p>But there is a problem. The summary page that is found on the <code>/</code> route needs to execute a heavy query on each visit, which slows everything down. Not to mention the lack of reusability when embedding the summary SQL code inside the app.</p>
<pre class="language-sql"><code class="language-sql"><span class="token comment">-- Employee Leaderboard</span>
<span class="token keyword">SELECT</span>
  concat<span class="token punctuation">(</span>e<span class="token punctuation">.</span>firstname<span class="token punctuation">,</span> <span class="token string">' '</span><span class="token punctuation">,</span> e<span class="token punctuation">.</span>lastname<span class="token punctuation">)</span> <span class="token keyword">AS</span> name<span class="token punctuation">,</span>
  <span class="token function">sum</span><span class="token punctuation">(</span>od<span class="token punctuation">.</span>price <span class="token operator">*</span> od<span class="token punctuation">.</span>quantity<span class="token punctuation">)</span> <span class="token keyword">AS</span> amount
<span class="token keyword">FROM</span>
  employee <span class="token keyword">AS</span> e
  <span class="token keyword">INNER</span> <span class="token keyword">JOIN</span> <span class="token keyword">order</span> <span class="token keyword">AS</span> o <span class="token keyword">ON</span> o<span class="token punctuation">.</span>employeeid <span class="token operator">=</span> e<span class="token punctuation">.</span>id
  <span class="token keyword">INNER</span> <span class="token keyword">JOIN</span> orderdetail <span class="token keyword">AS</span> od <span class="token keyword">ON</span> od<span class="token punctuation">.</span>orderid <span class="token operator">=</span> o<span class="token punctuation">.</span>id
<span class="token keyword">GROUP</span> <span class="token keyword">BY</span>
  e<span class="token punctuation">.</span>id
<span class="token keyword">ORDER</span> <span class="token keyword">BY</span>
  amount <span class="token keyword">DESC</span>
<span class="token keyword">LIMIT</span>
  <span class="token number">5</span><span class="token punctuation">;</span>

<span class="token comment">-- Customer Leaderboard</span>
<span class="token keyword">SELECT</span>
  c<span class="token punctuation">.</span>company <span class="token keyword">AS</span> name<span class="token punctuation">,</span>
  <span class="token function">sum</span><span class="token punctuation">(</span>od<span class="token punctuation">.</span>price <span class="token operator">*</span> od<span class="token punctuation">.</span>quantity<span class="token punctuation">)</span> <span class="token keyword">AS</span> amount
<span class="token keyword">FROM</span>
  customer <span class="token keyword">AS</span> c
  <span class="token keyword">INNER</span> <span class="token keyword">JOIN</span> <span class="token keyword">order</span> <span class="token keyword">AS</span> o <span class="token keyword">ON</span> o<span class="token punctuation">.</span>customerid <span class="token operator">=</span> c<span class="token punctuation">.</span>id
  <span class="token keyword">INNER</span> <span class="token keyword">JOIN</span> orderdetail <span class="token keyword">AS</span> od <span class="token keyword">ON</span> od<span class="token punctuation">.</span>orderid <span class="token operator">=</span> o<span class="token punctuation">.</span>id
<span class="token keyword">GROUP</span> <span class="token keyword">BY</span>
  c<span class="token punctuation">.</span>id
<span class="token keyword">ORDER</span> <span class="token keyword">BY</span>
  amount <span class="token keyword">DESC</span>
<span class="token keyword">LIMIT</span>
  <span class="token number">5</span><span class="token punctuation">;</span>

<span class="token comment">-- Product Leaderboard</span>
<span class="token keyword">SELECT</span>
  p<span class="token punctuation">.</span>product <span class="token keyword">AS</span> name<span class="token punctuation">,</span> <span class="token function">sum</span><span class="token punctuation">(</span>od<span class="token punctuation">.</span>price <span class="token operator">*</span> od<span class="token punctuation">.</span>quantity<span class="token punctuation">)</span> <span class="token keyword">AS</span> amount
<span class="token keyword">FROM</span>
  orderdetail <span class="token keyword">AS</span> od
  <span class="token keyword">INNER</span> <span class="token keyword">JOIN</span> <span class="token keyword">order</span> <span class="token keyword">AS</span> o <span class="token keyword">ON</span> o<span class="token punctuation">.</span>id <span class="token operator">=</span> od<span class="token punctuation">.</span>orderid
  <span class="token keyword">INNER</span> <span class="token keyword">JOIN</span> product <span class="token keyword">AS</span> p <span class="token keyword">ON</span> p<span class="token punctuation">.</span>id <span class="token operator">=</span> od<span class="token punctuation">.</span>productid
<span class="token keyword">GROUP</span> <span class="token keyword">BY</span>
  p<span class="token punctuation">.</span>id
<span class="token keyword">ORDER</span> <span class="token keyword">BY</span>
  amount <span class="token keyword">DESC</span>
<span class="token keyword">LIMIT</span>
  <span class="token number">5</span><span class="token punctuation">;</span>

<span class="token comment">-- Recent Orders</span>
<span class="token keyword">SELECT</span>
  o<span class="token punctuation">.</span>id<span class="token punctuation">,</span>
  concat<span class="token punctuation">(</span>e<span class="token punctuation">.</span>firstname<span class="token punctuation">,</span> <span class="token string">' '</span><span class="token punctuation">,</span> e<span class="token punctuation">.</span>lastname<span class="token punctuation">)</span> <span class="token keyword">AS</span> employee<span class="token punctuation">,</span>
  c<span class="token punctuation">.</span>company <span class="token keyword">AS</span> customer<span class="token punctuation">,</span>
  o<span class="token punctuation">.</span><span class="token keyword">date</span><span class="token punctuation">,</span>
  <span class="token function">sum</span><span class="token punctuation">(</span>od<span class="token punctuation">.</span>price <span class="token operator">*</span> od<span class="token punctuation">.</span>quantity<span class="token punctuation">)</span> <span class="token keyword">AS</span> amount
<span class="token keyword">FROM</span>
  <span class="token keyword">order</span> <span class="token keyword">AS</span> o
  <span class="token keyword">INNER</span> <span class="token keyword">JOIN</span> orderdetail <span class="token keyword">AS</span> od <span class="token keyword">ON</span> od<span class="token punctuation">.</span>orderid <span class="token operator">=</span> o<span class="token punctuation">.</span>id
  <span class="token keyword">INNER</span> <span class="token keyword">JOIN</span> employee <span class="token keyword">AS</span> e <span class="token keyword">ON</span> e<span class="token punctuation">.</span>id <span class="token operator">=</span> o<span class="token punctuation">.</span>employeeid
  <span class="token keyword">INNER</span> <span class="token keyword">JOIN</span> customer <span class="token keyword">AS</span> c <span class="token keyword">ON</span> c<span class="token punctuation">.</span>id <span class="token operator">=</span> o<span class="token punctuation">.</span>customerid
<span class="token keyword">WHERE</span>
  o<span class="token punctuation">.</span><span class="token keyword">date</span> <span class="token operator">IS</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span>
<span class="token keyword">GROUP</span> <span class="token keyword">BY</span>
  o<span class="token punctuation">.</span>id<span class="token punctuation">,</span> e<span class="token punctuation">.</span>firstname<span class="token punctuation">,</span> e<span class="token punctuation">.</span>lastname<span class="token punctuation">,</span> c<span class="token punctuation">.</span>company
<span class="token keyword">ORDER</span> <span class="token keyword">BY</span>
  o<span class="token punctuation">.</span><span class="token keyword">date</span> <span class="token keyword">DESC</span>
<span class="token keyword">LIMIT</span>
  <span class="token number">5</span><span class="token punctuation">;</span>

<span class="token comment">-- Product Reorder list</span>
<span class="token keyword">SELECT</span>
  product <span class="token keyword">AS</span> name<span class="token punctuation">,</span> reorderthreshold<span class="token punctuation">,</span> unitsinstock<span class="token punctuation">,</span> unitsordered
<span class="token keyword">FROM</span>
  product
<span class="token keyword">WHERE</span>
  <span class="token punctuation">(</span>unitsinstock <span class="token operator">+</span> unitsordered<span class="token punctuation">)</span> <span class="token operator">&lt;</span> reorderthreshold<span class="token punctuation">;</span>
</code></pre>
<p>Let's move this query inside the database as a <a href="https://www.postgresql.org/docs/current/rules-materializedviews.html">MATERIALIZED VIEW</a>.</p>
<h2>Refactor to PostgreSQL Materialized View</h2>
<p>PostgreSQL natively supports <code>MATERIALIZED VIEW</code>, which will simplify things a lot. The queries stay basically the same, so it's a simple refactor.</p>
<p>One problem one might encounter is a need to manually refresh the views, which can be solved with <a href="https://www.postgresql.org/docs/current/plpgsql-trigger.html">TRIGGER</a>.</p>
<pre class="language-sql"><code class="language-sql"><span class="token comment">-- Employee Leaderboard</span>
<span class="token keyword">CREATE</span> MATERIALIZED <span class="token keyword">VIEW</span> mv_employeeleaderboard
<span class="token keyword">AS</span>
<span class="token keyword">SELECT</span>
  concat<span class="token punctuation">(</span>e<span class="token punctuation">.</span>firstname<span class="token punctuation">,</span> <span class="token string">' '</span><span class="token punctuation">,</span> e<span class="token punctuation">.</span>lastname<span class="token punctuation">)</span> <span class="token keyword">AS</span> name<span class="token punctuation">,</span>
  <span class="token function">sum</span><span class="token punctuation">(</span>od<span class="token punctuation">.</span>price <span class="token operator">*</span> od<span class="token punctuation">.</span>quantity<span class="token punctuation">)</span> <span class="token keyword">AS</span> amount
<span class="token keyword">FROM</span>
  employee <span class="token keyword">AS</span> e
  <span class="token keyword">INNER</span> <span class="token keyword">JOIN</span> <span class="token keyword">order</span> <span class="token keyword">AS</span> o <span class="token keyword">ON</span> o<span class="token punctuation">.</span>employeeid <span class="token operator">=</span> e<span class="token punctuation">.</span>id
  <span class="token keyword">INNER</span> <span class="token keyword">JOIN</span> orderdetail <span class="token keyword">AS</span> od <span class="token keyword">ON</span> o<span class="token punctuation">.</span>id <span class="token operator">=</span> od<span class="token punctuation">.</span>orderid
  <span class="token keyword">GROUP</span> <span class="token keyword">BY</span>
    e<span class="token punctuation">.</span>id
  <span class="token keyword">ORDER</span> <span class="token keyword">BY</span>
    amount <span class="token keyword">DESC</span>
  <span class="token keyword">LIMIT</span> <span class="token number">5</span><span class="token punctuation">;</span>

<span class="token comment">-- Customer Leaderboard</span>
<span class="token keyword">CREATE</span> MATERIALIZED <span class="token keyword">VIEW</span> mv_customerleaderboard
<span class="token keyword">AS</span>
<span class="token keyword">SELECT</span>
  c<span class="token punctuation">.</span>company <span class="token keyword">AS</span> name<span class="token punctuation">,</span>
  <span class="token function">sum</span><span class="token punctuation">(</span>od<span class="token punctuation">.</span>price <span class="token operator">*</span> od<span class="token punctuation">.</span>quantity<span class="token punctuation">)</span> <span class="token keyword">AS</span> amount
<span class="token keyword">FROM</span>
  customer <span class="token keyword">AS</span> c
  <span class="token keyword">INNER</span> <span class="token keyword">JOIN</span> <span class="token keyword">order</span> <span class="token keyword">AS</span> o <span class="token keyword">ON</span> o<span class="token punctuation">.</span>customerid <span class="token operator">=</span> c<span class="token punctuation">.</span>id
  <span class="token keyword">INNER</span> <span class="token keyword">JOIN</span> orderdetail <span class="token keyword">AS</span> od <span class="token keyword">ON</span> o<span class="token punctuation">.</span>id <span class="token operator">=</span> od<span class="token punctuation">.</span>orderid
  <span class="token keyword">GROUP</span> <span class="token keyword">BY</span>
    c<span class="token punctuation">.</span>id
  <span class="token keyword">ORDER</span> <span class="token keyword">BY</span>
    amount <span class="token keyword">DESC</span>
  <span class="token keyword">LIMIT</span> <span class="token number">5</span><span class="token punctuation">;</span>

<span class="token comment">-- Product Leaderboard</span>
<span class="token keyword">CREATE</span> MATERIALIZED <span class="token keyword">VIEW</span> mv_productleaderboard
<span class="token keyword">AS</span>
<span class="token keyword">SELECT</span>
  p<span class="token punctuation">.</span>product <span class="token keyword">AS</span> name<span class="token punctuation">,</span>
  <span class="token function">sum</span><span class="token punctuation">(</span>od<span class="token punctuation">.</span>price <span class="token operator">*</span> od<span class="token punctuation">.</span>quantity<span class="token punctuation">)</span> <span class="token keyword">AS</span> amount
<span class="token keyword">FROM</span>
  orderdetail <span class="token keyword">AS</span> od
  <span class="token keyword">INNER</span> <span class="token keyword">JOIN</span> <span class="token keyword">order</span> <span class="token keyword">AS</span> o <span class="token keyword">ON</span> od<span class="token punctuation">.</span>orderid <span class="token operator">=</span> o<span class="token punctuation">.</span>id
  <span class="token keyword">INNER</span> <span class="token keyword">JOIN</span> product <span class="token keyword">AS</span> p <span class="token keyword">ON</span> od<span class="token punctuation">.</span>productid <span class="token operator">=</span> p<span class="token punctuation">.</span>id
  <span class="token keyword">GROUP</span> <span class="token keyword">BY</span>
    p<span class="token punctuation">.</span>id
  <span class="token keyword">ORDER</span> <span class="token keyword">BY</span>
    amount <span class="token keyword">DESC</span>
  <span class="token keyword">LIMIT</span> <span class="token number">5</span><span class="token punctuation">;</span>

<span class="token comment">-- Recent Orders</span>
<span class="token keyword">CREATE</span> <span class="token keyword">VIEW</span> mv_recentorders
<span class="token keyword">AS</span>
<span class="token keyword">SELECT</span>
  o<span class="token punctuation">.</span>id<span class="token punctuation">,</span>
  concat<span class="token punctuation">(</span>e<span class="token punctuation">.</span>firstname<span class="token punctuation">,</span> <span class="token string">' '</span><span class="token punctuation">,</span> e<span class="token punctuation">.</span>lastname<span class="token punctuation">)</span> <span class="token keyword">AS</span> employee<span class="token punctuation">,</span>
  c<span class="token punctuation">.</span>company <span class="token keyword">AS</span> customer<span class="token punctuation">,</span>
  o<span class="token punctuation">.</span><span class="token keyword">date</span><span class="token punctuation">,</span>
  <span class="token function">sum</span><span class="token punctuation">(</span>od<span class="token punctuation">.</span>price <span class="token operator">*</span> od<span class="token punctuation">.</span>quantity<span class="token punctuation">)</span> <span class="token keyword">AS</span> subtotal
<span class="token keyword">FROM</span>
  <span class="token keyword">order</span> <span class="token keyword">AS</span> o
  <span class="token keyword">INNER</span> <span class="token keyword">JOIN</span> orderdetail <span class="token keyword">AS</span> od <span class="token keyword">ON</span> od<span class="token punctuation">.</span>orderid <span class="token operator">=</span> o<span class="token punctuation">.</span>id
  <span class="token keyword">INNER</span> <span class="token keyword">JOIN</span> employee <span class="token keyword">AS</span> e <span class="token keyword">ON</span> o<span class="token punctuation">.</span>employeeid <span class="token operator">=</span> e<span class="token punctuation">.</span>id
  <span class="token keyword">INNER</span> <span class="token keyword">JOIN</span> customer <span class="token keyword">AS</span> c <span class="token keyword">ON</span> o<span class="token punctuation">.</span>customerid <span class="token operator">=</span> c<span class="token punctuation">.</span>id
  <span class="token keyword">WHERE</span>
    o<span class="token punctuation">.</span><span class="token keyword">date</span> <span class="token operator">IS</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span>
  <span class="token keyword">GROUP</span> <span class="token keyword">BY</span>
    o<span class="token punctuation">.</span>id<span class="token punctuation">,</span>
    e<span class="token punctuation">.</span>firstname<span class="token punctuation">,</span>
    e<span class="token punctuation">.</span>lastname<span class="token punctuation">,</span>
    c<span class="token punctuation">.</span>company
  <span class="token keyword">ORDER</span> <span class="token keyword">BY</span>
    o<span class="token punctuation">.</span><span class="token keyword">date</span> <span class="token keyword">DESC</span>
  <span class="token keyword">LIMIT</span> <span class="token number">5</span><span class="token punctuation">;</span>

<span class="token comment">-- Product Reorder list (VIEW is used to keep it up-to-date)</span>
<span class="token keyword">CREATE</span> <span class="token keyword">VIEW</span> v_reorderlist
<span class="token keyword">SELECT</span>
  product <span class="token keyword">AS</span> name<span class="token punctuation">,</span> reorderthreshold<span class="token punctuation">,</span> unitsinstock<span class="token punctuation">,</span> unitsordered
<span class="token keyword">FROM</span>
  product
<span class="token keyword">WHERE</span>
  <span class="token punctuation">(</span>unitsinstock <span class="token operator">+</span> unitsordered<span class="token punctuation">)</span> <span class="token operator">&lt;</span> reorderthreshold<span class="token punctuation">;</span>
</code></pre>
<p>Now let's create some <a href="https://www.postgresql.org/docs/current/plpgsql-trigger.html">TRIGGER</a>s and a <a href="https://www.postgresql.org/docs/current/sql-createfunction.html">FUNCTION</a> that will refresh created views on <code>order</code> update or delete.</p>
<pre class="language-sql"><code class="language-sql"><span class="token keyword">CREATE</span> <span class="token operator">OR</span> <span class="token keyword">REPLACE</span> <span class="token keyword">FUNCTION</span> refresh_dashboard<span class="token punctuation">(</span><span class="token punctuation">)</span>
  <span class="token keyword">RETURNS</span> <span class="token keyword">TRIGGER</span>
<span class="token keyword">AS</span> $$
<span class="token keyword">BEGIN</span>
  REFRESH MATERIALIZED <span class="token keyword">VIEW</span> mv_employeeleaderboard<span class="token punctuation">;</span>
  REFRESH MATERIALIZED <span class="token keyword">VIEW</span> mv_customerleaderboard<span class="token punctuation">;</span>
  REFRESH MATERIALIZED <span class="token keyword">VIEW</span> mv_productleaderboard<span class="token punctuation">;</span>
  REFRESH MATERIALIZED <span class="token keyword">VIEW</span> mv_recentorders<span class="token punctuation">;</span>
  <span class="token keyword">RETURN</span> new<span class="token punctuation">;</span>
<span class="token keyword">END</span><span class="token punctuation">;</span>
$$
<span class="token keyword">LANGUAGE</span> <span class="token string">'plpgsql'</span><span class="token punctuation">;</span>

<span class="token keyword">CREATE</span> <span class="token keyword">TRIGGER</span> dashboard_refresh_for_order_update
<span class="token keyword">AFTER</span> <span class="token keyword">UPDATE</span>
  <span class="token keyword">ON</span> <span class="token keyword">order</span> <span class="token keyword">FOR EACH ROW</span> <span class="token keyword">EXECUTE</span> <span class="token keyword">PROCEDURE</span> refresh_dashboard<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">CREATE</span> <span class="token keyword">TRIGGER</span> dashboard_refresh_for_order_delete
<span class="token keyword">AFTER</span> <span class="token keyword">DELETE</span>
  <span class="token keyword">ON</span> <span class="token keyword">order</span> <span class="token keyword">FOR EACH ROW</span> <span class="token keyword">EXECUTE</span> <span class="token keyword">PROCEDURE</span> refresh_dashboard<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<p>These statements can be entered directly via a terminal into a database, or even better inserted by a migration.</p>
<p>It is easy to revert introduced changes with these statements.</p>
<pre class="language-sql"><code class="language-sql"><span class="token keyword">DROP</span> MATERIALIZED <span class="token keyword">VIEW</span> mv_employeeleaderboard<span class="token punctuation">;</span>
<span class="token keyword">DROP</span> MATERIALIZED <span class="token keyword">VIEW</span> mv_customerleaderboard<span class="token punctuation">;</span>
<span class="token keyword">DROP</span> MATERIALIZED <span class="token keyword">VIEW</span> mv_productleaderboard<span class="token punctuation">;</span>
<span class="token keyword">DROP</span> MATERIALIZED <span class="token keyword">VIEW</span> mv_recentorders<span class="token punctuation">;</span>
<span class="token keyword">DROP</span> <span class="token keyword">VIEW</span> v_reorderlist<span class="token punctuation">;</span>

<span class="token keyword">DROP</span> <span class="token keyword">TRIGGER</span> dashboard_refresh_for_order_update <span class="token keyword">ON</span> <span class="token keyword">order</span><span class="token punctuation">;</span>
<span class="token keyword">DROP</span> <span class="token keyword">TRIGGER</span> dashboard_refresh_for_order_delete <span class="token keyword">ON</span> <span class="token keyword">order</span><span class="token punctuation">;</span>
</code></pre>
<h2>Refactor to MySQL Materialized View Hack</h2>
<p>Sadly MySQL doesn't have <code>MATERIALIZED VIEW</code>, what we could do is create a specialized table only used for the dashboard and manually update it's data.</p>
<p>First step is to encapsulate each query inside of a dedicated <code>VIEW</code>.</p>
<pre class="language-sql"><code class="language-sql"><span class="token comment">-- Employee Leaderboard</span>
<span class="token keyword">CREATE</span> <span class="token operator">OR</span> <span class="token keyword">REPLACE</span> <span class="token keyword">VIEW</span> v_employeeleaderboard
<span class="token keyword">AS</span> <span class="token punctuation">(</span>
  <span class="token keyword">SELECT</span>
    concat<span class="token punctuation">(</span>e<span class="token punctuation">.</span>firstname<span class="token punctuation">,</span> <span class="token string">' '</span><span class="token punctuation">,</span> e<span class="token punctuation">.</span>lastname<span class="token punctuation">)</span> <span class="token keyword">AS</span> name<span class="token punctuation">,</span>
    <span class="token function">sum</span><span class="token punctuation">(</span>od<span class="token punctuation">.</span>price <span class="token operator">*</span> od<span class="token punctuation">.</span>quantity<span class="token punctuation">)</span> <span class="token keyword">AS</span> amount
  <span class="token keyword">FROM</span>
    employee <span class="token keyword">AS</span> e
  <span class="token keyword">INNER</span> <span class="token keyword">JOIN</span> <span class="token keyword">order</span> <span class="token keyword">AS</span> o <span class="token keyword">ON</span> o<span class="token punctuation">.</span>employeeid <span class="token operator">=</span> e<span class="token punctuation">.</span>id
  <span class="token keyword">INNER</span> <span class="token keyword">JOIN</span> orderdetail <span class="token keyword">AS</span> od <span class="token keyword">ON</span> o<span class="token punctuation">.</span>id <span class="token operator">=</span> od<span class="token punctuation">.</span>orderid
  <span class="token keyword">GROUP</span> <span class="token keyword">BY</span>
    e<span class="token punctuation">.</span>id
  <span class="token keyword">ORDER</span> <span class="token keyword">BY</span>
    amount <span class="token keyword">DESC</span>
  <span class="token keyword">LIMIT</span> <span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">-- Customer Leaderboard</span>
<span class="token keyword">CREATE</span> <span class="token operator">OR</span> <span class="token keyword">REPLACE</span> <span class="token keyword">VIEW</span> v_customerleaderboard
<span class="token keyword">AS</span> <span class="token punctuation">(</span>
  <span class="token keyword">SELECT</span>
    c<span class="token punctuation">.</span>company <span class="token keyword">AS</span> name<span class="token punctuation">,</span>
    <span class="token function">SUM</span><span class="token punctuation">(</span>od<span class="token punctuation">.</span>price <span class="token operator">*</span> od<span class="token punctuation">.</span>quantity<span class="token punctuation">)</span> <span class="token keyword">AS</span> amount
  <span class="token keyword">FROM</span>
    customer <span class="token keyword">AS</span> c
  <span class="token keyword">INNER</span> <span class="token keyword">JOIN</span> <span class="token keyword">order</span> <span class="token keyword">AS</span> o <span class="token keyword">ON</span> o<span class="token punctuation">.</span>customerid <span class="token operator">=</span> c<span class="token punctuation">.</span>id
  <span class="token keyword">INNER</span> <span class="token keyword">JOIN</span> orderdetail <span class="token keyword">AS</span> od <span class="token keyword">ON</span> o<span class="token punctuation">.</span>id <span class="token operator">=</span> od<span class="token punctuation">.</span>orderid
  <span class="token keyword">GROUP</span> <span class="token keyword">BY</span>
    c<span class="token punctuation">.</span>id
  <span class="token keyword">ORDER</span> <span class="token keyword">BY</span>
    amount <span class="token keyword">DESC</span>
  <span class="token keyword">LIMIT</span> <span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">-- Product Leaderboard</span>
<span class="token keyword">CREATE</span> <span class="token operator">OR</span> <span class="token keyword">REPLACE</span> <span class="token keyword">VIEW</span> v_productleaderboard
<span class="token keyword">AS</span> <span class="token punctuation">(</span>
  <span class="token keyword">SELECT</span>
    p<span class="token punctuation">.</span>product <span class="token keyword">AS</span> name<span class="token punctuation">,</span>
    <span class="token function">sum</span><span class="token punctuation">(</span>od<span class="token punctuation">.</span>price <span class="token operator">*</span> od<span class="token punctuation">.</span>quantity<span class="token punctuation">)</span> <span class="token keyword">AS</span> amount
  <span class="token keyword">FROM</span>
    orderdetail <span class="token keyword">AS</span> od
  <span class="token keyword">INNER</span> <span class="token keyword">JOIN</span> <span class="token keyword">order</span> <span class="token keyword">AS</span> o <span class="token keyword">ON</span> od<span class="token punctuation">.</span>orderid <span class="token operator">=</span> o<span class="token punctuation">.</span>id
  <span class="token keyword">INNER</span> <span class="token keyword">JOIN</span> product <span class="token keyword">AS</span> p <span class="token keyword">ON</span> od<span class="token punctuation">.</span>productid <span class="token operator">=</span> p<span class="token punctuation">.</span>id
  <span class="token keyword">GROUP</span> <span class="token keyword">BY</span>
    p<span class="token punctuation">.</span>id
  <span class="token keyword">ORDER</span> <span class="token keyword">BY</span>
    amount <span class="token keyword">DESC</span>
  <span class="token keyword">LIMIT</span> <span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">-- Recent Orders</span>
<span class="token keyword">CREATE</span> <span class="token operator">OR</span> <span class="token keyword">REPLACE</span> <span class="token keyword">VIEW</span> v_recentorders
<span class="token keyword">AS</span> <span class="token punctuation">(</span>
  <span class="token keyword">SELECT</span>
    o<span class="token punctuation">.</span>id<span class="token punctuation">,</span>
    concat<span class="token punctuation">(</span>e<span class="token punctuation">.</span>firstname<span class="token punctuation">,</span> <span class="token string">' '</span><span class="token punctuation">,</span> e<span class="token punctuation">.</span>lastname<span class="token punctuation">)</span> <span class="token keyword">AS</span> employee<span class="token punctuation">,</span>
    c<span class="token punctuation">.</span>company <span class="token keyword">AS</span> customer<span class="token punctuation">,</span>
    o<span class="token punctuation">.</span><span class="token keyword">date</span><span class="token punctuation">,</span>
    <span class="token function">sum</span><span class="token punctuation">(</span>od<span class="token punctuation">.</span>price <span class="token operator">*</span> od<span class="token punctuation">.</span>quantity<span class="token punctuation">)</span> <span class="token keyword">AS</span> amount
  <span class="token keyword">FROM</span>
    <span class="token keyword">order</span> <span class="token keyword">AS</span> o
  <span class="token keyword">INNER</span> <span class="token keyword">JOIN</span> orderdetail <span class="token keyword">AS</span> od <span class="token keyword">ON</span> od<span class="token punctuation">.</span>orderid <span class="token operator">=</span> o<span class="token punctuation">.</span>id
  <span class="token keyword">INNER</span> <span class="token keyword">JOIN</span> employee <span class="token keyword">AS</span> e <span class="token keyword">ON</span> o<span class="token punctuation">.</span>employeeid <span class="token operator">=</span> e<span class="token punctuation">.</span>id
  <span class="token keyword">INNER</span> <span class="token keyword">JOIN</span> customer <span class="token keyword">AS</span> c <span class="token keyword">ON</span> o<span class="token punctuation">.</span>customerid <span class="token operator">=</span> c<span class="token punctuation">.</span>id
  <span class="token keyword">WHERE</span>
    o<span class="token punctuation">.</span><span class="token keyword">date</span> <span class="token operator">IS</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span>
  <span class="token keyword">GROUP</span> <span class="token keyword">BY</span>
    o<span class="token punctuation">.</span>id<span class="token punctuation">,</span>
    e<span class="token punctuation">.</span>firstname<span class="token punctuation">,</span>
    e<span class="token punctuation">.</span>lastname<span class="token punctuation">,</span>
    c<span class="token punctuation">.</span>company
  <span class="token keyword">ORDER</span> <span class="token keyword">BY</span>
    o<span class="token punctuation">.</span><span class="token keyword">date</span> <span class="token keyword">DESC</span>
  <span class="token keyword">LIMIT</span> <span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">-- Product Reorder list (VIEW is used to keep it up-to-date)</span>
<span class="token keyword">CREATE</span> <span class="token operator">OR</span> <span class="token keyword">REPLACE</span> <span class="token keyword">VIEW</span> v_reorderlist
<span class="token keyword">SELECT</span>
  product <span class="token keyword">AS</span> name<span class="token punctuation">,</span> reorderthreshold<span class="token punctuation">,</span> unitsinstock<span class="token punctuation">,</span> unitsordered
<span class="token keyword">FROM</span>
  product
<span class="token keyword">WHERE</span>
  <span class="token punctuation">(</span>unitsinstock <span class="token operator">+</span> unitsordered<span class="token punctuation">)</span> <span class="token operator">&lt;</span> reorderthreshold<span class="token punctuation">;</span>
</code></pre>
<p>Next is to create a <code>TABLE</code> that will imitate <code>MATERIALIZED VIEW</code>.</p>
<pre class="language-sql"><code class="language-sql"><span class="token keyword">CREATE</span> <span class="token keyword">TABLE</span> mv_employeeleaderboard <span class="token keyword">AS</span>
<span class="token keyword">SELECT</span> <span class="token operator">*</span> <span class="token keyword">FROM</span> v_employeeleaderboard<span class="token punctuation">;</span>

<span class="token keyword">CREATE</span> <span class="token keyword">TABLE</span> mv_customerleaderboard <span class="token keyword">AS</span>
<span class="token keyword">SELECT</span> <span class="token operator">*</span> <span class="token keyword">FROM</span> v_customerleaderboard<span class="token punctuation">;</span>

<span class="token keyword">CREATE</span> <span class="token keyword">TABLE</span> mv_productleaderboard <span class="token keyword">AS</span>
<span class="token keyword">SELECT</span> <span class="token operator">*</span> <span class="token keyword">FROM</span> v_productleaderboard<span class="token punctuation">;</span>

<span class="token keyword">CREATE</span> <span class="token keyword">TABLE</span> mv_recentorders <span class="token keyword">AS</span>
<span class="token keyword">SELECT</span> <span class="token operator">*</span> <span class="token keyword">FROM</span> v_recentorders<span class="token punctuation">;</span>

<span class="token keyword">CREATE</span> <span class="token keyword">TRIGGER</span> dashboard_refresh_for_order_update
<span class="token keyword">AFTER</span> <span class="token keyword">UPDATE</span>
  <span class="token keyword">ON</span> <span class="token keyword">order</span> <span class="token keyword">FOR EACH ROW</span>
<span class="token keyword">BEGIN</span>
  <span class="token keyword">DELETE</span> <span class="token keyword">FROM</span> mv_employeeleaderboard<span class="token punctuation">;</span>
  <span class="token keyword">DELETE</span> <span class="token keyword">FROM</span> mv_customerleaderboard<span class="token punctuation">;</span>
  <span class="token keyword">DELETE</span> <span class="token keyword">FROM</span> mv_productleaderboard<span class="token punctuation">;</span>
  <span class="token keyword">DELETE</span> <span class="token keyword">FROM</span> mv_recentorders<span class="token punctuation">;</span>

  <span class="token keyword">INSERT</span> <span class="token keyword">INTO</span> mv_employeeleaderboard
  <span class="token keyword">SELECT</span> <span class="token operator">*</span> <span class="token keyword">FROM</span> v_employeeleaderboard<span class="token punctuation">;</span>

  <span class="token keyword">INSERT</span> <span class="token keyword">INTO</span> mv_customerleaderboard
  <span class="token keyword">SELECT</span> <span class="token operator">*</span> <span class="token keyword">FROM</span> v_customerleaderboard<span class="token punctuation">;</span>

  <span class="token keyword">INSERT</span> <span class="token keyword">INTO</span> mv_productleaderboard
  <span class="token keyword">SELECT</span> <span class="token operator">*</span> <span class="token keyword">FROM</span> v_productleaderboard<span class="token punctuation">;</span>

  <span class="token keyword">INSERT</span> <span class="token keyword">INTO</span> mv_recentorders
  <span class="token keyword">SELECT</span> <span class="token operator">*</span> <span class="token keyword">FROM</span> v_recentorders<span class="token punctuation">;</span>
<span class="token keyword">END</span><span class="token punctuation">;</span>

<span class="token keyword">CREATE</span> <span class="token keyword">TRIGGER</span> dashboard_refresh_for_delete
<span class="token keyword">AFTER</span> <span class="token keyword">DELETE</span>
  <span class="token keyword">ON</span> <span class="token keyword">order</span> <span class="token keyword">FOR EACH ROW</span>
<span class="token keyword">BEGIN</span>
  <span class="token keyword">DELETE</span> <span class="token keyword">FROM</span> mv_employeeleaderboard<span class="token punctuation">;</span>
  <span class="token keyword">DELETE</span> <span class="token keyword">FROM</span> mv_customerleaderboard<span class="token punctuation">;</span>
  <span class="token keyword">DELETE</span> <span class="token keyword">FROM</span> mv_productleaderboard<span class="token punctuation">;</span>
  <span class="token keyword">DELETE</span> <span class="token keyword">FROM</span> mv_recentorders<span class="token punctuation">;</span>

  <span class="token keyword">INSERT</span> <span class="token keyword">INTO</span> mv_employeeleaderboard
  <span class="token keyword">SELECT</span> <span class="token operator">*</span> <span class="token keyword">FROM</span> v_employeeleaderboard<span class="token punctuation">;</span>

  <span class="token keyword">INSERT</span> <span class="token keyword">INTO</span> mv_customerleaderboard
  <span class="token keyword">SELECT</span> <span class="token operator">*</span> <span class="token keyword">FROM</span> v_customerleaderboard<span class="token punctuation">;</span>

  <span class="token keyword">INSERT</span> <span class="token keyword">INTO</span> mv_productleaderboard
  <span class="token keyword">SELECT</span> <span class="token operator">*</span> <span class="token keyword">FROM</span> v_productleaderboard<span class="token punctuation">;</span>

  <span class="token keyword">INSERT</span> <span class="token keyword">INTO</span> mv_recentorders
  <span class="token keyword">SELECT</span> <span class="token operator">*</span> <span class="token keyword">FROM</span> v_recentorders<span class="token punctuation">;</span>
<span class="token keyword">END</span><span class="token punctuation">;</span>
</code></pre>
<p>And to revert the changes.</p>
<pre class="language-sql"><code class="language-sql"><span class="token keyword">DROP</span> <span class="token keyword">VIEW</span> v_employeeleaderboard<span class="token punctuation">;</span>
<span class="token keyword">DROP</span> <span class="token keyword">VIEW</span> v_customerleaderboard<span class="token punctuation">;</span>
<span class="token keyword">DROP</span> <span class="token keyword">VIEW</span> v_productleaderboard<span class="token punctuation">;</span>
<span class="token keyword">DROP</span> <span class="token keyword">VIEW</span> v_recentorders<span class="token punctuation">;</span>
<span class="token keyword">DROP</span> <span class="token keyword">VIEW</span> v_reorderlist<span class="token punctuation">;</span>

<span class="token keyword">DROP</span> <span class="token keyword">TABLE</span> <span class="token keyword">IF</span> <span class="token keyword">EXISTS</span> mv_customerleaderboard<span class="token punctuation">;</span>
<span class="token keyword">DROP</span> <span class="token keyword">TABLE</span> <span class="token keyword">IF</span> <span class="token keyword">EXISTS</span> mv_employeeleaderboard<span class="token punctuation">;</span>
<span class="token keyword">DROP</span> <span class="token keyword">TABLE</span> <span class="token keyword">IF</span> <span class="token keyword">EXISTS</span> mv_productleaderboard<span class="token punctuation">;</span>
<span class="token keyword">DROP</span> <span class="token keyword">TABLE</span> <span class="token keyword">IF</span> <span class="token keyword">EXISTS</span> mv_recentorders<span class="token punctuation">;</span>

<span class="token keyword">DROP</span> <span class="token keyword">TRIGGER</span> <span class="token keyword">IF</span> <span class="token keyword">EXISTS</span> dashboard_refresh_for_order_update<span class="token punctuation">;</span>
<span class="token keyword">DROP</span> <span class="token keyword">TRIGGER</span> <span class="token keyword">IF</span> <span class="token keyword">EXISTS</span> dashboard_refresh_for_order_delete<span class="token punctuation">;</span>
</code></pre>
<h2>Final</h2>
<p>In the end this will significantly speedup the dashboard loading. In a future project I will create a logistics mock application that will feature this enhancement.</p>
<p><strong>PS:</strong> To use the views in your application code:</p>
<pre class="language-sql"><code class="language-sql"><span class="token keyword">SELECT</span> <span class="token operator">*</span> <span class="token keyword">FROM</span> mv_employeeleaderboard<span class="token punctuation">;</span>
<span class="token keyword">SELECT</span> <span class="token operator">*</span> <span class="token keyword">FROM</span> mv_customerleaderboard<span class="token punctuation">;</span>
<span class="token keyword">SELECT</span> <span class="token operator">*</span> <span class="token keyword">FROM</span> mv_productleaderboard<span class="token punctuation">;</span>
<span class="token keyword">SELECT</span> <span class="token operator">*</span> <span class="token keyword">FROM</span> mv_recentorders<span class="token punctuation">;</span>
<span class="token keyword">SELECT</span> <span class="token operator">*</span> <span class="token keyword">FROM</span> v_reorderlist<span class="token punctuation">;</span>
</code></pre>]]></content:encoded>
            <author>anton@azdanov.dev (Anton Ždanov)</author>
        </item>
        <item>
            <title><![CDATA[Generating MD5 Hashes in a Browser]]></title>
            <link>https://www.azdanov.dev/articles/2019/generate-md5-hashes-in-a-browser</link>
            <guid isPermaLink="false">https://www.azdanov.dev/articles/2019/generate-md5-hashes-in-a-browser</guid>
            <pubDate>Fri, 08 Mar 2019 08:40:51 GMT</pubDate>
            <content:encoded><![CDATA[<img alt="study" loading="lazy" width="1200" height="630" decoding="async" data-nimg="1" style="color:transparent" srcset="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fstudy.0pvgn-5savw_c.png&amp;w=1200&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fstudy.0pvgn-5savw_c.png&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fstudy.0pvgn-5savw_c.png&amp;w=3840&amp;q=75">
<p>One day I stumbled upon an interesting question: "How to generate a list of hashes for all the page images inside the browser?". It got me intrigued about how versatile JavaScript actually is. Thus here are the result of that endeavor.</p>
<h2>Prelude</h2>
<p>I will be using <a href="https://picsum.photos/">https://picsum.photos/</a> since there are no CORS issues. For any other website an extension/flag might be required to disable CORS protection inside the browser.</p>
<p>For the MD5 library there are many choices, through trial and error I've selected <a href="https://github.com/emn178/js-md5/">https://github.com/emn178/js-md5/</a>. The most common issue with others was lack of support for <code>ArrayBuffer</code> which resulted in incorrect hash values.</p>
<h2>Loading an External Package</h2>
<p>While this might sound daunting at first, it's not that bad. Most packages can be executed inside the browser without any compilation via babel/webpack.</p>
<p>Inside the browser console it is done by creating a <code>script</code> element and adding a source to the script file. In our case the source will be <a href="https://cdn.jsdelivr.net/npm/js-md5@0.7.3/src/md5.min.js">https://cdn.jsdelivr.net/npm/js-md5@0.7.3/src/md5.min.js</a>.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> script <span class="token operator">=</span> <span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token method function property-access">createElement</span><span class="token punctuation">(</span><span class="token string">"script"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
script<span class="token punctuation">.</span><span class="token property-access">src</span> <span class="token operator">=</span> <span class="token string">"https://cdn.jsdelivr.net/npm/js-md5@0.7.3/src/md5.min.js"</span><span class="token punctuation">;</span>

<span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token method function property-access">querySelector</span><span class="token punctuation">(</span><span class="token string">"head"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">appendChild</span><span class="token punctuation">(</span>script<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<p>If there were no CORS issues then an <code>md5</code> function will be available inside the terminal.
<em>Note:</em> this can also be used to require <code>jQuery</code> or similar libraries to do some DOM heavy lifting.</p>
<h2>Getting the Sources</h2>
<p>Next it is necessary to find all the image sources on the page. With <code>ES6</code> it is a trivial task.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> imgs <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token spread operator">...</span><span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token method function property-access">querySelectorAll</span><span class="token punctuation">(</span><span class="token string">"img"</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">var</span> imgSrcs <span class="token operator">=</span> imgs<span class="token punctuation">.</span><span class="token method function property-access">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">i</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> i<span class="token punctuation">.</span><span class="token property-access">src</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<h2>Preparing to Fetch</h2>
<p>Now that <code>imgSrcs</code> array has all the sources a function is needed to fetch each source, and convert it into a <a href="https://developer.mozilla.org/en-US/docs/Web/API/Blob">Blob</a>. Also this blog object must be converted into an <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer">ArrayBuffer</a>. Most modern browsers have <a href="https://developer.mozilla.org/en-US/docs/Web/API/FileReader">FileReader</a> API that facilitates working with <code>Files</code> and <code>Blobs</code>. And last but not least <a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API">Fetch</a> is a modern replacement for <a href="https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest">XMLHttpRequest</a>.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> <span class="token function-variable function">getData</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">url</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span>
  <span class="token function">fetch</span><span class="token punctuation">(</span>url<span class="token punctuation">)</span>
    <span class="token punctuation">.</span><span class="token method function property-access">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">response</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> response<span class="token punctuation">.</span><span class="token method function property-access">blob</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
    <span class="token punctuation">.</span><span class="token method function property-access">then</span><span class="token punctuation">(</span>
      <span class="token punctuation">(</span><span class="token parameter">blob</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span>
        <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
          <span class="token keyword">const</span> reader <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">FileReader</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
          reader<span class="token punctuation">.</span><span class="token method-variable function-variable method function property-access">onloadend</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token function">resolve</span><span class="token punctuation">(</span>reader<span class="token punctuation">.</span><span class="token property-access">result</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
          reader<span class="token punctuation">.</span><span class="token property-access">onerror</span> <span class="token operator">=</span> reject<span class="token punctuation">;</span>
          reader<span class="token punctuation">.</span><span class="token method function property-access">readAsArrayBuffer</span><span class="token punctuation">(</span>blob<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<p>This function will be used later to generate a list of <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">Promises</a>. Inside the second <code>then</code> block a <code>new Promise</code> is created. It is necessary because <code>reader.readAsArrayBuffer</code> is an asynchronous operation, that triggers <code>onloadend</code> or <code>onerror</code> after a certain period of time.</p>
<h2>Making Promises</h2>
<p>It is time to send out the request for each image.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> promises <span class="token operator">=</span> <span class="token known-class-name class-name">Promise</span><span class="token punctuation">.</span><span class="token method function property-access">all</span><span class="token punctuation">(</span>imgSrcs<span class="token punctuation">.</span><span class="token method function property-access">map</span><span class="token punctuation">(</span>getData<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<p><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all">Promise.all</a> helps in reducing overall delay by sending out the fetch requests simultaneously. Of course it might fail if one image is corrupt.</p>
<h2>Creating Hashes</h2>
<p>Final step would be to iterate over the <code>promises</code> array, convert each <code>ArrayBuffer</code> into <code>md5</code> and print out the results.</p>
<pre class="language-js"><code class="language-js">promises
  <span class="token punctuation">.</span><span class="token method function property-access">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">buffers</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> buffers<span class="token punctuation">.</span><span class="token method function property-access">map</span><span class="token punctuation">(</span>md5<span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token method function property-access">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">hashes</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token console class-name">console</span><span class="token punctuation">.</span><span class="token method function property-access">log</span><span class="token punctuation">(</span>hashes<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<h2>Final</h2>
<p>There are many other things that could be tried. Another hashing algorithm such as <code>SHA256</code>. <a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API">Web Crypto</a> API could be used instead of injecting an external library (Only for SHA). And what about error handling, since <code>Promise.all</code> will throw an error if any of the promises fail.</p>
<p><em>Code:</em></p>
<pre class="language-js"><code class="language-js"><span class="token comment">// Get md5 library</span>
<span class="token keyword">var</span> md5 <span class="token operator">=</span> <span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token method function property-access">createElement</span><span class="token punctuation">(</span><span class="token string">"script"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
md5<span class="token punctuation">.</span><span class="token property-access">src</span> <span class="token operator">=</span> <span class="token string">"https://cdn.jsdelivr.net/npm/js-md5@0.7.3/src/md5.min.js"</span><span class="token punctuation">;</span>
<span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token method function property-access">querySelector</span><span class="token punctuation">(</span><span class="token string">"head"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">appendChild</span><span class="token punctuation">(</span>md5<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// Prepare function to get image blobs</span>
<span class="token keyword">var</span> <span class="token function-variable function">getData</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">url</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span>
  <span class="token function">fetch</span><span class="token punctuation">(</span>url<span class="token punctuation">)</span>
    <span class="token punctuation">.</span><span class="token method function property-access">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">response</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> response<span class="token punctuation">.</span><span class="token method function property-access">blob</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
    <span class="token punctuation">.</span><span class="token method function property-access">then</span><span class="token punctuation">(</span>
      <span class="token punctuation">(</span><span class="token parameter">blob</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span>
        <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
          <span class="token keyword">const</span> reader <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">FileReader</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
          reader<span class="token punctuation">.</span><span class="token method-variable function-variable method function property-access">onloadend</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token function">resolve</span><span class="token punctuation">(</span>reader<span class="token punctuation">.</span><span class="token property-access">result</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
          reader<span class="token punctuation">.</span><span class="token property-access">onerror</span> <span class="token operator">=</span> reject<span class="token punctuation">;</span>
          reader<span class="token punctuation">.</span><span class="token method function property-access">readAsArrayBuffer</span><span class="token punctuation">(</span>blob<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// Get image sources</span>
<span class="token keyword">var</span> imgSrcs <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token spread operator">...</span><span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token method function property-access">querySelectorAll</span><span class="token punctuation">(</span><span class="token string">"img"</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token method function property-access">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">i</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> i<span class="token punctuation">.</span><span class="token property-access">src</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// Load images</span>
<span class="token keyword">var</span> promises <span class="token operator">=</span> <span class="token known-class-name class-name">Promise</span><span class="token punctuation">.</span><span class="token method function property-access">all</span><span class="token punctuation">(</span>imgSrcs<span class="token punctuation">.</span><span class="token method function property-access">map</span><span class="token punctuation">(</span>getData<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// Calculate hashes</span>
promises
  <span class="token punctuation">.</span><span class="token method function property-access">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">buffers</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> buffers<span class="token punctuation">.</span><span class="token method function property-access">map</span><span class="token punctuation">(</span>md5<span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token method function property-access">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">hashes</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token console class-name">console</span><span class="token punctuation">.</span><span class="token method function property-access">log</span><span class="token punctuation">(</span>hashes<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<p>In the end I was satisfied with the results, because modern JavaScript is a powerful tool to know and use.</p>]]></content:encoded>
            <author>anton@azdanov.dev (Anton Ždanov)</author>
        </item>
        <item>
            <title><![CDATA[Create React App: Service Worker]]></title>
            <link>https://www.azdanov.dev/articles/2019/create-react-app-service-worker</link>
            <guid isPermaLink="false">https://www.azdanov.dev/articles/2019/create-react-app-service-worker</guid>
            <pubDate>Wed, 27 Feb 2019 09:26:57 GMT</pubDate>
            <content:encoded><![CDATA[<img alt="react" loading="lazy" width="1200" height="630" decoding="async" data-nimg="1" style="color:transparent" srcset="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Freact.17ltqoq0bclt3.jpeg&amp;w=1200&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Freact.17ltqoq0bclt3.jpeg&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Freact.17ltqoq0bclt3.jpeg&amp;w=3840&amp;q=75">
<p>When doing a recent project I decided to add offline capabilities. This was a <a href="https://translations.netlify.com/en/et/">dictionary app</a>
that relied on internet connectivity, and each new request was expensive time-wise.
Luckily, <a href="https://facebook.github.io/create-react-app/">Create React App</a> comes with an already
configured <a href="https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app">Service Worker</a> that eases turning a React project into a Progressive Web App.</p>
<h2>Enabling the Service Worker</h2>
<p>Inside <code>src/index.js</code> change <code>serviceWorker.unregister()</code> to <code>serviceWorker.register()</code>.</p>
<p>This will allow service worker to cache external resources and app files. Which for many use
cases is enough.</p>
<p>Note that by default service workers will update itself only on total page restart, which
means closing all tabs on a device and opening the app again. This can be confusing.</p>
<h2>Updating the Service Worker</h2>
<p>Sometimes updating the app is critical to its functionality. On a mobile device a
hidden open tab can prevent a service worker update. Which can lead to a lot of frustration
for both the developer and user.</p>
<p>The easiest way around this is to trigger a force update inside a service worker. This can be
potentially dangerous if the user enters any data inside the app, so keep that in mind.</p>
<p>Currently, there's no way to add a <a href="https://developers.google.com/web/tools/workbox/modules/workbox-webpack-plugin#generateSW-skipWaiting">config option inside webpack</a> to enable this.</p>
<p>Let's do it manually, using <code>fs</code> module from node.</p>
<p>After running <code>npm build</code> a <code>build/service-worker.js</code> will be created:</p>
<pre class="language-js"><code class="language-js"><span class="token function">importScripts</span><span class="token punctuation">(</span>
  <span class="token string">"https://storage.googleapis.com/workbox-cdn/releases/3.6.3/workbox-sw.js"</span><span class="token punctuation">,</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token function">importScripts</span><span class="token punctuation">(</span><span class="token string">"/precache-manifest.1627229ec6fca0a0029e621a9027a2fd.js"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

workbox<span class="token punctuation">.</span><span class="token method function property-access">clientsClaim</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

self<span class="token punctuation">.</span><span class="token property-access">__precacheManifest</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token method function property-access">concat</span><span class="token punctuation">(</span>self<span class="token punctuation">.</span><span class="token property-access">__precacheManifest</span> <span class="token operator">||</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
workbox<span class="token punctuation">.</span><span class="token property-access">precaching</span><span class="token punctuation">.</span><span class="token method function property-access">suppressWarnings</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
workbox<span class="token punctuation">.</span><span class="token property-access">precaching</span><span class="token punctuation">.</span><span class="token method function property-access">precacheAndRoute</span><span class="token punctuation">(</span>self<span class="token punctuation">.</span><span class="token property-access">__precacheManifest</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

workbox<span class="token punctuation">.</span><span class="token property-access">routing</span><span class="token punctuation">.</span><span class="token method function property-access">registerNavigationRoute</span><span class="token punctuation">(</span><span class="token string">"/index.html"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
  <span class="token literal-property property">blacklist</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">^\/_</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">,</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\/[^\/]+\.[^\/]+$</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<p>To enable force an update <code>self.skipWaiting()</code> needs to be added here.</p>
<p>And node is well suited for this job.</p>
<ol>
<li>Create a file <code>modifyServiceWorker.js</code></li>
</ol>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> fs <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"fs"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

fs<span class="token punctuation">.</span><span class="token method function property-access">readFile</span><span class="token punctuation">(</span><span class="token string">"build/service-worker.js"</span><span class="token punctuation">,</span> <span class="token string">"utf8"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">err<span class="token punctuation">,</span> data</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token keyword control-flow">return</span> <span class="token console class-name">console</span><span class="token punctuation">.</span><span class="token method function property-access">error</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> snippet <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">
self.addEventListener('install', event =&gt; {
  self.skipWaiting();
});
  </span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> result <span class="token operator">=</span> data<span class="token punctuation">.</span><span class="token method function property-access">replace</span><span class="token punctuation">(</span>
    <span class="token string">"workbox.clientsClaim();"</span><span class="token punctuation">,</span>
    <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">workbox.clientsClaim();\n</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>snippet<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>

  fs<span class="token punctuation">.</span><span class="token method function property-access">writeFile</span><span class="token punctuation">(</span><span class="token string">"build/service-worker.js"</span><span class="token punctuation">,</span> result<span class="token punctuation">,</span> <span class="token string">"utf8"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">readError</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>readError<span class="token punctuation">)</span> <span class="token keyword control-flow">return</span> <span class="token console class-name">console</span><span class="token punctuation">.</span><span class="token method function property-access">log</span><span class="token punctuation">(</span>readError<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<ol start="2">
<li>Modify the npm build script</li>
</ol>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"scripts"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"build"</span><span class="token operator">:</span> <span class="token string">"react-scripts build &amp;&amp; node modifyServiceWorker.js"</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>This will skip the <code>waiting</code> lifecycle of service worker and update it immediately, which
can be good and bad. This depends on the app itself.</p>
<h2>Prompting the user to update</h2>
<p>For better user experience would be to ask the user if they are ready for an update.</p>
<p>This is slightly more complicated, but in the end more considerate.</p>
<p>To achieve such behavior we need to display a button, that will send a message to the service
worker on clicking it. Here is a general idea:</p>
<ol>
<li>Adjust <code>modifyServiceWorker.js</code> to listen for a <code>message</code></li>
</ol>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> fs <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"fs"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

fs<span class="token punctuation">.</span><span class="token method function property-access">readFile</span><span class="token punctuation">(</span><span class="token string">"build/service-worker.js"</span><span class="token punctuation">,</span> <span class="token string">"utf8"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">err<span class="token punctuation">,</span> data</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token keyword control-flow">return</span> <span class="token console class-name">console</span><span class="token punctuation">.</span><span class="token method function property-access">error</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> snippet <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">
  addEventListener('message', messageEvent =&gt; {
    if (messageEvent.data === 'skipWaiting') return skipWaiting();
  });
  </span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> result <span class="token operator">=</span> data<span class="token punctuation">.</span><span class="token method function property-access">replace</span><span class="token punctuation">(</span>
    <span class="token string">"workbox.clientsClaim();"</span><span class="token punctuation">,</span>
    <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">workbox.clientsClaim();\n</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>snippet<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>

  fs<span class="token punctuation">.</span><span class="token method function property-access">writeFile</span><span class="token punctuation">(</span><span class="token string">"build/service-worker.js"</span><span class="token punctuation">,</span> result<span class="token punctuation">,</span> <span class="token string">"utf8"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">readError</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>readError<span class="token punctuation">)</span> <span class="token keyword control-flow">return</span> <span class="token console class-name">console</span><span class="token punctuation">.</span><span class="token method function property-access">log</span><span class="token punctuation">(</span>readError<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<ol start="2">
<li>Modify <code>serviceWorker.js</code> and trigger an <code>onUpdate</code> hooks for <code>registration.waiting</code></li>
</ol>
<pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">registerValidSW</span><span class="token punctuation">(</span><span class="token parameter">swUrl<span class="token punctuation">,</span> config</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token dom variable">navigator</span><span class="token punctuation">.</span><span class="token property-access">serviceWorker</span><span class="token punctuation">.</span><span class="token method function property-access">register</span><span class="token punctuation">(</span>swUrl<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">registration</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>registration<span class="token punctuation">.</span><span class="token property-access">waiting</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token comment">// Prompt user to update service workers</span>
      <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>config <span class="token operator">&amp;&amp;</span> config<span class="token punctuation">.</span><span class="token property-access">onUpdate</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        config<span class="token punctuation">.</span><span class="token method function property-access">onUpdate</span><span class="token punctuation">(</span>registration<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>

    registration<span class="token punctuation">.</span><span class="token method-variable function-variable method function property-access">onupdatefound</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
      <span class="token comment">// ...</span>
      installing<span class="token punctuation">.</span><span class="token method-variable function-variable method function property-access">onstatechange</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
        <span class="token comment">// ...</span>
      <span class="token punctuation">}</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre>
<ol start="3">
<li>Add a <code>div</code> inside <code>public/index.html</code> for rendering messages</li>
</ol>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>worker-message<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
</code></pre>
<ol start="4">
<li>Use the <code>onUpdate</code> hooks inside <code>index.js</code>:</li>
</ol>
<pre class="language-jsx"><code class="language-jsx">serviceWorker<span class="token punctuation">.</span><span class="token method function property-access">register</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token function-variable function">onUpdate</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">registration</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>registration<span class="token punctuation">.</span><span class="token property-access">waiting</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token maybe-class-name">ReactDOM</span><span class="token punctuation">.</span><span class="token method function property-access">render</span><span class="token punctuation">(</span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">ServiceWorkerMessage</span></span> <span class="token attr-name">registration</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>registration<span class="token punctuation">}</span></span> <span class="token punctuation">/&gt;</span></span><span class="token punctuation">,</span>
        <span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token method function property-access">querySelector</span><span class="token punctuation">(</span><span class="token string">"#worker-message"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
      <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<ol start="5">
<li>Create <code>ServiceWorkerMessage</code> that will work in two steps by sending a message and listening for a change event</li>
</ol>
<pre class="language-jsx"><code class="language-jsx"><span class="token keyword module">import</span> <span class="token imports"><span class="token maybe-class-name">React</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> useState<span class="token punctuation">,</span> useEffect <span class="token punctuation">}</span></span> <span class="token keyword module">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span>

<span class="token keyword module">export</span> <span class="token keyword">const</span> <span class="token function-variable function"><span class="token maybe-class-name">ServiceWorkerMessage</span></span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> registration <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>show<span class="token punctuation">,</span> setShow<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token dom variable">navigator</span><span class="token punctuation">.</span><span class="token property-access">serviceWorker</span><span class="token punctuation">.</span><span class="token method function property-access">addEventListener</span><span class="token punctuation">(</span><span class="token string">"controllerchange"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
      <span class="token dom variable">window</span><span class="token punctuation">.</span><span class="token property-access">location</span><span class="token punctuation">.</span><span class="token method function property-access">reload</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword control-flow">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">React.Fragment</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
      </span><span class="token punctuation">{</span>show <span class="token operator">&amp;&amp;</span> <span class="token punctuation">(</span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>message<span class="token punctuation">"</span></span> <span class="token attr-name">role</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>alert<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
          </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>message__text<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
            Your app is ready for an update. Please save any data before
            proceeding.
          </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
          </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span>
            <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>message__button<span class="token punctuation">"</span></span>
            <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
              <span class="token function">setShow</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
              registration<span class="token punctuation">.</span><span class="token property-access">waiting</span><span class="token punctuation">.</span><span class="token method function property-access">postMessage</span><span class="token punctuation">(</span><span class="token string">"skipWaiting"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span><span class="token punctuation">}</span></span>
          <span class="token punctuation">&gt;</span></span><span class="token plain-text">
            Update
          </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
        </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
      <span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token plain-text">
    </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span><span class="token class-name">React.Fragment</span></span><span class="token punctuation">&gt;</span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre>
<p>On clicking the <code>Update</code> button all open tabs inside the browser will be refreshed.</p>
<img alt="Update Message Popup" loading="lazy" width="2784" height="1778" decoding="async" data-nimg="1" style="color:transparent" srcset="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fmessage.0yq_2wkjqb_wq.png&amp;w=3840&amp;q=75 1x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fmessage.0yq_2wkjqb_wq.png&amp;w=3840&amp;q=75">
<p>You can view the <a href="https://github.com/azdanov/crasw">GitHub Repo</a> for a working example.</p>
<h2>Recap</h2>
<p>There are many ways to update a service worker. We've seen three:</p>
<ul>
<li>Background update, that works when user manually closes all the tabs</li>
<li>Force with a <code>skipWaiting</code> inside the service worker.</li>
<li>Prompt user for an action that refreshes all the open tabs.</li>
</ul>
<p>For more information on service worker read the excellent documentation on <a href="https://developers.google.com/web/tools/workbox/guides/get-started">developers.google.com</a>.</p>]]></content:encoded>
            <author>anton@azdanov.dev (Anton Ždanov)</author>
        </item>
        <item>
            <title><![CDATA[Using Docker for Laravel Development]]></title>
            <link>https://www.azdanov.dev/articles/2018/using-docker-for-laravel-development</link>
            <guid isPermaLink="false">https://www.azdanov.dev/articles/2018/using-docker-for-laravel-development</guid>
            <pubDate>Mon, 12 Nov 2018 07:25:42 GMT</pubDate>
            <content:encoded><![CDATA[<img alt="Docker" loading="lazy" width="1200" height="630" decoding="async" data-nimg="1" style="color:transparent" srcset="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fdocker-social.0xd70e7wkb9bu.png&amp;w=1200&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fdocker-social.0xd70e7wkb9bu.png&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fdocker-social.0xd70e7wkb9bu.png&amp;w=3840&amp;q=75">
<p>Docker can be a good replacement for <a href="https://laravel.com/docs/master/homestead">Homestead</a> and <a href="https://laravel.com/docs/master/valet">Valet</a> when developing a project that needs to be shared with developers working on different operating systems (Linux, Windows, MacOS) and having special requirements not covered by installing homestead. With smaller projects, Valet works fine, and Homestead can support larger projects due to preinstalled packages both of them have limitations. For Valet it's the issue of installing all the project's dependencies on a local machine which must be reinstalled to accommodate specific requirements. And Homestead is bulky, slow, includes a lot of unnecessary packages.</p>
<p>Docker in a way follows the "Composition over inheritance" principle by providing necessary smaller images to compose an environment instead of using a prebuilt monolith with bloat.</p>
<h2>docker-compose cheatsheet</h2>
<p><strong>Note:</strong> you need to <code>cd</code> first to where your <code>docker-compose.yml</code> is located.</p>
<ul>
<li>Start containers in the background: <code>docker-compose up -d</code></li>
<li>Start containers on the foreground: <code>docker-compose up</code>. You will see a stream of logs for every container running.</li>
<li>Stop containers: <code>docker-compose stop</code></li>
<li>Kill containers: <code>docker-compose kill</code></li>
<li>View container logs: <code>docker-compose logs</code></li>
<li>Execute command inside container: <code>docker-compose exec SERVICE_NAME COMMAND</code> where <code>COMMAND</code> is whatever you want to run. Examples:<!-- -->
<ul>
<li>Open shell, <code>docker-compose exec nginx sh</code></li>
<li>Run migrations, <code>docker-compose exec php php artisan migrate</code></li>
<li>Open psql shell, <code>docker-compose exec postgres sudo -u postgres psql postgres</code></li>
</ul>
</li>
</ul>
<h2>Basic Setup</h2>
<p>To get started Laravel requires three basics: a web-server, a database and php. I will be using Nginx, PHP-FPM and PostgreSQL.</p>
<p>Minimal <code>docker-compose.yml</code> for docker:</p>
<p>I will be using <code>alpine</code> images to speed-up download times. And pre-built <code>jguyomard/laravel-php:7.2</code> image, which includes all the necessary Laravel dependencies. It is possible to add extra packages and build your own <code>php</code> image. Just copy this <a href="https://hub.docker.com/r/jguyomard/laravel-php/~/dockerfile/">Dockerfile</a> and modify as needed. Here is a good example on <a href="https://github.com/ElisDN/laravel-demo-board/blob/f44e8d3bc6416a16a42f1fa408d1a20b730b0491/docker-compose.yml#L4-L6">ElisDN Laravel Demo</a>. But I prefer images stored in the <a href="https://hub.docker.com">hub.docker.com</a> as it removes the build step.</p>
<p>Notice that <code>${}</code> syntax is used to extract environment variables from <code>.env</code> file. And that I've created a <code>docker</code> folder with additional configuration files.</p>
<pre class="language-yaml"><code class="language-yaml"><span class="token key atrule">version</span><span class="token punctuation">:</span> <span class="token string">"3"</span>
<span class="token key atrule">services</span><span class="token punctuation">:</span>
  <span class="token key atrule">nginx</span><span class="token punctuation">:</span>
    <span class="token key atrule">image</span><span class="token punctuation">:</span> nginx<span class="token punctuation">:</span>1.15<span class="token punctuation">-</span>alpine
    <span class="token key atrule">volumes</span><span class="token punctuation">:</span>
      <span class="token punctuation">-</span> .<span class="token punctuation">:</span>/var/www/
      <span class="token punctuation">-</span> ./docker/nginx/default.conf<span class="token punctuation">:</span>/etc/nginx/conf.d/default.conf
    <span class="token key atrule">ports</span><span class="token punctuation">:</span>
      <span class="token punctuation">-</span> 8080<span class="token punctuation">:</span><span class="token number">80</span>
    <span class="token key atrule">depends_on</span><span class="token punctuation">:</span>
      <span class="token punctuation">-</span> php
      <span class="token punctuation">-</span> postgres
  <span class="token key atrule">php</span><span class="token punctuation">:</span>
    <span class="token key atrule">image</span><span class="token punctuation">:</span> jguyomard/laravel<span class="token punctuation">-</span>php<span class="token punctuation">:</span><span class="token number">7.2</span>
    <span class="token key atrule">volumes</span><span class="token punctuation">:</span>
      <span class="token punctuation">-</span> ./<span class="token punctuation">:</span>/var/www/
      <span class="token punctuation">-</span> $HOME/.composer/<span class="token punctuation">:</span>$HOME/.composer/
    <span class="token key atrule">environment</span><span class="token punctuation">:</span>
      <span class="token punctuation">-</span> DB_HOST=$<span class="token punctuation">{</span>DB_HOST<span class="token punctuation">}</span>
      <span class="token punctuation">-</span> DB_DATABASE=$<span class="token punctuation">{</span>DB_DATABASE<span class="token punctuation">}</span>
      <span class="token punctuation">-</span> DB_USERNAME=$<span class="token punctuation">{</span>DB_USERNAME<span class="token punctuation">}</span>
      <span class="token punctuation">-</span> DB_PASSWORD=$<span class="token punctuation">{</span>DB_PASSWORD<span class="token punctuation">}</span>
  <span class="token key atrule">postgres</span><span class="token punctuation">:</span>
    <span class="token key atrule">image</span><span class="token punctuation">:</span> postgres<span class="token punctuation">:</span>11<span class="token punctuation">-</span>alpine
    <span class="token key atrule">environment</span><span class="token punctuation">:</span>
      <span class="token punctuation">-</span> POSTGRES_DB=$<span class="token punctuation">{</span>DB_DATABASE<span class="token punctuation">}</span>
      <span class="token punctuation">-</span> POSTGRES_USER=$<span class="token punctuation">{</span>DB_USERNAME<span class="token punctuation">}</span>
      <span class="token punctuation">-</span> POSTGRES_PASSWORD=$<span class="token punctuation">{</span>DB_PASSWORD<span class="token punctuation">}</span>
    <span class="token key atrule">ports</span><span class="token punctuation">:</span>
      <span class="token punctuation">-</span> 5432<span class="token punctuation">:</span><span class="token number">5432</span>
    <span class="token key atrule">volumes</span><span class="token punctuation">:</span>
      <span class="token punctuation">-</span> postgres<span class="token punctuation">-</span>data<span class="token punctuation">:</span>/var/lib/postgresql/data
<span class="token key atrule">volumes</span><span class="token punctuation">:</span>
  <span class="token key atrule">postgres-data</span><span class="token punctuation">:</span>
</code></pre>
<p>And <code>default.conf</code> for nginx:</p>
<p>Here <code>root /var/www/public;</code> must correspond to previously configured <code>volume</code> in <code>docker-compose.yml</code>. And <code>php</code> name in <code>fastcgi_pass php:9000;</code> line will be the one used to indicate the <code>php</code> service. For example if there are multiple php services <code>php-cli</code> and <code>php-fpm</code> this line will be <code>fastcgi_pass php-fpm:9000;</code>.</p>
<pre class="language-nginx"><code class="language-nginx"><span class="token directive"><span class="token keyword">server</span></span> <span class="token punctuation">{</span>
    <span class="token directive"><span class="token keyword">listen</span> <span class="token number">80</span></span><span class="token punctuation">;</span>
    <span class="token directive"><span class="token keyword">index</span> index.php index.html</span><span class="token punctuation">;</span>
    <span class="token directive"><span class="token keyword">root</span> /var/www/public</span><span class="token punctuation">;</span>
    <span class="token directive"><span class="token keyword">client_max_body_size</span> <span class="token number">32M</span></span><span class="token punctuation">;</span>

    <span class="token directive"><span class="token keyword">location</span> /</span> <span class="token punctuation">{</span>
        <span class="token directive"><span class="token keyword">try_files</span> <span class="token variable">$uri</span> /index.php?<span class="token variable">$args</span></span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token directive"><span class="token keyword">location</span> ~ \.php$</span> <span class="token punctuation">{</span>
        <span class="token directive"><span class="token keyword">fastcgi_split_path_info</span> ^(.+\.php)(/.+)$</span><span class="token punctuation">;</span>
        <span class="token directive"><span class="token keyword">fastcgi_pass</span> php:9000</span><span class="token punctuation">;</span>
        <span class="token directive"><span class="token keyword">fastcgi_index</span> index.php</span><span class="token punctuation">;</span>
        <span class="token directive"><span class="token keyword">include</span> fastcgi_params</span><span class="token punctuation">;</span>
        <span class="token directive"><span class="token keyword">fastcgi_param</span> SCRIPT_FILENAME <span class="token variable">$document_root</span><span class="token variable">$fastcgi_script_name</span></span><span class="token punctuation">;</span>
        <span class="token directive"><span class="token keyword">fastcgi_param</span> PATH_INFO <span class="token variable">$fastcgi_path_info</span></span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<h2>Adding Extras</h2>
<p>Once the basic development environment is setup it is possible to add additional images: <code>node</code> to build front-end assets, <code>redis</code> for caching, <code>mailhog</code> to catch outbound email, <code>elasticsearch</code> for speeding up search and doing analytics.</p>
<pre class="language-yaml"><code class="language-yaml"><span class="token key atrule">version</span><span class="token punctuation">:</span> <span class="token string">"3"</span>
<span class="token key atrule">services</span><span class="token punctuation">:</span>
  <span class="token key atrule">nginx</span><span class="token punctuation">:</span>
    <span class="token key atrule">image</span><span class="token punctuation">:</span> nginx<span class="token punctuation">:</span>1.15<span class="token punctuation">-</span>alpine
    <span class="token key atrule">volumes</span><span class="token punctuation">:</span>
      <span class="token punctuation">-</span> .<span class="token punctuation">:</span>/var/www/
      <span class="token punctuation">-</span> ./docker/nginx/default.conf<span class="token punctuation">:</span>/etc/nginx/conf.d/default.conf
    <span class="token key atrule">ports</span><span class="token punctuation">:</span>
      <span class="token punctuation">-</span> 8080<span class="token punctuation">:</span><span class="token number">80</span>
    <span class="token key atrule">depends_on</span><span class="token punctuation">:</span>
      <span class="token punctuation">-</span> php
      <span class="token punctuation">-</span> postgres
  <span class="token key atrule">php</span><span class="token punctuation">:</span>
    <span class="token key atrule">image</span><span class="token punctuation">:</span> jguyomard/laravel<span class="token punctuation">-</span>php<span class="token punctuation">:</span><span class="token number">7.2</span>
    <span class="token key atrule">volumes</span><span class="token punctuation">:</span>
      <span class="token punctuation">-</span> ./<span class="token punctuation">:</span>/var/www/
      <span class="token punctuation">-</span> $HOME/.composer/<span class="token punctuation">:</span>$HOME/.composer/
    <span class="token key atrule">environment</span><span class="token punctuation">:</span>
      <span class="token punctuation">-</span> DB_HOST=$<span class="token punctuation">{</span>DB_HOST<span class="token punctuation">}</span>
      <span class="token punctuation">-</span> DB_DATABASE=$<span class="token punctuation">{</span>DB_DATABASE<span class="token punctuation">}</span>
      <span class="token punctuation">-</span> DB_USERNAME=$<span class="token punctuation">{</span>DB_USERNAME<span class="token punctuation">}</span>
      <span class="token punctuation">-</span> DB_PASSWORD=$<span class="token punctuation">{</span>DB_PASSWORD<span class="token punctuation">}</span>
  <span class="token key atrule">postgres</span><span class="token punctuation">:</span>
    <span class="token key atrule">image</span><span class="token punctuation">:</span> postgres<span class="token punctuation">:</span>11<span class="token punctuation">-</span>alpine
    <span class="token key atrule">environment</span><span class="token punctuation">:</span>
      <span class="token punctuation">-</span> POSTGRES_DB=$<span class="token punctuation">{</span>DB_DATABASE<span class="token punctuation">}</span>
      <span class="token punctuation">-</span> POSTGRES_USER=$<span class="token punctuation">{</span>DB_USERNAME<span class="token punctuation">}</span>
      <span class="token punctuation">-</span> POSTGRES_PASSWORD=$<span class="token punctuation">{</span>DB_PASSWORD<span class="token punctuation">}</span>
    <span class="token key atrule">ports</span><span class="token punctuation">:</span>
      <span class="token punctuation">-</span> 5432<span class="token punctuation">:</span><span class="token number">5432</span>
    <span class="token key atrule">volumes</span><span class="token punctuation">:</span>
      <span class="token punctuation">-</span> postgres<span class="token punctuation">-</span>data<span class="token punctuation">:</span>/var/lib/postgresql/data
      <span class="token punctuation">-</span> ./docker/conf/postgres/<span class="token punctuation">:</span>/docker<span class="token punctuation">-</span>entrypoint<span class="token punctuation">-</span>initdb.d/
  <span class="token key atrule">node</span><span class="token punctuation">:</span>
    <span class="token key atrule">image</span><span class="token punctuation">:</span> node<span class="token punctuation">:</span>10.13<span class="token punctuation">-</span>alpine
    <span class="token key atrule">volumes</span><span class="token punctuation">:</span>
      <span class="token punctuation">-</span> ./<span class="token punctuation">:</span>/var/www
    <span class="token key atrule">working_dir</span><span class="token punctuation">:</span> /var/www
    <span class="token key atrule">tty</span><span class="token punctuation">:</span> <span class="token boolean important">true</span>
  <span class="token key atrule">redis</span><span class="token punctuation">:</span>
    <span class="token key atrule">image</span><span class="token punctuation">:</span> redis<span class="token punctuation">:</span><span class="token number">5.0</span>
    <span class="token key atrule">ports</span><span class="token punctuation">:</span>
      <span class="token punctuation">-</span> 6379<span class="token punctuation">:</span><span class="token number">6379</span>
  <span class="token key atrule">mailhog</span><span class="token punctuation">:</span>
    <span class="token key atrule">image</span><span class="token punctuation">:</span> mailhog/mailhog<span class="token punctuation">:</span>latest
    <span class="token key atrule">ports</span><span class="token punctuation">:</span>
      <span class="token punctuation">-</span> 1025<span class="token punctuation">:</span><span class="token number">1025</span>
      <span class="token punctuation">-</span> 8025<span class="token punctuation">:</span><span class="token number">8025</span>
  <span class="token key atrule">elasticsearch</span><span class="token punctuation">:</span>
    <span class="token key atrule">image</span><span class="token punctuation">:</span> docker.elastic.co/elasticsearch/elasticsearch<span class="token punctuation">:</span>6.4.3
    <span class="token key atrule">environment</span><span class="token punctuation">:</span>
      <span class="token punctuation">-</span> bootstrap.memory_lock=true
      <span class="token punctuation">-</span> <span class="token string">"ES_JAVA_OPTS=-Xms128m -Xmx128m"</span>
    <span class="token key atrule">ulimits</span><span class="token punctuation">:</span>
      <span class="token key atrule">memlock</span><span class="token punctuation">:</span>
        <span class="token key atrule">soft</span><span class="token punctuation">:</span> <span class="token number">-1</span>
        <span class="token key atrule">hard</span><span class="token punctuation">:</span> <span class="token number">-1</span>
    <span class="token key atrule">volumes</span><span class="token punctuation">:</span>
      <span class="token punctuation">-</span> elastic<span class="token punctuation">-</span>data<span class="token punctuation">:</span>/usr/share/elasticsearch/data
    <span class="token key atrule">ports</span><span class="token punctuation">:</span>
      <span class="token punctuation">-</span> 9200<span class="token punctuation">:</span><span class="token number">9200</span>
<span class="token key atrule">volumes</span><span class="token punctuation">:</span>
  <span class="token key atrule">postgres-data</span><span class="token punctuation">:</span>
  <span class="token key atrule">elastic-data</span><span class="token punctuation">:</span>
</code></pre>
<h3>Services exposed outside your environment</h3>
<p>You can access your application via <strong><code>localhost</code></strong>.</p>
<table><thead><tr><th>Service</th><th>Address outside containers</th></tr></thead><tbody><tr><td>Webserver (Nginx)</td><td><a href="http://localhost:8080">localhost:8080</a></td></tr><tr><td>Mailhog (WebUI)</td><td><a href="http://localhost:8025">localhost:8025</a></td></tr><tr><td>PostgreSQL (DB)</td><td><a href="http://localhost:5432">localhost:5432</a></td></tr><tr><td>ElasticSearch (REST)</td><td><a href="http://localhost:9200">localhost:9200</a></td></tr><tr><td>Redis (CLI)</td><td><a href="http://localhost:6379">localhost:6379</a></td></tr></tbody></table>
<h3>Hosts within your environment</h3>
<p>You'll need to configure your application to use any services you enabled:</p>
<table><thead><tr><th>Service</th><th>Hostname</th><th>Port number</th><th>Description</th></tr></thead><tbody><tr><td>PHP-fpm</td><td>php</td><td>9000</td><td>Used for nginx, composer and artisan</td></tr><tr><td>SMTP (Mailhog)</td><td>mailhog</td><td>1025</td><td>Catch outbound mail</td></tr><tr><td>HTTP (Mailhog)</td><td>mailhog</td><td>8025</td><td>Access a WebUI to view caught email</td></tr><tr><td>Node</td><td>node</td><td>8081</td><td>Build assets for frontend</td></tr><tr><td>PostgreSQL</td><td>postgres</td><td>5432</td><td>Application database</td></tr><tr><td>Redis</td><td>redis</td><td>6379</td><td>Cache service</td></tr><tr><td>ElasticSearch</td><td>elasticsearch</td><td>9200</td><td>Search service</td></tr></tbody></table>
<h2>Recommendations</h2>
<p>Here are some tips on using docker:</p>
<ul>
<li>Run composer outside the php container (if applicable), as doing so would install all your dependencies owned by <code>root</code> within your vendor folder.</li>
<li>Run commands (ie Symfony's console, or Laravel artisan) straight inside your container. You can easily open a shell as described above and do your thing from there.</li>
<li>On MacOS Docker is slow. This guide on <a href="https://laradock.io/#improve-speed-on-macos">laradock</a> might help. Another solution is described on <a href="https://medium.com/@sean.handley/how-to-set-up-docker-for-mac-with-native-nfs-145151458adc">medium</a>.</li>
</ul>]]></content:encoded>
            <author>anton@azdanov.dev (Anton Ždanov)</author>
        </item>
        <item>
            <title><![CDATA[Building My First Extension: Visual Studio Code]]></title>
            <link>https://www.azdanov.dev/articles/2018/building-my-first-extension-visual-studio-code</link>
            <guid isPermaLink="false">https://www.azdanov.dev/articles/2018/building-my-first-extension-visual-studio-code</guid>
            <pubDate>Sun, 16 Sep 2018 08:08:55 GMT</pubDate>
            <content:encoded><![CDATA[<img alt="extension social" loading="lazy" width="1200" height="630" decoding="async" data-nimg="1" style="color:transparent" srcset="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fextension-social.01hol9hl-79_n.png&amp;w=1200&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fextension-social.01hol9hl-79_n.png&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fextension-social.01hol9hl-79_n.png&amp;w=3840&amp;q=75">
<p>Building an extension at first seemed like a daunting task. There are so many new things to consider: Tooling, Testing, API, CI, CD and so on. And last but not least, what extension idea to realize. There are already so many amazing extensions out there, with great functionality. At first, it may seem impossible to build a similarly useful product. It is important to remember that everyone started in the same spot, and it took many months and community contributions to get to where they are now. It is useful about this process as a bunch consecutive layers on top of one another.</p>
<img alt="extension" loading="lazy" width="1200" height="1200" decoding="async" data-nimg="1" style="color:transparent" srcset="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fextension.0u_6yrlm.zlce.png&amp;w=1200&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fextension.0u_6yrlm.zlce.png&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fextension.0u_6yrlm.zlce.png&amp;w=3840&amp;q=75">
<h2>Points of Interest</h2>
<p>The easiest way to start is to find an existing extension and read the source while referencing the official <a href="https://code.visualstudio.com/docs/extensionAPI/vscode-api">VSCode API</a> overview. There are numerous simple extension projects out there: <a href="https://code.visualstudio.com/docs/extensions/example-hello-world">hello-world</a>, <a href="https://code.visualstudio.com/docs/extensions/example-word-count">word-coung</a>, <a href="https://github.com/vanister/duck-generator">duck-generator</a> and for more advanced cases <a href="https://code.visualstudio.com/docs/extensions/example-language-server">language-server</a>. And it is always useful to dig into similar projects. For example, if I want to build a spell checker it would be prudent to find any existing ones, read the code, find what is good, what is bad, how some problems are solved and is there a way to improve. It is even possible to abandon the idea of building an extension an instead contribute to the found project.</p>
<h2>Words of Encouragement</h2>
<p>Any new endeavor is scary. In a way, one might feel like a maritime explorer from the 15th century who is preparing for a voyage to unexplored lands. What motivates me is the feeling of discovering new things, exploring new ideas and perfecting my craft. So by focusing on the positive and ignoring the negative in such cases is necessary to progress further.</p>]]></content:encoded>
            <author>anton@azdanov.dev (Anton Ždanov)</author>
        </item>
        <item>
            <title><![CDATA[Exploring Haskell: Higher-order Functions]]></title>
            <link>https://www.azdanov.dev/articles/2018/exploring-haskell-higher-order-functions</link>
            <guid isPermaLink="false">https://www.azdanov.dev/articles/2018/exploring-haskell-higher-order-functions</guid>
            <pubDate>Sun, 09 Sep 2018 08:56:56 GMT</pubDate>
            <content:encoded><![CDATA[<img alt="exploring haskell higher order functions" loading="lazy" width="1199" height="630" decoding="async" data-nimg="1" style="color:transparent" srcset="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexploring-haskell-higher-order-functions.04l4tquw8-auw.png&amp;w=1200&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexploring-haskell-higher-order-functions.04l4tquw8-auw.png&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexploring-haskell-higher-order-functions.04l4tquw8-auw.png&amp;w=3840&amp;q=75">
<p>Higher-order functions allow common programming patterns to be encapsulated as functions.</p>
<h2>Basic Concepts</h2>
<p>A function that takes a function as an argument or returns a function as a result is called a higher-order function.
Because the term curried already exists for returning functions as results, the term higher-order is often just used for taking functions as arguments.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token hvariable">twice</span> <span class="token operator">::</span> <span class="token punctuation">(</span><span class="token hvariable">a</span> <span class="token operator">-&gt;</span> <span class="token hvariable">a</span><span class="token punctuation">)</span> <span class="token operator">-&gt;</span> <span class="token hvariable">a</span> <span class="token operator">-&gt;</span> <span class="token hvariable">a</span>
<span class="token hvariable">twice</span> <span class="token hvariable">f</span> <span class="token hvariable">x</span> <span class="token operator">=</span> <span class="token hvariable">f</span> <span class="token punctuation">(</span><span class="token hvariable">f</span> <span class="token hvariable">x</span><span class="token punctuation">)</span>

<span class="token hvariable">twice</span> <span class="token punctuation">(</span><span class="token operator">*</span><span class="token number">2</span><span class="token punctuation">)</span> <span class="token number">3</span> <span class="token comment">-- 12</span>
<span class="token hvariable">twice</span> <span class="token builtin">reverse</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">]</span> <span class="token comment">-- [1,2,3]</span>
</code></pre>
<h2>Processing Lists</h2>
<p>The standard library defines a number of useful higher-order functions for processing lists.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token builtin">map</span> <span class="token operator">::</span> <span class="token punctuation">(</span><span class="token hvariable">a</span> <span class="token operator">-&gt;</span> <span class="token hvariable">b</span><span class="token punctuation">)</span> <span class="token operator">-&gt;</span> <span class="token punctuation">[</span><span class="token hvariable">a</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token punctuation">[</span><span class="token hvariable">b</span><span class="token punctuation">]</span>
<span class="token builtin">map</span> <span class="token hvariable">f</span> <span class="token hvariable">xs</span> <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token hvariable">f</span> <span class="token hvariable">x</span> <span class="token operator">|</span> <span class="token hvariable">x</span> <span class="token operator">&lt;-</span> <span class="token hvariable">xs</span> <span class="token punctuation">]</span>
<span class="token operator">----</span>
<span class="token builtin">map</span> <span class="token operator">::</span> <span class="token punctuation">(</span><span class="token hvariable">a</span> <span class="token operator">-&gt;</span> <span class="token hvariable">b</span><span class="token punctuation">)</span> <span class="token operator">-&gt;</span> <span class="token punctuation">[</span><span class="token hvariable">a</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token punctuation">[</span><span class="token hvariable">b</span><span class="token punctuation">]</span>
<span class="token builtin">map</span> <span class="token hvariable">f</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>
<span class="token builtin">map</span> <span class="token hvariable">f</span> <span class="token punctuation">(</span><span class="token hvariable">x</span><span class="token operator">:</span><span class="token hvariable">xs</span><span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token hvariable">f</span> <span class="token hvariable">x</span> <span class="token operator">:</span> <span class="token builtin">map</span> <span class="token hvariable">f</span> <span class="token hvariable">xs</span>
<span class="token operator">----</span>
<span class="token builtin">map</span> <span class="token punctuation">(</span><span class="token operator">+</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">,</span><span class="token number">5</span><span class="token punctuation">,</span><span class="token number">7</span><span class="token punctuation">]</span> <span class="token comment">-- [2,4,6,8]</span>

<span class="token builtin">map</span> <span class="token builtin">even</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token punctuation">]</span> <span class="token comment">-- [False,True,False,True]</span>

<span class="token builtin">map</span> <span class="token builtin">reverse</span> <span class="token punctuation">[</span><span class="token string">"abc"</span><span class="token punctuation">,</span><span class="token string">"def"</span><span class="token punctuation">,</span><span class="token string">"ghi"</span><span class="token punctuation">]</span> <span class="token comment">-- ["cba","fed","ihg"]</span>
<span class="token operator">----</span>
<span class="token builtin">map</span> <span class="token punctuation">(</span><span class="token builtin">map</span> <span class="token punctuation">(</span><span class="token operator">+</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">[</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token punctuation">[</span><span class="token number">4</span><span class="token punctuation">,</span><span class="token number">5</span><span class="token punctuation">]</span><span class="token punctuation">]</span> <span class="token comment">-- { applying the outer map }</span>
↓
<span class="token punctuation">[</span><span class="token builtin">map</span> <span class="token punctuation">(</span><span class="token operator">+</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token builtin">map</span> <span class="token punctuation">(</span><span class="token operator">+</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">[</span><span class="token number">4</span><span class="token punctuation">,</span><span class="token number">5</span><span class="token punctuation">]</span><span class="token punctuation">]</span> <span class="token comment">-- { applying the inner maps }</span>
↓
<span class="token punctuation">[</span><span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token punctuation">[</span><span class="token number">5</span><span class="token punctuation">,</span><span class="token number">6</span><span class="token punctuation">]</span><span class="token punctuation">]</span>
</code></pre>
<pre class="language-haskell"><code class="language-haskell"><span class="token builtin">filter</span> <span class="token operator">::</span> <span class="token punctuation">(</span><span class="token hvariable">a</span> <span class="token operator">-&gt;</span> <span class="token constant">Bool</span><span class="token punctuation">)</span> <span class="token operator">-&gt;</span> <span class="token punctuation">[</span><span class="token hvariable">a</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token punctuation">[</span><span class="token hvariable">a</span><span class="token punctuation">]</span>
<span class="token builtin">filter</span> <span class="token hvariable">p</span> <span class="token hvariable">xs</span> <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token hvariable">x</span> <span class="token operator">|</span> <span class="token hvariable">x</span> <span class="token operator">&lt;-</span> <span class="token hvariable">xs</span><span class="token punctuation">,</span> <span class="token hvariable">p</span> <span class="token hvariable">x</span> <span class="token punctuation">]</span>
<span class="token operator">----</span>
<span class="token builtin">filter</span> <span class="token operator">::</span> <span class="token punctuation">(</span><span class="token hvariable">a</span> <span class="token operator">-&gt;</span> <span class="token constant">Bool</span><span class="token punctuation">)</span> <span class="token operator">-&gt;</span> <span class="token punctuation">[</span><span class="token hvariable">a</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token punctuation">[</span><span class="token hvariable">a</span><span class="token punctuation">]</span>
<span class="token builtin">filter</span> <span class="token hvariable">p</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>
<span class="token builtin">filter</span> <span class="token hvariable">p</span> <span class="token punctuation">(</span><span class="token hvariable">x</span> <span class="token operator">:</span> <span class="token hvariable">xs</span><span class="token punctuation">)</span> <span class="token operator">|</span> <span class="token hvariable">p</span> <span class="token hvariable">x</span>       <span class="token operator">=</span> <span class="token hvariable">x</span> <span class="token operator">:</span> <span class="token builtin">filter</span> <span class="token hvariable">p</span> <span class="token hvariable">xs</span>
                  <span class="token operator">|</span> <span class="token builtin">otherwise</span> <span class="token operator">=</span> <span class="token builtin">filter</span> <span class="token hvariable">p</span> <span class="token hvariable">xs</span>
<span class="token operator">----</span>
<span class="token builtin">filter</span> <span class="token builtin">even</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token operator">..</span><span class="token number">10</span><span class="token punctuation">]</span> <span class="token comment">-- [2,4,6,8,10]</span>

<span class="token builtin">filter</span> <span class="token punctuation">(</span><span class="token operator">&gt;</span> <span class="token number">5</span><span class="token punctuation">)</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token operator">..</span><span class="token number">10</span><span class="token punctuation">]</span> <span class="token comment">-- [6,7,8,9,10]</span>

<span class="token builtin">filter</span> <span class="token punctuation">(</span><span class="token operator">/=</span> <span class="token char string">' '</span><span class="token punctuation">)</span> <span class="token string">"abc def ghi"</span> <span class="token comment">-- "abcdefghi"</span>
</code></pre>
<pre class="language-haskell"><code class="language-haskell"><span class="token builtin">all</span> <span class="token builtin">even</span> <span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token punctuation">,</span><span class="token number">6</span><span class="token punctuation">,</span><span class="token number">8</span><span class="token punctuation">]</span> <span class="token comment">-- True</span>
<span class="token operator">----</span>
<span class="token builtin">any</span> <span class="token builtin">odd</span> <span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token punctuation">,</span><span class="token number">6</span><span class="token punctuation">,</span><span class="token number">8</span><span class="token punctuation">]</span> <span class="token comment">-- False</span>
<span class="token operator">----</span>
<span class="token builtin">takeWhile</span> <span class="token builtin">even</span> <span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token punctuation">,</span><span class="token number">6</span><span class="token punctuation">,</span><span class="token number">7</span><span class="token punctuation">,</span><span class="token number">8</span><span class="token punctuation">]</span> <span class="token comment">-- [2,4,6]</span>
<span class="token operator">----</span>
<span class="token builtin">dropWhile</span> <span class="token builtin">odd</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">,</span><span class="token number">5</span><span class="token punctuation">,</span><span class="token number">6</span><span class="token punctuation">,</span><span class="token number">7</span><span class="token punctuation">]</span> <span class="token comment">-- [6,7]</span>
</code></pre>
<h2>The foldr Function</h2>
<p>Many functions that take a list as their argument can be defined using the following pattern of recursion on lists:</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token hvariable">f</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>     <span class="token operator">=</span> <span class="token hvariable">v</span>
<span class="token hvariable">f</span> <span class="token punctuation">(</span><span class="token hvariable">x</span><span class="token operator">:</span><span class="token hvariable">xs</span><span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token hvariable">x</span> <span class="token operator">#</span> <span class="token hvariable">f</span> <span class="token hvariable">xs</span>
</code></pre>
<p>The function maps the empty list to a value <code>v</code>, and any non-empty list to an operator <code>#</code> applied to the head of the list and the result of recursively processed tail.</p>
<p>For example:</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token builtin">sum</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>       <span class="token operator">=</span> <span class="token number">0</span>
<span class="token builtin">sum</span> <span class="token punctuation">(</span><span class="token hvariable">x</span> <span class="token operator">:</span> <span class="token hvariable">xs</span><span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token hvariable">x</span> <span class="token operator">+</span> <span class="token builtin">sum</span> <span class="token hvariable">xs</span>
<span class="token operator">----</span>
<span class="token builtin">product</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>       <span class="token operator">=</span> <span class="token number">1</span>
<span class="token builtin">product</span> <span class="token punctuation">(</span><span class="token hvariable">x</span> <span class="token operator">:</span> <span class="token hvariable">xs</span><span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token hvariable">x</span> <span class="token operator">*</span> <span class="token builtin">product</span> <span class="token hvariable">xs</span>
<span class="token operator">----</span>
<span class="token builtin">or</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>       <span class="token operator">=</span> <span class="token constant">False</span>
<span class="token builtin">or</span> <span class="token punctuation">(</span><span class="token hvariable">x</span> <span class="token operator">:</span> <span class="token hvariable">xs</span><span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token hvariable">x</span> <span class="token operator">||</span> <span class="token builtin">or</span> <span class="token hvariable">xs</span>
<span class="token operator">----</span>
<span class="token builtin">and</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>       <span class="token operator">=</span> <span class="token constant">True</span>
<span class="token builtin">and</span> <span class="token punctuation">(</span><span class="token hvariable">x</span> <span class="token operator">:</span> <span class="token hvariable">xs</span><span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token hvariable">x</span> <span class="token operator">&amp;&amp;</span> <span class="token builtin">and</span> <span class="token hvariable">xs</span>
</code></pre>
<p>The higher-order library function foldr (fold right) encapsulates this pattern of recursion for defining functions on lists.</p>
<p>Fold right function assumes that the given operator associates to the right: <code>1+(2+(3+0))</code>.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token builtin">foldr</span> <span class="token operator">::</span> <span class="token punctuation">(</span><span class="token hvariable">a</span> <span class="token operator">-&gt;</span> <span class="token hvariable">b</span> <span class="token operator">-&gt;</span> <span class="token hvariable">b</span><span class="token punctuation">)</span> <span class="token operator">-&gt;</span> <span class="token hvariable">b</span> <span class="token operator">-&gt;</span> <span class="token punctuation">[</span><span class="token hvariable">a</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token hvariable">b</span>
<span class="token builtin">foldr</span> <span class="token hvariable">f</span> <span class="token hvariable">v</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>       <span class="token operator">=</span> <span class="token hvariable">v</span>
<span class="token builtin">foldr</span> <span class="token hvariable">f</span> <span class="token hvariable">v</span> <span class="token punctuation">(</span><span class="token hvariable">x</span> <span class="token operator">:</span> <span class="token hvariable">xs</span><span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token hvariable">f</span> <span class="token hvariable">x</span> <span class="token punctuation">(</span><span class="token builtin">foldr</span> <span class="token hvariable">f</span> <span class="token hvariable">v</span> <span class="token hvariable">xs</span><span class="token punctuation">)</span>
<span class="token operator">----</span>
<span class="token builtin">sum</span> <span class="token operator">::</span> <span class="token constant">Num</span> <span class="token hvariable">a</span> <span class="token operator">=&gt;</span> <span class="token punctuation">[</span><span class="token hvariable">a</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token hvariable">a</span>
<span class="token builtin">sum</span> <span class="token operator">=</span> <span class="token builtin">foldr</span> <span class="token punctuation">(</span><span class="token operator">+</span><span class="token punctuation">)</span> <span class="token number">0</span>
<span class="token operator">----</span>
<span class="token builtin">product</span> <span class="token operator">::</span> <span class="token constant">Num</span> <span class="token hvariable">a</span> <span class="token operator">=&gt;</span> <span class="token punctuation">[</span><span class="token hvariable">a</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token hvariable">a</span>
<span class="token builtin">product</span> <span class="token operator">=</span> <span class="token builtin">foldr</span> <span class="token punctuation">(</span><span class="token operator">*</span><span class="token punctuation">)</span> <span class="token number">1</span>
<span class="token operator">----</span>
<span class="token builtin">or</span> <span class="token operator">::</span> <span class="token punctuation">[</span><span class="token constant">Bool</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token constant">Bool</span>
<span class="token builtin">or</span> <span class="token operator">=</span> <span class="token builtin">foldr</span> <span class="token punctuation">(</span><span class="token operator">||</span><span class="token punctuation">)</span> <span class="token constant">False</span>
<span class="token operator">----</span>
<span class="token builtin">and</span> <span class="token operator">::</span> <span class="token punctuation">[</span><span class="token constant">Bool</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token constant">Bool</span>
<span class="token builtin">and</span> <span class="token operator">=</span> <span class="token builtin">foldr</span> <span class="token punctuation">(</span><span class="token operator">&amp;&amp;</span><span class="token punctuation">)</span> <span class="token constant">True</span>
</code></pre>
<p>It is easier to reason about <code>foldr f v</code> in a non-recursive way, as simply replacing each <code>:</code> (cons) operator in a list by the function <code>f</code>, and the empty list at the end by the value <code>v</code>.</p>
<p>For example, applying the function <code>foldr (+) 0</code> to the list <code>1 : (2 : (3 : []))</code> gives the result <code>1 + (2 + (3 + 0))</code> in which <code>:</code> and <code>[]</code> have been replaced by <code>+</code> and <code>0</code>.</p>
<p>A quick reminder: <code>[1,2,3]</code> and <code>1 : (2 : (3 : []))</code> are equivalent.</p>
<p>Many functions can be redefined with <code>foldr</code>:</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token builtin">length</span> <span class="token operator">::</span> <span class="token punctuation">[</span><span class="token hvariable">a</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token constant">Int</span>
<span class="token builtin">length</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>       <span class="token operator">=</span> <span class="token number">0</span>
<span class="token builtin">length</span> <span class="token punctuation">(</span><span class="token hvariable">_</span> <span class="token operator">:</span> <span class="token hvariable">xs</span><span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token number">1</span> <span class="token operator">+</span> <span class="token builtin">length</span> <span class="token hvariable">xs</span>
<span class="token operator">----</span>
<span class="token builtin">length</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">]</span>
↓
<span class="token number">1</span> <span class="token operator">:</span> <span class="token punctuation">(</span><span class="token number">2</span> <span class="token operator">:</span> <span class="token punctuation">(</span><span class="token number">3</span> <span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
↓
<span class="token number">1</span> <span class="token operator">+</span> <span class="token punctuation">(</span><span class="token number">1</span> <span class="token operator">+</span> <span class="token punctuation">(</span><span class="token number">1</span> <span class="token operator">+</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
↓
<span class="token number">3</span>
<span class="token operator">----</span>
<span class="token builtin">length</span> <span class="token operator">::</span> <span class="token punctuation">[</span><span class="token hvariable">a</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token constant">Int</span>
<span class="token builtin">length</span> <span class="token operator">=</span> <span class="token builtin">foldr</span> <span class="token punctuation">(</span><span class="token operator">\</span><span class="token hvariable">_</span> <span class="token hvariable">n</span> <span class="token operator">-&gt;</span> <span class="token number">1</span> <span class="token operator">+</span> <span class="token hvariable">n</span><span class="token punctuation">)</span> <span class="token number">0</span>

<span class="token operator">----</span>

<span class="token builtin">reverse</span> <span class="token operator">::</span> <span class="token punctuation">[</span><span class="token hvariable">a</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token punctuation">[</span><span class="token hvariable">a</span><span class="token punctuation">]</span>
<span class="token builtin">reverse</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>       <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>
<span class="token builtin">reverse</span> <span class="token punctuation">(</span><span class="token hvariable">x</span> <span class="token operator">:</span> <span class="token hvariable">xs</span><span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token builtin">reverse</span> <span class="token hvariable">xs</span> <span class="token operator">++</span> <span class="token punctuation">[</span><span class="token hvariable">x</span><span class="token punctuation">]</span>

<span class="token builtin">reverse</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">]</span>
↓
<span class="token number">1</span> <span class="token operator">:</span> <span class="token punctuation">(</span><span class="token number">2</span> <span class="token operator">:</span> <span class="token punctuation">(</span><span class="token number">3</span> <span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
↓
<span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">++</span> <span class="token punctuation">[</span><span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">++</span> <span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">++</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span>
<span class="token operator">----</span>
<span class="token hvariable">snoc</span> <span class="token hvariable">x</span> <span class="token hvariable">xs</span> <span class="token operator">=</span> <span class="token hvariable">xs</span> <span class="token operator">++</span> <span class="token punctuation">[</span><span class="token hvariable">x</span><span class="token punctuation">]</span> <span class="token comment">-- cons backwards</span>

<span class="token builtin">reverse</span> <span class="token operator">::</span> <span class="token punctuation">[</span><span class="token hvariable">a</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token punctuation">[</span><span class="token hvariable">a</span><span class="token punctuation">]</span>
<span class="token builtin">reverse</span> <span class="token operator">=</span> <span class="token builtin">foldr</span> <span class="token hvariable">snoc</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>
</code></pre>
<h2>The foldl Function</h2>
<p>Opposite of <code>foldr</code>, assumes that operator associates to the left: <code>((0+1)+2)+3</code>.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token builtin">foldl</span> <span class="token operator">::</span> <span class="token punctuation">(</span><span class="token hvariable">a</span> <span class="token operator">-&gt;</span> <span class="token hvariable">b</span> <span class="token operator">-&gt;</span> <span class="token hvariable">a</span><span class="token punctuation">)</span> <span class="token operator">-&gt;</span> <span class="token hvariable">a</span> <span class="token operator">-&gt;</span> <span class="token punctuation">[</span><span class="token hvariable">b</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token hvariable">a</span>
<span class="token builtin">foldl</span> <span class="token hvariable">f</span> <span class="token hvariable">v</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>       <span class="token operator">=</span> <span class="token hvariable">v</span>
<span class="token builtin">foldl</span> <span class="token hvariable">f</span> <span class="token hvariable">v</span> <span class="token punctuation">(</span><span class="token hvariable">x</span> <span class="token operator">:</span> <span class="token hvariable">xs</span><span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token builtin">foldl</span> <span class="token hvariable">f</span> <span class="token punctuation">(</span><span class="token hvariable">f</span> <span class="token hvariable">v</span> <span class="token hvariable">x</span><span class="token punctuation">)</span> <span class="token hvariable">xs</span>
</code></pre>
<p>It is useful for mapping the empty list to the accumulator value <code>v</code>, and any non-empty list to the result of recursively processing the tail using a new accumulator value obtained by applying an operator <code>#</code> to the current value and the head of the list.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token hvariable">f</span> <span class="token hvariable">v</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>     <span class="token operator">=</span> <span class="token hvariable">v</span>
<span class="token hvariable">f</span> <span class="token hvariable">v</span> <span class="token punctuation">(</span><span class="token hvariable">x</span><span class="token operator">:</span><span class="token hvariable">xs</span><span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token hvariable">f</span> <span class="token punctuation">(</span><span class="token hvariable">v</span> <span class="token operator">#</span> <span class="token hvariable">x</span><span class="token punctuation">)</span> <span class="token hvariable">xs</span>
</code></pre>
<p>When a function can be defined using both <code>foldr</code> and <code>foldl</code> the choice of which definition is preferable is usually based on efficiency and requires considering the evaluation mechanism of Haskell.</p>
<h2>The Composition Operator</h2>
<p>The standard operator <code>.</code> returns the composition of two functions as a single function.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token punctuation">(</span><span class="token punctuation">.</span><span class="token punctuation">)</span> <span class="token operator">::</span> <span class="token punctuation">(</span><span class="token hvariable">b</span> <span class="token operator">-&gt;</span> <span class="token hvariable">c</span><span class="token punctuation">)</span> <span class="token operator">-&gt;</span> <span class="token punctuation">(</span><span class="token hvariable">a</span> <span class="token operator">-&gt;</span> <span class="token hvariable">b</span><span class="token punctuation">)</span> <span class="token operator">-&gt;</span> <span class="token punctuation">(</span><span class="token hvariable">a</span> <span class="token operator">-&gt;</span> <span class="token hvariable">c</span><span class="token punctuation">)</span>
<span class="token hvariable">f</span> <span class="token operator">.</span> <span class="token hvariable">g</span> <span class="token operator">=</span> <span class="token operator">\</span><span class="token hvariable">x</span> <span class="token operator">-&gt;</span> <span class="token hvariable">f</span> <span class="token punctuation">(</span><span class="token hvariable">g</span> <span class="token hvariable">x</span><span class="token punctuation">)</span>
<span class="token operator">----</span>
<span class="token builtin">odd</span> <span class="token hvariable">n</span> <span class="token operator">=</span> <span class="token builtin">not</span> <span class="token punctuation">(</span><span class="token builtin">even</span> <span class="token hvariable">n</span><span class="token punctuation">)</span>
<span class="token builtin">odd</span> <span class="token operator">=</span> <span class="token builtin">not</span> <span class="token operator">.</span> <span class="token builtin">even</span>
<span class="token operator">----</span>
<span class="token hvariable">twice</span> <span class="token hvariable">f</span> <span class="token hvariable">x</span> <span class="token operator">=</span> <span class="token hvariable">f</span> <span class="token punctuation">(</span><span class="token hvariable">f</span> <span class="token hvariable">x</span><span class="token punctuation">)</span>
<span class="token hvariable">twice</span> <span class="token operator">=</span> <span class="token hvariable">f</span> <span class="token operator">.</span> <span class="token hvariable">f</span>
<span class="token operator">----</span>
<span class="token builtin">id</span> <span class="token operator">::</span> <span class="token hvariable">a</span> <span class="token operator">-&gt;</span> <span class="token hvariable">a</span>
<span class="token builtin">id</span> <span class="token operator">=</span> <span class="token operator">\</span><span class="token hvariable">x</span> <span class="token operator">-&gt;</span> <span class="token hvariable">x</span>
<span class="token comment">-- compose a list of functions</span>
<span class="token hvariable">compose</span> <span class="token operator">::</span> <span class="token punctuation">[</span><span class="token hvariable">a</span> <span class="token operator">-&gt;</span> <span class="token hvariable">a</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token punctuation">(</span><span class="token hvariable">a</span> <span class="token operator">-&gt;</span> <span class="token hvariable">a</span><span class="token punctuation">)</span>
<span class="token hvariable">compose</span> <span class="token operator">=</span> <span class="token builtin">foldr</span> <span class="token punctuation">(</span><span class="token punctuation">.</span><span class="token punctuation">)</span> <span class="token builtin">id</span>
</code></pre>
<p>Continuing later on.</p>]]></content:encoded>
            <author>anton@azdanov.dev (Anton Ždanov)</author>
        </item>
        <item>
            <title><![CDATA[Exploring Haskell: Recursive Functions]]></title>
            <link>https://www.azdanov.dev/articles/2018/exploring-haskell-recursive-functions</link>
            <guid isPermaLink="false">https://www.azdanov.dev/articles/2018/exploring-haskell-recursive-functions</guid>
            <pubDate>Wed, 05 Sep 2018 18:42:06 GMT</pubDate>
            <content:encoded><![CDATA[<img alt="exploring haskell recursive functions" loading="lazy" width="1199" height="630" decoding="async" data-nimg="1" style="color:transparent" srcset="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexploring-haskell-recursive-functions.0~jnsi1hge70w.png&amp;w=1200&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexploring-haskell-recursive-functions.0~jnsi1hge70w.png&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexploring-haskell-recursive-functions.0~jnsi1hge70w.png&amp;w=3840&amp;q=75">
<p>In Haskell recursion serves as the basic mechanism for looping.</p>
<h2>Basic Concepts</h2>
<p>It is possible to define a function which can call itself. This is the basic principle behind recursion.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token comment">-- Without recursion</span>
<span class="token hvariable">fac</span> <span class="token operator">::</span> <span class="token constant">Int</span> <span class="token operator">-&gt;</span> <span class="token constant">Int</span>
<span class="token hvariable">fac</span> <span class="token hvariable">n</span> <span class="token operator">=</span> <span class="token builtin">product</span> <span class="token punctuation">[</span><span class="token number">1</span> <span class="token operator">..</span> <span class="token hvariable">n</span><span class="token punctuation">]</span>

<span class="token comment">-- With recursion</span>
<span class="token hvariable">fac</span> <span class="token operator">::</span> <span class="token constant">Int</span> <span class="token operator">-&gt;</span> <span class="token constant">Int</span>
<span class="token hvariable">fac</span> <span class="token number">0</span> <span class="token operator">=</span> <span class="token number">1</span>
<span class="token hvariable">fac</span> <span class="token hvariable">n</span> <span class="token operator">=</span> <span class="token hvariable">n</span> <span class="token operator">*</span> <span class="token hvariable">fac</span> <span class="token punctuation">(</span><span class="token hvariable">n</span> <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span>

<span class="token comment">-- Which can be traced as:</span>

<span class="token hvariable">fac</span> <span class="token number">3</span> <span class="token comment">-- { applying fac }</span>
↓
<span class="token number">3</span> <span class="token operator">*</span> <span class="token hvariable">fac</span> <span class="token number">2</span> <span class="token comment">-- { applying fac }</span>
↓
<span class="token number">3</span> <span class="token operator">*</span> <span class="token punctuation">(</span><span class="token number">2</span> <span class="token operator">*</span> <span class="token hvariable">fac</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token comment">-- { applying fac }</span>
↓
<span class="token number">3</span> <span class="token operator">*</span> <span class="token punctuation">(</span><span class="token number">2</span> <span class="token operator">*</span> <span class="token punctuation">(</span><span class="token number">1</span> <span class="token operator">*</span> <span class="token hvariable">fac</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">-- { applying fac }</span>
↓
<span class="token number">3</span> <span class="token operator">*</span> <span class="token punctuation">(</span><span class="token number">2</span> <span class="token operator">*</span> <span class="token punctuation">(</span><span class="token number">1</span> <span class="token operator">*</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">-- { applying * }</span>
↓
<span class="token number">6</span>
</code></pre>
<p>Same for the multiplication function, which can be defined via multiple additions.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token punctuation">(</span><span class="token operator">*</span><span class="token punctuation">)</span> <span class="token operator">::</span> <span class="token constant">Int</span> <span class="token operator">-&gt;</span> <span class="token constant">Int</span> <span class="token operator">-&gt;</span> <span class="token constant">Int</span>
<span class="token hvariable">m</span> <span class="token operator">*</span> <span class="token number">0</span> <span class="token operator">=</span> <span class="token number">0</span>
<span class="token hvariable">m</span> <span class="token operator">*</span> <span class="token hvariable">n</span> <span class="token operator">=</span> <span class="token hvariable">m</span> <span class="token operator">+</span> <span class="token punctuation">(</span><span class="token hvariable">m</span> <span class="token operator">*</span> <span class="token punctuation">(</span><span class="token hvariable">n</span> <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

<span class="token number">4</span> <span class="token operator">*</span> <span class="token number">3</span> <span class="token comment">-- { applying * }</span>
↓
<span class="token number">4</span> <span class="token operator">+</span> <span class="token punctuation">(</span><span class="token number">4</span> <span class="token operator">*</span> <span class="token number">2</span><span class="token punctuation">)</span> <span class="token comment">-- { applying * }</span>
↓
<span class="token number">4</span> <span class="token operator">+</span> <span class="token punctuation">(</span><span class="token number">4</span> <span class="token operator">+</span> <span class="token punctuation">(</span><span class="token number">4</span> <span class="token operator">*</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">-- { applying * }</span>
↓
<span class="token number">4</span> <span class="token operator">+</span> <span class="token punctuation">(</span><span class="token number">4</span> <span class="token operator">+</span> <span class="token punctuation">(</span><span class="token number">4</span> <span class="token operator">+</span> <span class="token punctuation">(</span><span class="token number">4</span> <span class="token operator">*</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">-- { applying * }</span>
↓
<span class="token number">4</span> <span class="token operator">+</span> <span class="token punctuation">(</span><span class="token number">4</span> <span class="token operator">+</span> <span class="token punctuation">(</span><span class="token number">4</span> <span class="token operator">+</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">-- { applying + }</span>
↓
<span class="token number">12</span>
</code></pre>
<h2>Recursion on Lists</h2>
<p>Previously mentioned <code>product</code> function can be defined with recursion.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token builtin">product</span> <span class="token operator">::</span> <span class="token constant">Num</span> <span class="token hvariable">a</span> <span class="token operator">=&gt;</span> <span class="token punctuation">[</span><span class="token hvariable">a</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token hvariable">a</span>
<span class="token builtin">product</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>       <span class="token operator">=</span> <span class="token number">1</span>
<span class="token builtin">product</span> <span class="token punctuation">(</span><span class="token hvariable">n</span> <span class="token operator">:</span> <span class="token hvariable">ns</span><span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token hvariable">n</span> <span class="token operator">*</span> <span class="token builtin">product</span> <span class="token hvariable">ns</span>

<span class="token builtin">product</span> <span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token punctuation">]</span> <span class="token comment">-- { applying product }</span>
↓
<span class="token number">2</span> <span class="token operator">*</span> <span class="token builtin">product</span> <span class="token punctuation">[</span><span class="token number">3</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token punctuation">]</span> <span class="token comment">-- { applying product }</span>
↓
<span class="token number">2</span> <span class="token operator">*</span> <span class="token punctuation">(</span><span class="token number">3</span> <span class="token operator">*</span> <span class="token builtin">product</span> <span class="token punctuation">[</span><span class="token number">4</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token comment">-- { applying product }</span>
↓
<span class="token number">2</span> <span class="token operator">*</span> <span class="token punctuation">(</span><span class="token number">3</span> <span class="token operator">*</span> <span class="token punctuation">(</span><span class="token number">4</span> <span class="token operator">*</span> <span class="token builtin">product</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">-- { applying product }</span>
↓
<span class="token number">2</span> <span class="token operator">*</span> <span class="token punctuation">(</span><span class="token number">3</span> <span class="token operator">*</span> <span class="token punctuation">(</span><span class="token number">4</span> <span class="token operator">*</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">-- { applying * }</span>
↓
<span class="token number">24</span>
</code></pre>
<p>Function <code>length</code> can be defined in a similar way.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token builtin">length</span> <span class="token operator">::</span> <span class="token punctuation">[</span><span class="token hvariable">a</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token constant">Int</span>
<span class="token builtin">length</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>       <span class="token operator">=</span> <span class="token number">0</span>
<span class="token builtin">length</span> <span class="token punctuation">(</span><span class="token hvariable">_</span> <span class="token operator">:</span> <span class="token hvariable">xs</span><span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token number">1</span> <span class="token operator">+</span> <span class="token builtin">length</span> <span class="token hvariable">xs</span>
</code></pre>
<p>Defining <code>reverse</code> can be done this way.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token builtin">reverse</span> <span class="token operator">::</span> <span class="token punctuation">[</span><span class="token hvariable">a</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token punctuation">[</span><span class="token hvariable">a</span><span class="token punctuation">]</span>
<span class="token builtin">reverse</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>       <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>
<span class="token builtin">reverse</span> <span class="token punctuation">(</span><span class="token hvariable">x</span> <span class="token operator">:</span> <span class="token hvariable">xs</span><span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token builtin">reverse</span> <span class="token hvariable">xs</span> <span class="token operator">++</span> <span class="token punctuation">[</span><span class="token hvariable">x</span><span class="token punctuation">]</span>

<span class="token builtin">reverse</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">]</span> <span class="token comment">-- { applying reverse }</span>
↓
<span class="token builtin">reverse</span> <span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">]</span> <span class="token operator">++</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span> <span class="token comment">-- { applying reverse }</span>
↓
<span class="token punctuation">(</span><span class="token builtin">reverse</span> <span class="token punctuation">[</span><span class="token number">3</span><span class="token punctuation">]</span> <span class="token operator">++</span> <span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">++</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span> <span class="token comment">-- { applying reverse }</span>
↓
<span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token builtin">reverse</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">++</span> <span class="token punctuation">[</span><span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">++</span> <span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">++</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span> <span class="token comment">-- { applying reverse }</span>
↓
<span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">++</span> <span class="token punctuation">[</span><span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">++</span> <span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">++</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span> <span class="token comment">-- { applying ++ }</span>
↓
<span class="token punctuation">[</span><span class="token number">3</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">1</span><span class="token punctuation">]</span>
</code></pre>
<p>And <code>++</code> operation.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token punctuation">(</span><span class="token operator">++</span><span class="token punctuation">)</span> <span class="token operator">::</span> <span class="token punctuation">[</span><span class="token hvariable">a</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token punctuation">[</span><span class="token hvariable">a</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token punctuation">[</span><span class="token hvariable">a</span><span class="token punctuation">]</span>
<span class="token punctuation">[</span><span class="token punctuation">]</span>       <span class="token operator">++</span> <span class="token hvariable">ys</span> <span class="token operator">=</span> <span class="token hvariable">ys</span>
<span class="token punctuation">(</span><span class="token hvariable">x</span> <span class="token operator">:</span> <span class="token hvariable">xs</span><span class="token punctuation">)</span> <span class="token operator">++</span> <span class="token hvariable">ys</span> <span class="token operator">=</span> <span class="token hvariable">x</span> <span class="token operator">:</span> <span class="token punctuation">(</span><span class="token hvariable">xs</span> <span class="token operator">++</span> <span class="token hvariable">ys</span><span class="token punctuation">)</span>

<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">]</span> <span class="token operator">++</span> <span class="token punctuation">[</span><span class="token number">4</span><span class="token punctuation">,</span><span class="token number">5</span><span class="token punctuation">]</span> <span class="token comment">-- { applying ++ }</span>
↓
<span class="token number">1</span> <span class="token operator">:</span> <span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">]</span> <span class="token operator">++</span> <span class="token punctuation">[</span><span class="token number">4</span><span class="token punctuation">,</span><span class="token number">5</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token comment">-- { applying ++ }</span>
↓
<span class="token number">1</span> <span class="token operator">:</span> <span class="token punctuation">(</span><span class="token number">2</span> <span class="token operator">:</span> <span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token number">3</span><span class="token punctuation">]</span> <span class="token operator">++</span> <span class="token punctuation">[</span><span class="token number">4</span><span class="token punctuation">,</span><span class="token number">5</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">-- { applying ++ }</span>
↓
<span class="token number">1</span> <span class="token operator">:</span> <span class="token punctuation">(</span><span class="token number">2</span> <span class="token operator">:</span> <span class="token punctuation">(</span><span class="token number">3</span> <span class="token operator">:</span> <span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">++</span> <span class="token punctuation">[</span><span class="token number">4</span><span class="token punctuation">,</span><span class="token number">5</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">-- { applying ++ }</span>
↓
<span class="token number">1</span> <span class="token operator">:</span> <span class="token punctuation">(</span><span class="token number">2</span> <span class="token operator">:</span> <span class="token punctuation">(</span><span class="token number">3</span> <span class="token operator">:</span> <span class="token punctuation">[</span><span class="token number">4</span><span class="token punctuation">,</span><span class="token number">5</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">-- { list notation }</span>
↓
<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token punctuation">,</span><span class="token number">5</span><span class="token punctuation">]</span>
</code></pre>
<p>Here's a recursive function that inserts values to an ordered list.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token hvariable">insert</span> <span class="token operator">::</span> <span class="token constant">Ord</span> <span class="token hvariable">a</span> <span class="token operator">=&gt;</span> <span class="token hvariable">a</span> <span class="token operator">-&gt;</span> <span class="token punctuation">[</span><span class="token hvariable">a</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token punctuation">[</span><span class="token hvariable">a</span><span class="token punctuation">]</span>
<span class="token hvariable">insert</span> <span class="token hvariable">x</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token hvariable">x</span><span class="token punctuation">]</span>
<span class="token hvariable">insert</span> <span class="token hvariable">x</span> <span class="token punctuation">(</span><span class="token hvariable">y</span> <span class="token operator">:</span> <span class="token hvariable">ys</span><span class="token punctuation">)</span> <span class="token operator">|</span> <span class="token hvariable">x</span> <span class="token operator">&lt;=</span> <span class="token hvariable">y</span>    <span class="token operator">=</span> <span class="token hvariable">x</span> <span class="token operator">:</span> <span class="token hvariable">y</span> <span class="token operator">:</span> <span class="token hvariable">ys</span>
                  <span class="token operator">|</span> <span class="token builtin">otherwise</span> <span class="token operator">=</span> <span class="token hvariable">y</span> <span class="token operator">:</span> <span class="token hvariable">insert</span> <span class="token hvariable">x</span> <span class="token hvariable">ys</span>

<span class="token hvariable">insert</span> <span class="token number">3</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token punctuation">,</span><span class="token number">5</span><span class="token punctuation">]</span> <span class="token comment">-- { applying insert }</span>
↓
<span class="token number">1</span> <span class="token operator">:</span> <span class="token hvariable">insert</span> <span class="token number">3</span> <span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token punctuation">,</span><span class="token number">5</span><span class="token punctuation">]</span> <span class="token comment">-- { applying insert }</span>
↓
<span class="token number">1</span> <span class="token operator">:</span> <span class="token number">2</span> <span class="token operator">:</span> <span class="token hvariable">insert</span> <span class="token number">3</span> <span class="token punctuation">[</span><span class="token number">4</span><span class="token punctuation">,</span><span class="token number">5</span><span class="token punctuation">]</span> <span class="token comment">-- { applying insert }</span>
↓
<span class="token number">1</span> <span class="token operator">:</span> <span class="token number">2</span> <span class="token operator">:</span> <span class="token number">3</span> <span class="token operator">:</span> <span class="token punctuation">[</span><span class="token number">4</span><span class="token punctuation">,</span><span class="token number">5</span><span class="token punctuation">]</span> <span class="token comment">-- { list notation }</span>
↓
<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token punctuation">,</span><span class="token number">5</span><span class="token punctuation">]</span>
</code></pre>
<p>Using previously defined function creating <a href="https://en.wikipedia.org/wiki/Insertion_sort">insertion sort</a> becomes easy.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token hvariable">isort</span> <span class="token operator">::</span> <span class="token constant">Ord</span> <span class="token hvariable">a</span> <span class="token operator">=&gt;</span> <span class="token punctuation">[</span><span class="token hvariable">a</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token punctuation">[</span><span class="token hvariable">a</span><span class="token punctuation">]</span>
<span class="token hvariable">isort</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>       <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>
<span class="token hvariable">isort</span> <span class="token punctuation">(</span><span class="token hvariable">x</span> <span class="token operator">:</span> <span class="token hvariable">xs</span><span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token hvariable">insert</span> <span class="token hvariable">x</span> <span class="token punctuation">(</span><span class="token hvariable">isort</span> <span class="token hvariable">xs</span><span class="token punctuation">)</span>

<span class="token hvariable">isort</span> <span class="token punctuation">[</span><span class="token number">3</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token punctuation">]</span> <span class="token comment">-- { applying isort }</span>
↓
<span class="token hvariable">insert</span> <span class="token number">3</span> <span class="token punctuation">(</span><span class="token hvariable">insert</span> <span class="token number">2</span> <span class="token punctuation">(</span><span class="token hvariable">insert</span> <span class="token number">1</span> <span class="token punctuation">(</span><span class="token hvariable">insert</span> <span class="token number">4</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">-- { applying insert }</span>
↓
<span class="token hvariable">insert</span> <span class="token number">3</span> <span class="token punctuation">(</span><span class="token hvariable">insert</span> <span class="token number">2</span> <span class="token punctuation">(</span><span class="token hvariable">insert</span> <span class="token number">1</span> <span class="token punctuation">[</span><span class="token number">4</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">-- { applying insert }</span>
↓
<span class="token hvariable">insert</span> <span class="token number">3</span> <span class="token punctuation">(</span><span class="token hvariable">insert</span> <span class="token number">2</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token comment">-- { applying insert }</span>
↓
<span class="token hvariable">insert</span> <span class="token number">3</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token punctuation">]</span> <span class="token comment">-- { applying insert }</span>
↓
<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token punctuation">]</span>
</code></pre>
<h2>Multiple Arguments</h2>
<p>For example library function <code>zip</code> takes two lists and produces a list of pairs.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token builtin">zip</span> <span class="token operator">::</span> <span class="token punctuation">[</span><span class="token hvariable">a</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token punctuation">[</span><span class="token hvariable">b</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token punctuation">[</span><span class="token punctuation">(</span><span class="token hvariable">a</span><span class="token punctuation">,</span> <span class="token hvariable">b</span><span class="token punctuation">)</span><span class="token punctuation">]</span>
<span class="token builtin">zip</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>       <span class="token hvariable">_</span>        <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>
<span class="token builtin">zip</span> <span class="token hvariable">_</span>        <span class="token punctuation">[</span><span class="token punctuation">]</span>       <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>
<span class="token builtin">zip</span> <span class="token punctuation">(</span><span class="token hvariable">x</span> <span class="token operator">:</span> <span class="token hvariable">xs</span><span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token hvariable">y</span> <span class="token operator">:</span> <span class="token hvariable">ys</span><span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token hvariable">x</span><span class="token punctuation">,</span> <span class="token hvariable">y</span><span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token builtin">zip</span> <span class="token hvariable">xs</span> <span class="token hvariable">ys</span>

<span class="token builtin">zip</span> <span class="token punctuation">[</span><span class="token char string">'a'</span><span class="token punctuation">,</span><span class="token char string">'b'</span><span class="token punctuation">,</span><span class="token char string">'c'</span><span class="token punctuation">]</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token punctuation">]</span> <span class="token comment">-- { applying zip }</span>
↓
<span class="token punctuation">(</span><span class="token char string">'a'</span><span class="token punctuation">,</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token builtin">zip</span> <span class="token punctuation">[</span><span class="token char string">'b'</span><span class="token punctuation">,</span><span class="token char string">'c'</span><span class="token punctuation">]</span> <span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token punctuation">]</span> <span class="token comment">-- { applying zip }</span>
↓
<span class="token punctuation">(</span><span class="token char string">'a'</span><span class="token punctuation">,</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token punctuation">(</span><span class="token char string">'b'</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token builtin">zip</span> <span class="token punctuation">[</span><span class="token char string">'c'</span><span class="token punctuation">]</span> <span class="token punctuation">[</span><span class="token number">3</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token punctuation">]</span> <span class="token comment">-- { applying zip }</span>
↓
<span class="token punctuation">(</span><span class="token char string">'a'</span><span class="token punctuation">,</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token punctuation">(</span><span class="token char string">'b'</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token punctuation">(</span><span class="token char string">'c'</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token builtin">zip</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">[</span><span class="token number">4</span><span class="token punctuation">]</span> <span class="token comment">-- { applying zip }</span>
↓
<span class="token punctuation">(</span><span class="token char string">'a'</span><span class="token punctuation">,</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token punctuation">(</span><span class="token char string">'b'</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token punctuation">(</span><span class="token char string">'c'</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token comment">-- { list notation }</span>
↓
<span class="token punctuation">[</span><span class="token punctuation">(</span><span class="token char string">'a'</span><span class="token punctuation">,</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token char string">'b'</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token char string">'c'</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">]</span>
</code></pre>
<p>In a similar way the <code>drop</code> function is defined which removes a given number of elements from a list.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token builtin">drop</span> <span class="token operator">::</span> <span class="token constant">Int</span> <span class="token operator">-&gt;</span> <span class="token punctuation">[</span><span class="token hvariable">a</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token punctuation">[</span><span class="token hvariable">a</span><span class="token punctuation">]</span>
<span class="token builtin">drop</span> <span class="token number">0</span> <span class="token hvariable">xs</span>       <span class="token operator">=</span> <span class="token hvariable">xs</span>
<span class="token builtin">drop</span> <span class="token hvariable">_</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>       <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>
<span class="token builtin">drop</span> <span class="token hvariable">n</span> <span class="token punctuation">(</span><span class="token hvariable">_</span> <span class="token operator">:</span> <span class="token hvariable">xs</span><span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token builtin">drop</span> <span class="token punctuation">(</span><span class="token hvariable">n</span> <span class="token operator">-</span> <span class="token hvariable">a</span><span class="token punctuation">)</span> <span class="token hvariable">xs</span>
</code></pre>
<h2>Multiple Recursion</h2>
<p>It is also possible to use recursive function multiple times.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token comment">-- Get fibonacci at n-th positions</span>
<span class="token hvariable">fib</span> <span class="token operator">::</span> <span class="token constant">Int</span> <span class="token operator">-&gt;</span> <span class="token constant">Int</span>
<span class="token hvariable">fib</span> <span class="token number">0</span> <span class="token operator">=</span> <span class="token number">0</span>
<span class="token hvariable">fib</span> <span class="token number">1</span> <span class="token operator">=</span> <span class="token number">1</span>
<span class="token hvariable">fib</span> <span class="token hvariable">n</span> <span class="token operator">=</span> <span class="token hvariable">fib</span> <span class="token punctuation">(</span><span class="token hvariable">n</span> <span class="token operator">-</span> <span class="token number">2</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token hvariable">fib</span> <span class="token punctuation">(</span><span class="token hvariable">n</span> <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span>
</code></pre>
<p><a href="https://en.wikipedia.org/wiki/Quicksort">Quicksort</a> also demonstrates how multiple recursions occur inside a single function.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token hvariable">qsort</span> <span class="token operator">::</span> <span class="token constant">Ord</span> <span class="token hvariable">a</span> <span class="token operator">=&gt;</span> <span class="token punctuation">[</span><span class="token hvariable">a</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token punctuation">[</span><span class="token hvariable">a</span><span class="token punctuation">]</span>
<span class="token hvariable">qsort</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>       <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>
<span class="token hvariable">qsort</span> <span class="token punctuation">(</span><span class="token hvariable">x</span> <span class="token operator">:</span> <span class="token hvariable">xs</span><span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token hvariable">qsort</span> <span class="token hvariable">smaller</span> <span class="token operator">++</span> <span class="token punctuation">[</span><span class="token hvariable">x</span><span class="token punctuation">]</span> <span class="token operator">++</span> <span class="token hvariable">qsort</span> <span class="token hvariable">larger</span>
  <span class="token keyword">where</span>
    <span class="token hvariable">smaller</span> <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token hvariable">a</span> <span class="token operator">|</span> <span class="token hvariable">a</span> <span class="token operator">&lt;-</span> <span class="token hvariable">xs</span><span class="token punctuation">,</span> <span class="token hvariable">a</span> <span class="token operator">&lt;=</span> <span class="token hvariable">x</span> <span class="token punctuation">]</span>
    <span class="token hvariable">larger</span>  <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token hvariable">b</span> <span class="token operator">|</span> <span class="token hvariable">b</span> <span class="token operator">&lt;-</span> <span class="token hvariable">xs</span><span class="token punctuation">,</span> <span class="token hvariable">b</span> <span class="token operator">&gt;</span> <span class="token hvariable">x</span> <span class="token punctuation">]</span>
</code></pre>
<h2>Mutual Recursion</h2>
<p>Functions can also be defined recursively in terms of each other.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token builtin">even</span> <span class="token operator">::</span> <span class="token constant">Int</span> <span class="token operator">-&gt;</span> <span class="token constant">Bool</span>
<span class="token builtin">even</span> <span class="token number">0</span> <span class="token operator">=</span> <span class="token constant">True</span>
<span class="token builtin">even</span> <span class="token hvariable">n</span> <span class="token operator">=</span> <span class="token builtin">odd</span> <span class="token punctuation">(</span><span class="token hvariable">n</span> <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span>

<span class="token builtin">odd</span> <span class="token operator">::</span> <span class="token constant">Int</span> <span class="token operator">-&gt;</span> <span class="token constant">Bool</span>
<span class="token builtin">odd</span> <span class="token number">0</span> <span class="token operator">=</span> <span class="token constant">False</span>
<span class="token builtin">odd</span> <span class="token hvariable">n</span> <span class="token operator">=</span> <span class="token builtin">even</span> <span class="token punctuation">(</span><span class="token hvariable">n</span> <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span>

<span class="token builtin">even</span> <span class="token number">4</span> <span class="token comment">-- { applying even }</span>
↓
<span class="token builtin">odd</span> <span class="token number">3</span> <span class="token comment">-- { applying odd }</span>
↓
<span class="token builtin">even</span> <span class="token number">2</span> <span class="token comment">-- { applying even }</span>
↓
<span class="token builtin">odd</span> <span class="token number">1</span> <span class="token comment">-- { applying odd }</span>
↓
<span class="token builtin">even</span> <span class="token number">0</span> <span class="token comment">-- { applying even }</span>
↓
<span class="token constant">True</span>
</code></pre>
<p>Another pair of functions <code>evens</code> and <code>odds</code> can be defined similarly.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token hvariable">evens</span> <span class="token operator">::</span> <span class="token punctuation">[</span><span class="token hvariable">a</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token punctuation">[</span><span class="token hvariable">a</span><span class="token punctuation">]</span>
<span class="token hvariable">evens</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>       <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>
<span class="token hvariable">evens</span> <span class="token punctuation">(</span><span class="token hvariable">x</span> <span class="token operator">:</span> <span class="token hvariable">xs</span><span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token hvariable">x</span> <span class="token operator">:</span> <span class="token hvariable">odds</span> <span class="token hvariable">xs</span>

<span class="token hvariable">odds</span> <span class="token operator">::</span> <span class="token punctuation">[</span><span class="token hvariable">a</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token punctuation">[</span><span class="token hvariable">a</span><span class="token punctuation">]</span>
<span class="token hvariable">odds</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>       <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>
<span class="token hvariable">odds</span> <span class="token punctuation">(</span><span class="token hvariable">_</span> <span class="token operator">:</span> <span class="token hvariable">xs</span><span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token hvariable">evens</span> <span class="token hvariable">xs</span>

<span class="token hvariable">evens</span> <span class="token string">"abcde"</span> <span class="token comment">-- { applying evens }</span>
↓
<span class="token char string">'a'</span> <span class="token operator">:</span> <span class="token hvariable">odds</span> <span class="token string">"bcde"</span> <span class="token comment">-- { applying odds }</span>
↓
<span class="token char string">'a'</span> <span class="token operator">:</span> <span class="token hvariable">evens</span> <span class="token string">"cde"</span> <span class="token comment">-- { applying evens }</span>
↓
<span class="token char string">'a'</span> <span class="token operator">:</span> <span class="token char string">'c'</span> <span class="token operator">:</span> <span class="token hvariable">odds</span> <span class="token string">"de"</span> <span class="token comment">-- { applying odds }</span>
↓
<span class="token char string">'a'</span> <span class="token operator">:</span> <span class="token char string">'c'</span> <span class="token operator">:</span> <span class="token hvariable">evens</span> <span class="token string">"e"</span> <span class="token comment">-- { applying evens }</span>
↓
<span class="token char string">'a'</span> <span class="token operator">:</span> <span class="token char string">'c'</span> <span class="token operator">:</span> <span class="token char string">'e'</span> <span class="token operator">:</span> <span class="token hvariable">odds</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token comment">-- { applying odds }</span>
↓
<span class="token char string">'a'</span> <span class="token operator">:</span> <span class="token char string">'c'</span> <span class="token operator">:</span> <span class="token char string">'e'</span> <span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token comment">-- { string notation }</span>
↓
<span class="token string">"ace"</span>
</code></pre>
<h2>Advice on Recursion</h2>
<p>As an example <code>product</code> function will be used during next steps.</p>
<ol>
<li>define the type</li>
</ol>
<pre class="language-haskell"><code class="language-haskell"><span class="token builtin">product</span> <span class="token operator">::</span> <span class="token punctuation">[</span><span class="token constant">Int</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token constant">Int</span>
</code></pre>
<ol start="2">
<li>enumerate the cases</li>
</ol>
<pre class="language-haskell"><code class="language-haskell"><span class="token builtin">product</span> <span class="token operator">::</span> <span class="token punctuation">[</span><span class="token constant">Int</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token constant">Int</span>
<span class="token builtin">product</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>       <span class="token operator">=</span>
<span class="token builtin">product</span> <span class="token punctuation">(</span><span class="token hvariable">n</span> <span class="token operator">:</span> <span class="token hvariable">ns</span><span class="token punctuation">)</span> <span class="token operator">=</span>
</code></pre>
<ol start="3">
<li>define the simple cases</li>
</ol>
<pre class="language-haskell"><code class="language-haskell"><span class="token builtin">product</span> <span class="token operator">::</span> <span class="token punctuation">[</span><span class="token constant">Int</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token constant">Int</span>
<span class="token builtin">product</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>       <span class="token operator">=</span> <span class="token number">1</span>
<span class="token builtin">product</span> <span class="token punctuation">(</span><span class="token hvariable">n</span> <span class="token operator">:</span> <span class="token hvariable">ns</span><span class="token punctuation">)</span> <span class="token operator">=</span>
</code></pre>
<ol start="4">
<li>define the other cases</li>
</ol>
<pre class="language-haskell"><code class="language-haskell"><span class="token builtin">product</span> <span class="token operator">::</span> <span class="token punctuation">[</span><span class="token constant">Int</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token constant">Int</span>
<span class="token builtin">product</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>       <span class="token operator">=</span> <span class="token number">1</span>
<span class="token builtin">product</span> <span class="token punctuation">(</span><span class="token hvariable">n</span> <span class="token operator">:</span> <span class="token hvariable">ns</span><span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token hvariable">n</span> <span class="token operator">*</span> <span class="token builtin">product</span> <span class="token hvariable">ns</span>
</code></pre>
<ol start="5">
<li>generalize and simplify</li>
</ol>
<pre class="language-haskell"><code class="language-haskell"><span class="token builtin">product</span> <span class="token operator">::</span> <span class="token constant">Num</span> <span class="token hvariable">a</span> <span class="token operator">=&gt;</span> <span class="token punctuation">[</span><span class="token hvariable">a</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token hvariable">a</span>
<span class="token builtin">product</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>       <span class="token operator">=</span> <span class="token number">1</span>
<span class="token builtin">product</span> <span class="token punctuation">(</span><span class="token hvariable">n</span> <span class="token operator">:</span> <span class="token hvariable">ns</span><span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token hvariable">n</span> <span class="token operator">*</span> <span class="token builtin">product</span> <span class="token hvariable">ns</span>
</code></pre>
<p>Recursion is an important milestone to reach and understand. End.</p>]]></content:encoded>
            <author>anton@azdanov.dev (Anton Ždanov)</author>
        </item>
        <item>
            <title><![CDATA[Exploring Haskell: List Comprehensions]]></title>
            <link>https://www.azdanov.dev/articles/2018/exploring-haskell-list-comprehensions</link>
            <guid isPermaLink="false">https://www.azdanov.dev/articles/2018/exploring-haskell-list-comprehensions</guid>
            <pubDate>Mon, 03 Sep 2018 22:58:48 GMT</pubDate>
            <content:encoded><![CDATA[<img alt="exploring haskell list comprehensions" loading="lazy" width="1199" height="630" decoding="async" data-nimg="1" style="color:transparent" srcset="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexploring-haskell-list-comprehensions.0~0pobutk4ru~.png&amp;w=1200&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexploring-haskell-list-comprehensions.0~0pobutk4ru~.png&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexploring-haskell-list-comprehensions.0~0pobutk4ru~.png&amp;w=3840&amp;q=75">
<p>List comprehensions allow defining of many functions on lists in a simple way.</p>
<h2>Basic Concepts</h2>
<p>In mathematics, the comprehension notation can be used to construct new sets from existing sets.</p>
<p>For example, the comprehension <code>{x² | x ∈ {1..5}}</code> produces the set <code>{1, 4, 9, 16, 25}</code>.</p>
<p>A similar comprehension In Haskell:</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token punctuation">[</span><span class="token hvariable">x</span><span class="token operator">^</span><span class="token number">2</span> <span class="token operator">|</span> <span class="token hvariable">x</span> <span class="token operator">&lt;-</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token operator">..</span><span class="token number">5</span><span class="token punctuation">]</span><span class="token punctuation">]</span> <span class="token comment">-- [1,4,9,16,25]</span>
</code></pre>
<p>The symbol <code>|</code> is read as such that, <code>&lt;-</code> is read as is drawn from, and the expression <code>x &lt;- [1..5]</code> is called a generator.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token punctuation">[</span><span class="token punctuation">(</span><span class="token hvariable">x</span><span class="token punctuation">,</span><span class="token hvariable">y</span><span class="token punctuation">)</span> <span class="token operator">|</span> <span class="token hvariable">x</span> <span class="token operator">&lt;-</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token hvariable">y</span> <span class="token operator">&lt;-</span> <span class="token punctuation">[</span><span class="token number">4</span><span class="token punctuation">,</span><span class="token number">5</span><span class="token punctuation">]</span><span class="token punctuation">]</span> <span class="token comment">-- [(1,4),(1,5),(2,4),(2,5),(3,4),(3,5)]</span>

<span class="token punctuation">[</span><span class="token punctuation">(</span><span class="token hvariable">x</span><span class="token punctuation">,</span><span class="token hvariable">y</span><span class="token punctuation">)</span> <span class="token operator">|</span> <span class="token hvariable">y</span> <span class="token operator">&lt;-</span> <span class="token punctuation">[</span><span class="token number">4</span><span class="token punctuation">,</span><span class="token number">5</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token hvariable">x</span> <span class="token operator">&lt;-</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">]</span> <span class="token comment">-- [(1,4),(2,4),(3,4),(1,5),(2,5),(3,5)]</span>
</code></pre>
<p>The order of generators produces the same set of pairs, but arranged in different order.</p>
<p>Multiple generators are like nested loops, with later generators as more deeply nested loops, whose values change more frequently.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token punctuation">[</span><span class="token punctuation">(</span><span class="token hvariable">x</span><span class="token punctuation">,</span><span class="token hvariable">y</span><span class="token punctuation">)</span> <span class="token operator">|</span> <span class="token hvariable">x</span> <span class="token operator">&lt;-</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token operator">..</span><span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token hvariable">y</span> <span class="token operator">&lt;-</span> <span class="token punctuation">[</span><span class="token hvariable">x</span><span class="token operator">..</span><span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">]</span> <span class="token comment">-- [(1,1),(1,2),(1,3),(2,2),(2,3),(3,3)]</span>
</code></pre>
<p>Later generator can depend upon values of earlier generators.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token builtin">concat</span> <span class="token operator">::</span> <span class="token punctuation">[</span><span class="token punctuation">[</span><span class="token hvariable">a</span><span class="token punctuation">]</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token punctuation">[</span><span class="token hvariable">a</span><span class="token punctuation">]</span>
<span class="token builtin">concat</span> <span class="token hvariable">xss</span> <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token hvariable">x</span> <span class="token operator">|</span> <span class="token hvariable">xs</span> <span class="token operator">&lt;-</span> <span class="token hvariable">xss</span><span class="token punctuation">,</span> <span class="token hvariable">x</span> <span class="token operator">&lt;-</span> <span class="token hvariable">xs</span> <span class="token punctuation">]</span>

<span class="token builtin">concat</span> <span class="token punctuation">[</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token number">3</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token punctuation">]</span><span class="token punctuation">]</span> <span class="token comment">-- [1,2,3,4]</span>
</code></pre>
<p>A more useful example of using list comprehensions.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token hvariable">firsts</span> <span class="token operator">::</span> <span class="token punctuation">[</span><span class="token punctuation">(</span><span class="token hvariable">a</span><span class="token punctuation">,</span> <span class="token hvariable">b</span><span class="token punctuation">)</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token punctuation">[</span><span class="token hvariable">a</span><span class="token punctuation">]</span>
<span class="token hvariable">firsts</span> <span class="token hvariable">ps</span> <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token hvariable">x</span> <span class="token operator">|</span> <span class="token punctuation">(</span><span class="token hvariable">x</span><span class="token punctuation">,</span> <span class="token hvariable">_</span><span class="token punctuation">)</span> <span class="token operator">&lt;-</span> <span class="token hvariable">ps</span> <span class="token punctuation">]</span>

<span class="token hvariable">firsts</span> <span class="token punctuation">[</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token punctuation">)</span><span class="token punctuation">]</span> <span class="token comment">-- [1,3]</span>

<span class="token builtin">length</span> <span class="token operator">::</span> <span class="token punctuation">[</span><span class="token hvariable">a</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token constant">Int</span>
<span class="token builtin">length</span> <span class="token hvariable">xs</span> <span class="token operator">=</span> <span class="token builtin">sum</span> <span class="token punctuation">[</span> <span class="token number">1</span> <span class="token operator">|</span> <span class="token hvariable">_</span> <span class="token operator">&lt;-</span> <span class="token hvariable">xs</span> <span class="token punctuation">]</span>

<span class="token builtin">length</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token punctuation">]</span> <span class="token comment">-- 4</span>
</code></pre>
<p>Wildcard pattern <code>_</code> can be used to discard a value from a list.</p>
<h2>Guards</h2>
<p>A guard can be used to filter values produced by earlier generators.</p>
<p>If a guard is <code>True</code>, then the current value is retained, if it is <code>False</code> then it is discarded.</p>
<p>For example, the comprehension <code>[x | x &lt;- [1..10], even x]</code> produces the list <code>[2,4,6,8,10]</code>.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token hvariable">factors</span> <span class="token operator">::</span> <span class="token constant">Int</span> <span class="token operator">-&gt;</span> <span class="token punctuation">[</span><span class="token constant">Int</span><span class="token punctuation">]</span>
<span class="token hvariable">factors</span> <span class="token hvariable">n</span> <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token hvariable">x</span> <span class="token operator">|</span> <span class="token hvariable">x</span> <span class="token operator">&lt;-</span> <span class="token punctuation">[</span><span class="token number">1</span> <span class="token operator">..</span> <span class="token hvariable">n</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token hvariable">n</span> <span class="token operator">`mod`</span> <span class="token hvariable">x</span> <span class="token operator">==</span> <span class="token number">0</span> <span class="token punctuation">]</span>

<span class="token hvariable">factors</span> <span class="token number">15</span> <span class="token comment">-- [1,3,5,15]</span>

<span class="token hvariable">factors</span> <span class="token number">7</span> <span class="token comment">-- [1,7]</span>
</code></pre>
<p>A function to find all the factors of an integer.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token hvariable">prime</span> <span class="token operator">::</span> <span class="token constant">Int</span> <span class="token operator">-&gt;</span> <span class="token constant">Bool</span>
<span class="token hvariable">prime</span> <span class="token hvariable">n</span> <span class="token operator">=</span> <span class="token hvariable">factors</span> <span class="token hvariable">n</span> <span class="token operator">==</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token hvariable">n</span><span class="token punctuation">]</span>

<span class="token hvariable">prime</span> <span class="token number">15</span> <span class="token comment">-- False</span>

<span class="token hvariable">prime</span> <span class="token number">7</span> <span class="token comment">-- True</span>
</code></pre>
<p>Combining both functions to find if a integer is prime.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token hvariable">primes</span> <span class="token operator">::</span> <span class="token constant">Int</span> <span class="token operator">-&gt;</span> <span class="token punctuation">[</span><span class="token constant">Int</span><span class="token punctuation">]</span>
<span class="token hvariable">primes</span> <span class="token hvariable">n</span> <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token hvariable">x</span> <span class="token operator">|</span> <span class="token hvariable">x</span> <span class="token operator">&lt;-</span> <span class="token punctuation">[</span><span class="token number">2</span> <span class="token operator">..</span> <span class="token hvariable">n</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token hvariable">prime</span> <span class="token hvariable">x</span> <span class="token punctuation">]</span>

<span class="token hvariable">primes</span> <span class="token number">40</span> <span class="token comment">-- [2,3,5,7,11,13,17,19,23,29,31,37]</span>
</code></pre>
<p>Creating a list of primes by reusing the previous function.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token hvariable">find</span> <span class="token operator">::</span> <span class="token constant">Eq</span> <span class="token hvariable">a</span> <span class="token operator">=&gt;</span> <span class="token hvariable">a</span> <span class="token operator">-&gt;</span> <span class="token punctuation">[</span><span class="token punctuation">(</span><span class="token hvariable">a</span><span class="token punctuation">,</span> <span class="token hvariable">b</span><span class="token punctuation">)</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token punctuation">[</span><span class="token hvariable">b</span><span class="token punctuation">]</span>
<span class="token hvariable">find</span> <span class="token hvariable">k</span> <span class="token hvariable">t</span> <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token hvariable">v</span> <span class="token operator">|</span> <span class="token punctuation">(</span><span class="token hvariable">k'</span><span class="token punctuation">,</span> <span class="token hvariable">v</span><span class="token punctuation">)</span> <span class="token operator">&lt;-</span> <span class="token hvariable">t</span><span class="token punctuation">,</span> <span class="token hvariable">k</span> <span class="token operator">==</span> <span class="token hvariable">k'</span> <span class="token punctuation">]</span>

<span class="token hvariable">find</span> <span class="token char string">'b'</span> <span class="token punctuation">[</span><span class="token punctuation">(</span><span class="token char string">'a'</span><span class="token punctuation">,</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">,</span><span class="token punctuation">(</span><span class="token char string">'b'</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">,</span><span class="token punctuation">(</span><span class="token char string">'c'</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">,</span><span class="token punctuation">(</span><span class="token char string">'b'</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token punctuation">)</span><span class="token punctuation">]</span> <span class="token comment">-- [2,4]</span>
</code></pre>
<p>Finds values by a key from a list of pairs.</p>
<h2>Zip Function</h2>
<p>The library function zip produces a new list by pairing successive elements from two existing lists until either or both lists are exhausted.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token builtin">zip</span> <span class="token punctuation">[</span><span class="token char string">'a'</span><span class="token punctuation">,</span><span class="token char string">'b'</span><span class="token punctuation">,</span><span class="token char string">'c'</span><span class="token punctuation">]</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token punctuation">]</span> <span class="token comment">-- [('a',1),('b',2),('c',3)]</span>
</code></pre>
<p>Notice that zip stops when one of the lists end is reached.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token hvariable">pairs</span> <span class="token operator">::</span> <span class="token punctuation">[</span><span class="token hvariable">a</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token punctuation">[</span><span class="token punctuation">(</span><span class="token hvariable">a</span><span class="token punctuation">,</span> <span class="token hvariable">a</span><span class="token punctuation">)</span><span class="token punctuation">]</span>
<span class="token hvariable">pairs</span> <span class="token hvariable">xs</span> <span class="token operator">=</span> <span class="token builtin">zip</span> <span class="token hvariable">xs</span> <span class="token punctuation">(</span><span class="token builtin">tail</span> <span class="token hvariable">xs</span><span class="token punctuation">)</span>

<span class="token hvariable">pairs</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token punctuation">]</span> <span class="token comment">-- [(1,2),(2,3),(3,4)]</span>
</code></pre>
<p>Zip function can be useful with list comprehensions.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token hvariable">sorted</span> <span class="token operator">::</span> <span class="token constant">Ord</span> <span class="token hvariable">a</span> <span class="token operator">=&gt;</span> <span class="token punctuation">[</span><span class="token hvariable">a</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token constant">Bool</span>
<span class="token hvariable">sorted</span> <span class="token hvariable">xs</span> <span class="token operator">=</span> <span class="token builtin">and</span> <span class="token punctuation">[</span> <span class="token hvariable">x</span> <span class="token operator">&lt;=</span> <span class="token hvariable">y</span> <span class="token operator">|</span> <span class="token punctuation">(</span><span class="token hvariable">x</span><span class="token punctuation">,</span> <span class="token hvariable">y</span><span class="token punctuation">)</span> <span class="token operator">&lt;-</span> <span class="token hvariable">pairs</span> <span class="token hvariable">xs</span> <span class="token punctuation">]</span>

<span class="token hvariable">sorted</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token punctuation">]</span> <span class="token comment">-- True</span>

<span class="token hvariable">sorted</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token punctuation">]</span> <span class="token comment">-- False</span>
</code></pre>
<p>Checks if a list of elements is sorted.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token hvariable">positions</span> <span class="token operator">::</span> <span class="token constant">Eq</span> <span class="token hvariable">a</span> <span class="token operator">=&gt;</span> <span class="token hvariable">a</span> <span class="token operator">-&gt;</span> <span class="token punctuation">[</span><span class="token hvariable">a</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token punctuation">[</span><span class="token constant">Int</span><span class="token punctuation">]</span>
<span class="token hvariable">positions</span> <span class="token hvariable">x</span> <span class="token hvariable">xs</span> <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token hvariable">i</span> <span class="token operator">|</span> <span class="token punctuation">(</span><span class="token hvariable">x'</span><span class="token punctuation">,</span> <span class="token hvariable">i</span><span class="token punctuation">)</span> <span class="token operator">&lt;-</span> <span class="token builtin">zip</span> <span class="token hvariable">xs</span> <span class="token punctuation">[</span><span class="token number">0</span> <span class="token operator">..</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token hvariable">x</span> <span class="token operator">==</span> <span class="token hvariable">x'</span> <span class="token punctuation">]</span>

<span class="token hvariable">positions</span> <span class="token constant">False</span> <span class="token punctuation">[</span><span class="token constant">True</span><span class="token punctuation">,</span> <span class="token constant">False</span><span class="token punctuation">,</span> <span class="token constant">True</span><span class="token punctuation">,</span> <span class="token constant">False</span><span class="token punctuation">]</span> <span class="token comment">-- [1,3]</span>
</code></pre>
<p>Finds all the positions of a provided value in a list.</p>
<h2>String Comprehensions</h2>
<p>In Haskell a string is represented as a list of characters. Which allows to use any polymorphic list functions on a string.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token string">"abcde"</span> <span class="token operator">!!</span> <span class="token number">2</span> <span class="token comment">-- 'c'</span>

<span class="token builtin">take</span> <span class="token number">3</span> <span class="token string">"abcde"</span> <span class="token comment">-- "abc"</span>

<span class="token builtin">length</span> <span class="token string">"abcde"</span> <span class="token comment">-- 5</span>

<span class="token builtin">zip</span> <span class="token string">"abc"</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token punctuation">]</span> <span class="token comment">-- [('a',1),('b',2),('c',3)]</span>

<span class="token hvariable">count_lower</span> <span class="token operator">::</span> <span class="token constant">String</span> <span class="token operator">-&gt;</span> <span class="token constant">Int</span>
<span class="token hvariable">count_lower</span> <span class="token hvariable">xs</span> <span class="token operator">=</span> <span class="token builtin">length</span> <span class="token punctuation">[</span> <span class="token hvariable">x</span> <span class="token operator">|</span> <span class="token hvariable">x</span> <span class="token operator">&lt;-</span> <span class="token hvariable">xs</span><span class="token punctuation">,</span> <span class="token hvariable">x</span> <span class="token operator">&gt;=</span> <span class="token char string">'a'</span> <span class="token operator">&amp;&amp;</span> <span class="token hvariable">x</span> <span class="token operator">&lt;=</span> <span class="token char string">'z'</span> <span class="token punctuation">]</span>

<span class="token hvariable">count_lower</span> <span class="token string">"Haskell"</span> <span class="token comment">-- 6</span>

<span class="token hvariable">count</span> <span class="token operator">::</span> <span class="token constant">Char</span> <span class="token operator">-&gt;</span> <span class="token constant">String</span> <span class="token operator">-&gt;</span> <span class="token constant">Int</span>
<span class="token hvariable">count</span> <span class="token hvariable">x</span> <span class="token hvariable">xs</span> <span class="token operator">=</span> <span class="token builtin">length</span> <span class="token punctuation">[</span> <span class="token hvariable">x'</span> <span class="token operator">|</span> <span class="token hvariable">x'</span> <span class="token operator">&lt;-</span> <span class="token hvariable">xs</span><span class="token punctuation">,</span> <span class="token hvariable">x</span> <span class="token operator">==</span> <span class="token hvariable">x'</span> <span class="token punctuation">]</span>

<span class="token hvariable">count</span> <span class="token char string">'s'</span> <span class="token string">"Mississippi"</span> <span class="token comment">-- 4</span>
</code></pre>
<p>Over and out.</p>]]></content:encoded>
            <author>anton@azdanov.dev (Anton Ždanov)</author>
        </item>
        <item>
            <title><![CDATA[Exploring Haskell: Defining Functions]]></title>
            <link>https://www.azdanov.dev/articles/2018/exploring-haskell-defining-functions</link>
            <guid isPermaLink="false">https://www.azdanov.dev/articles/2018/exploring-haskell-defining-functions</guid>
            <pubDate>Sat, 01 Sep 2018 23:04:15 GMT</pubDate>
            <content:encoded><![CDATA[<img alt="exploring-haskell-defining-functions" loading="lazy" width="1199" height="630" decoding="async" data-nimg="1" style="color:transparent" srcset="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexploring-haskell-defining-functions.0hze_rstc0-8p.png&amp;w=1200&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexploring-haskell-defining-functions.0hze_rstc0-8p.png&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexploring-haskell-defining-functions.0hze_rstc0-8p.png&amp;w=3840&amp;q=75">
<p>Going from conditional expressions and guarded equations to pattern matching, lambda expressions, and operator sections.</p>
<h2>Conditional Expressions</h2>
<p>As in most programming languages, Haskell supports conditional expression, which also can be used to define a function.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token comment">-- Absolute integer</span>
<span class="token builtin">abs</span> <span class="token operator">::</span> <span class="token constant">Int</span> <span class="token operator">-&gt;</span> <span class="token constant">Int</span>
<span class="token builtin">abs</span> <span class="token hvariable">n</span> <span class="token operator">=</span> <span class="token keyword">if</span> <span class="token hvariable">n</span> <span class="token operator">&gt;=</span> <span class="token number">0</span> <span class="token keyword">then</span> <span class="token hvariable">n</span> <span class="token keyword">else</span> <span class="token operator">-</span><span class="token hvariable">n</span>

<span class="token comment">-- Sign of integer</span>
<span class="token builtin">signum</span> <span class="token operator">::</span> <span class="token constant">Int</span> <span class="token operator">-&gt;</span> <span class="token constant">Int</span>
<span class="token builtin">signum</span> <span class="token hvariable">n</span> <span class="token operator">=</span> <span class="token keyword">if</span> <span class="token hvariable">n</span> <span class="token operator">&lt;</span> <span class="token number">0</span> <span class="token keyword">then</span> <span class="token operator">-</span><span class="token number">1</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token hvariable">n</span> <span class="token operator">==</span> <span class="token number">0</span> <span class="token keyword">then</span> <span class="token number">0</span> <span class="token keyword">else</span> <span class="token number">1</span>
</code></pre>
<h2>Guarded Equations</h2>
<p>Guarded equation is a preferred alternative to a conditional expression in Haskell.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token comment">-- Absolute integer</span>
<span class="token builtin">abs</span> <span class="token operator">::</span> <span class="token constant">Int</span> <span class="token operator">-&gt;</span> <span class="token constant">Int</span>
<span class="token builtin">abs</span> <span class="token hvariable">n</span> <span class="token operator">|</span> <span class="token hvariable">n</span> <span class="token operator">&gt;=</span> <span class="token number">0</span>    <span class="token operator">=</span> <span class="token hvariable">n</span>
      <span class="token operator">|</span> <span class="token builtin">otherwise</span> <span class="token operator">=</span> <span class="token operator">-</span><span class="token hvariable">n</span>

<span class="token comment">-- Sign of integer</span>
<span class="token builtin">signum</span> <span class="token operator">::</span> <span class="token constant">Int</span> <span class="token operator">-&gt;</span> <span class="token constant">Int</span>
<span class="token builtin">signum</span> <span class="token hvariable">n</span> <span class="token operator">|</span> <span class="token hvariable">n</span> <span class="token operator">&lt;</span> <span class="token number">0</span>     <span class="token operator">=</span> <span class="token operator">-</span><span class="token number">1</span>
         <span class="token operator">|</span> <span class="token hvariable">n</span> <span class="token operator">==</span> <span class="token number">0</span>    <span class="token operator">=</span> <span class="token number">0</span>
         <span class="token operator">|</span> <span class="token builtin">otherwise</span> <span class="token operator">=</span> <span class="token number">1</span>

<span class="token comment">-- When otherwise is unspecified the default value is otherwise = True</span>
</code></pre>
<h2>Pattern Matching</h2>
<p>Pattern matching is a simple way to define a function by matching a pattern with an expected result.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token comment">-- Boolean negation</span>
<span class="token builtin">not</span> <span class="token operator">::</span> <span class="token constant">Bool</span> <span class="token operator">-&gt;</span> <span class="token constant">Bool</span>
<span class="token builtin">not</span> <span class="token constant">False</span> <span class="token operator">=</span> <span class="token constant">True</span>
<span class="token builtin">not</span> <span class="token constant">True</span>  <span class="token operator">=</span> <span class="token constant">False</span>

<span class="token comment">-- Boolean AND (Naive)</span>
<span class="token punctuation">(</span><span class="token operator">&amp;&amp;</span><span class="token punctuation">)</span> <span class="token operator">::</span> <span class="token constant">Bool</span> <span class="token operator">-&gt;</span> <span class="token constant">Bool</span> <span class="token operator">-&gt;</span> <span class="token constant">Bool</span>
<span class="token constant">True</span>  <span class="token operator">&amp;&amp;</span> <span class="token constant">True</span>  <span class="token operator">=</span> <span class="token constant">True</span>
<span class="token constant">True</span>  <span class="token operator">&amp;&amp;</span> <span class="token constant">False</span> <span class="token operator">=</span> <span class="token constant">False</span>
<span class="token constant">False</span> <span class="token operator">&amp;&amp;</span> <span class="token constant">True</span>  <span class="token operator">=</span> <span class="token constant">False</span>
<span class="token constant">False</span> <span class="token operator">&amp;&amp;</span> <span class="token constant">False</span> <span class="token operator">=</span> <span class="token constant">False</span>

<span class="token comment">-- Boolean AND (Compact)</span>
<span class="token punctuation">(</span><span class="token operator">&amp;&amp;</span><span class="token punctuation">)</span> <span class="token operator">::</span> <span class="token constant">Bool</span> <span class="token operator">-&gt;</span> <span class="token constant">Bool</span> <span class="token operator">-&gt;</span> <span class="token constant">Bool</span>
<span class="token constant">True</span> <span class="token operator">&amp;&amp;</span> <span class="token constant">True</span> <span class="token operator">=</span> <span class="token constant">True</span>
<span class="token hvariable">_</span>    <span class="token operator">&amp;&amp;</span> <span class="token hvariable">_</span>    <span class="token operator">=</span> <span class="token constant">False</span>

<span class="token comment">-- _ is a wildcard to match any symbol</span>

<span class="token comment">-- Boolean AND (Lazy)</span>
<span class="token punctuation">(</span><span class="token operator">&amp;&amp;</span><span class="token punctuation">)</span> <span class="token operator">::</span> <span class="token constant">Bool</span> <span class="token operator">-&gt;</span> <span class="token constant">Bool</span> <span class="token operator">-&gt;</span> <span class="token constant">Bool</span>
<span class="token constant">True</span>  <span class="token operator">&amp;&amp;</span> <span class="token hvariable">b</span> <span class="token operator">=</span> <span class="token hvariable">b</span>
<span class="token constant">False</span> <span class="token operator">&amp;&amp;</span> <span class="token hvariable">_</span> <span class="token operator">=</span> <span class="token constant">False</span>
</code></pre>
<p>Patterns are matched in order of definition, left to right, top to bottom.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token comment">-- Will always return False</span>
<span class="token punctuation">(</span><span class="token operator">&amp;&amp;</span><span class="token punctuation">)</span> <span class="token operator">::</span> <span class="token constant">Bool</span> <span class="token operator">-&gt;</span> <span class="token constant">Bool</span> <span class="token operator">-&gt;</span> <span class="token constant">Bool</span>
<span class="token hvariable">_</span>    <span class="token operator">&amp;&amp;</span> <span class="token hvariable">_</span>    <span class="token operator">=</span> <span class="token constant">False</span>
<span class="token constant">True</span> <span class="token operator">&amp;&amp;</span> <span class="token constant">True</span> <span class="token operator">=</span> <span class="token constant">True</span>
</code></pre>
<p>Patterns do not repeating arguments.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token comment">-- Conflicting definition of b</span>
<span class="token punctuation">(</span><span class="token operator">&amp;&amp;</span><span class="token punctuation">)</span> <span class="token operator">::</span> <span class="token constant">Bool</span> <span class="token operator">-&gt;</span> <span class="token constant">Bool</span> <span class="token operator">-&gt;</span> <span class="token constant">Bool</span>
<span class="token hvariable">b</span> <span class="token operator">&amp;&amp;</span> <span class="token hvariable">b</span> <span class="token operator">=</span> <span class="token hvariable">b</span>
<span class="token hvariable">_</span> <span class="token operator">&amp;&amp;</span> <span class="token hvariable">_</span> <span class="token operator">=</span> <span class="token constant">False</span>

<span class="token comment">-- Correct way is to use a guarded equation</span>
<span class="token punctuation">(</span><span class="token operator">&amp;&amp;</span><span class="token punctuation">)</span> <span class="token operator">::</span> <span class="token constant">Bool</span> <span class="token operator">-&gt;</span> <span class="token constant">Bool</span> <span class="token operator">-&gt;</span> <span class="token constant">Bool</span>
<span class="token hvariable">b</span> <span class="token operator">&amp;&amp;</span> <span class="token hvariable">c</span> <span class="token operator">|</span> <span class="token hvariable">b</span> <span class="token operator">==</span> <span class="token hvariable">c</span>    <span class="token operator">=</span> <span class="token hvariable">b</span>
       <span class="token operator">|</span> <span class="token builtin">otherwise</span> <span class="token operator">=</span> <span class="token constant">False</span>
</code></pre>
<h2>List Patterns</h2>
<p>Internally, every non-empty list is constructed by repeated use of an operator <code>:</code> called <em>cons</em> that adds an element to the start of a list.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">]</span>

<span class="token comment">-- is actually</span>

<span class="token number">1</span><span class="token operator">:</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token operator">:</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token operator">:</span><span class="token punctuation">(</span><span class="token number">4</span><span class="token operator">:</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre>
<p>Function on a list can be defined using a <code>x:xs</code> pattern.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token comment">-- Return the first element of a given list</span>
<span class="token builtin">head</span> <span class="token operator">::</span> <span class="token punctuation">[</span><span class="token hvariable">a</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token hvariable">a</span>
<span class="token builtin">head</span> <span class="token punctuation">(</span><span class="token hvariable">x</span> <span class="token operator">:</span> <span class="token hvariable">_</span><span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token hvariable">x</span>

<span class="token comment">-- Return given list without the first element</span>
<span class="token builtin">tail</span> <span class="token operator">::</span> <span class="token punctuation">[</span><span class="token hvariable">a</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token punctuation">[</span><span class="token hvariable">a</span><span class="token punctuation">]</span>
<span class="token builtin">tail</span> <span class="token punctuation">(</span><span class="token hvariable">_</span> <span class="token operator">:</span> <span class="token hvariable">xs</span><span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token hvariable">xs</span>
</code></pre>
<ul>
<li><code>x:xs</code> can only match non-empty lists.</li>
<li><code>x:xs</code> pattern must be inside parenthesis because of the order of operations.</li>
</ul>
<h2>Lambda Expressions</h2>
<p>A function can be constructed without naming the function by using a lambda expression.
For example: <code>λx -&gt; x + x</code>.</p>
<p>The symbol <code>λ</code> is the Greek letter <em>lambda</em> and in Haskell is denoted with a <code>\</code>.</p>
<h3>Usage of Lambda Expressions</h3>
<p>Give formal meaning to a curried function.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token comment">-- Without lambda expression</span>
<span class="token hvariable">add</span> <span class="token operator">::</span> <span class="token constant">Int</span> <span class="token operator">-&gt;</span> <span class="token constant">Int</span> <span class="token operator">-&gt;</span> <span class="token constant">Int</span>
<span class="token hvariable">add</span> <span class="token hvariable">x</span> <span class="token hvariable">y</span> <span class="token operator">=</span> <span class="token hvariable">x</span> <span class="token operator">+</span> <span class="token hvariable">y</span>

<span class="token comment">-- With lambda expression</span>
<span class="token hvariable">add</span> <span class="token operator">::</span> <span class="token constant">Int</span> <span class="token operator">-&gt;</span> <span class="token constant">Int</span> <span class="token operator">-&gt;</span> <span class="token constant">Int</span>
<span class="token hvariable">add</span> <span class="token operator">=</span> <span class="token operator">\</span><span class="token hvariable">x</span> <span class="token operator">-&gt;</span> <span class="token punctuation">(</span><span class="token operator">\</span><span class="token hvariable">y</span> <span class="token operator">-&gt;</span> <span class="token hvariable">x</span> <span class="token operator">+</span> <span class="token hvariable">y</span><span class="token punctuation">)</span>
</code></pre>
<p>Define a function that returns another function as a result.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token comment">-- Without lambda expression</span>
<span class="token builtin">const</span> <span class="token operator">::</span> <span class="token hvariable">a</span> <span class="token operator">-&gt;</span> <span class="token hvariable">b</span> <span class="token operator">-&gt;</span> <span class="token hvariable">a</span>
<span class="token builtin">const</span> <span class="token hvariable">x</span> <span class="token hvariable">_</span> <span class="token operator">=</span> <span class="token hvariable">x</span>

<span class="token comment">-- With lambda expression</span>
<span class="token builtin">const</span> <span class="token operator">::</span> <span class="token hvariable">a</span> <span class="token operator">-&gt;</span> <span class="token punctuation">(</span><span class="token hvariable">b</span> <span class="token operator">-&gt;</span> <span class="token hvariable">a</span><span class="token punctuation">)</span>
<span class="token builtin">const</span> <span class="token hvariable">x</span> <span class="token operator">=</span> <span class="token operator">\</span><span class="token hvariable">_</span> <span class="token operator">-&gt;</span> <span class="token hvariable">x</span>
</code></pre>
<p>Avoid naming a function that is used once.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token comment">-- Without lambda expression</span>
<span class="token hvariable">odds</span> <span class="token operator">::</span> <span class="token constant">Int</span> <span class="token operator">-&gt;</span> <span class="token punctuation">[</span><span class="token constant">Int</span><span class="token punctuation">]</span>
<span class="token hvariable">odds</span> <span class="token hvariable">n</span> <span class="token operator">=</span> <span class="token builtin">map</span> <span class="token hvariable">f</span> <span class="token punctuation">[</span><span class="token number">0</span> <span class="token operator">..</span> <span class="token hvariable">n</span> <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">]</span> <span class="token keyword">where</span> <span class="token hvariable">f</span> <span class="token hvariable">x</span> <span class="token operator">=</span> <span class="token hvariable">x</span> <span class="token operator">*</span> <span class="token number">2</span> <span class="token operator">+</span> <span class="token number">1</span>

<span class="token comment">-- With lambda expression</span>
<span class="token hvariable">odds</span> <span class="token operator">::</span> <span class="token constant">Int</span> <span class="token operator">-&gt;</span> <span class="token punctuation">[</span><span class="token constant">Int</span><span class="token punctuation">]</span>
<span class="token hvariable">odds</span> <span class="token hvariable">n</span> <span class="token operator">=</span> <span class="token builtin">map</span> <span class="token punctuation">(</span><span class="token operator">\</span><span class="token hvariable">x</span> <span class="token operator">-&gt;</span> <span class="token hvariable">x</span> <span class="token operator">*</span> <span class="token number">2</span> <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">[</span><span class="token number">0</span> <span class="token operator">..</span> <span class="token hvariable">n</span> <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">]</span>
</code></pre>
<h2>Sections</h2>
<p>An operator written between its two arguments can be converted into a curried function written before its two arguments by using parenthesis.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token number">1</span> <span class="token operator">+</span> <span class="token number">2</span> <span class="token comment">-- 3</span>

<span class="token punctuation">(</span><span class="token operator">+</span><span class="token punctuation">)</span> <span class="token number">1</span> <span class="token number">2</span> <span class="token comment">-- 3</span>

<span class="token punctuation">(</span><span class="token number">1</span><span class="token operator">+</span><span class="token punctuation">)</span> <span class="token number">2</span> <span class="token comment">-- 3</span>

<span class="token punctuation">(</span><span class="token operator">+</span><span class="token number">2</span><span class="token punctuation">)</span> <span class="token number">1</span> <span class="token comment">-- 3</span>
</code></pre>
<p>In general if <code>+</code> is an operator then functions of the form <code>(+)</code>, <code>(x+)</code>, <code>(+y)</code> are called sections.</p>
<h3>Using Sections</h3>
<p>Sections can be used to instead of functions:</p>
<ul>
<li><code>(+)</code> is the addition function <code>\x -&gt; (\y -&gt; x + y)</code></li>
<li><code>(1+)</code> is the successor function <code>\y -&gt; 1 + y</code></li>
<li><code>(1/)</code> is the reciprocation function <code>\y -&gt; 1 / y</code></li>
<li><code>(*2)</code> is the doubling function <code>\x -&gt; x * 2</code></li>
<li><code>(/2)</code> is the halving function <code>\x -&gt; x / 2</code></li>
</ul>
<p>And that's that.</p>]]></content:encoded>
            <author>anton@azdanov.dev (Anton Ždanov)</author>
        </item>
        <item>
            <title><![CDATA[Exploring Haskell: Types & Classes]]></title>
            <link>https://www.azdanov.dev/articles/2018/exploring-haskell-types-and-classes</link>
            <guid isPermaLink="false">https://www.azdanov.dev/articles/2018/exploring-haskell-types-and-classes</guid>
            <pubDate>Thu, 30 Aug 2018 21:28:36 GMT</pubDate>
            <content:encoded><![CDATA[<img alt="exploring haskell types and classes" loading="lazy" width="1199" height="630" decoding="async" data-nimg="1" style="color:transparent" srcset="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexploring-haskell-types-and-classes.0vz_x_10npq76.png&amp;w=1200&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexploring-haskell-types-and-classes.0vz_x_10npq76.png&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexploring-haskell-types-and-classes.0vz_x_10npq76.png&amp;w=3840&amp;q=75">
<p>Code examples are adapted from <a href="https://www.edx.org/course/introduction-functional-programming-delftx-fp101x-0">Introduction to Functional Programming</a> course.</p>
<p>Access to <a href="https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/ghci.html">GHCi</a> is available on <a href="https://repl.it/">repl.it</a> to test out these snippets online.</p>
<h2>Types</h2>
<p>Evaluating an expression <code>e</code>.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token hvariable">e</span> <span class="token operator">::</span> <span class="token hvariable">t</span> <span class="token comment">-- This reads as e has type t, also used for type casting</span>
</code></pre>
<p>Every valid expression has a type, which is calculated using <em>type inference</em>.</p>
<p>To get a type in GHCi use <code>:t</code> which is an abbreviation for <code>:type</code> command.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token builtin">not</span> <span class="token constant">False</span> <span class="token comment">-- True</span>

<span class="token operator">:</span><span class="token hvariable">t</span> <span class="token builtin">not</span> <span class="token constant">False</span> <span class="token comment">-- not False :: Bool</span>
</code></pre>
<h3>Basic Types</h3>
<p>Some basic types that are common in other programming languages:</p>
<ul>
<li><code>Bool</code> - logical values</li>
<li><code>Char</code> - single character</li>
<li><code>String</code> - strings of characters</li>
<li><code>Int</code> - fixed-precision integers</li>
<li><code>Integer</code> - arbitrary-precision integers</li>
<li><code>Float</code> - floating-point numbers</li>
</ul>
<pre class="language-haskell"><code class="language-haskell"><span class="token operator">:</span><span class="token hvariable">t</span> <span class="token constant">True</span> <span class="token comment">-- Bool - logical values</span>

<span class="token operator">:</span><span class="token hvariable">t</span> <span class="token char string">'H'</span> <span class="token comment">-- Char - single character</span>
<span class="token operator">:</span><span class="token hvariable">t</span> <span class="token string">"Hi"</span> <span class="token comment">-- [Char] - strings of characters</span>

<span class="token operator">:</span><span class="token hvariable">t</span> <span class="token number">1</span> <span class="token comment">-- Num p =&gt; p</span>
<span class="token number">2</span><span class="token operator">^</span><span class="token number">64</span> <span class="token operator">::</span> <span class="token constant">Int</span> <span class="token comment">-- is out of the Int range (Overflow)</span>

<span class="token operator">:</span><span class="token hvariable">t</span> <span class="token number">2</span><span class="token operator">^</span><span class="token number">65</span> <span class="token comment">-- Num p =&gt; p</span>
<span class="token number">2</span><span class="token operator">^</span><span class="token number">65</span> <span class="token operator">::</span> <span class="token constant">Integer</span> <span class="token comment">-- 36893488147419103232</span>

<span class="token operator">:</span><span class="token hvariable">t</span> <span class="token number">1.5</span> <span class="token comment">-- Fractional p =&gt; p</span>
</code></pre>
<h3>List Types</h3>
<p>Lists in Haskell are polymorphic and can only contain a sequence of values with the same type.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token operator">:</span><span class="token hvariable">t</span> <span class="token punctuation">[</span><span class="token constant">False</span><span class="token punctuation">,</span> <span class="token constant">True</span><span class="token punctuation">,</span> <span class="token constant">False</span><span class="token punctuation">]</span> <span class="token comment">-- [False, True, False] :: [Bool]</span>

<span class="token operator">:</span><span class="token hvariable">t</span> <span class="token punctuation">[</span><span class="token char string">'a'</span><span class="token punctuation">,</span> <span class="token char string">'b'</span><span class="token punctuation">,</span> <span class="token char string">'c'</span><span class="token punctuation">,</span> <span class="token char string">'d'</span><span class="token punctuation">]</span> <span class="token comment">-- ['a', 'b', 'c', 'd'] :: [Char]</span>

<span class="token operator">:</span><span class="token hvariable">t</span> <span class="token punctuation">[</span><span class="token punctuation">[</span><span class="token char string">'a'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token char string">'b'</span><span class="token punctuation">,</span> <span class="token char string">'c'</span><span class="token punctuation">]</span><span class="token punctuation">]</span> <span class="token comment">-- [['a'], ['b', 'c']] -- :: [[Char]]</span>
</code></pre>
<h3>Tuple Types</h3>
<p>Tuples can contain sequence of values with different types</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token operator">:</span><span class="token hvariable">t</span> <span class="token punctuation">(</span><span class="token constant">False</span><span class="token punctuation">,</span> <span class="token constant">True</span><span class="token punctuation">)</span> <span class="token comment">-- (False, True) :: (Bool, Bool)</span>

<span class="token operator">:</span><span class="token hvariable">t</span> <span class="token punctuation">(</span><span class="token constant">False</span><span class="token punctuation">,</span><span class="token char string">'a'</span><span class="token punctuation">,</span><span class="token constant">True</span><span class="token punctuation">)</span> <span class="token comment">-- (False, 'a', True) :: (Bool, Char, Bool)</span>

<span class="token operator">:</span><span class="token hvariable">t</span> <span class="token punctuation">(</span><span class="token char string">'a'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token constant">False</span><span class="token punctuation">,</span> <span class="token char string">'b'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">-- ('a', (False, 'b')) :: (Char, (Bool, Char))</span>

<span class="token operator">:</span><span class="token hvariable">t</span> <span class="token punctuation">(</span><span class="token constant">True</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token char string">'a'</span><span class="token punctuation">,</span> <span class="token char string">'b'</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token comment">-- (True, ['a', 'b']) -- :: (Bool, [Char])</span>
</code></pre>
<h2>Functions</h2>
<p>A function is a mapping from values of one type to values of another type:</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token import-statement"><span class="token keyword">import</span> Data<span class="token punctuation">.</span>Char</span> <span class="token punctuation">(</span><span class="token builtin">isDigit</span><span class="token punctuation">)</span> <span class="token comment">-- Necessary for isDigit to work</span>
<span class="token operator">:</span><span class="token hvariable">t</span> <span class="token builtin">isDigit</span> <span class="token comment">-- isDigit :: Char -&gt; Bool</span>

<span class="token operator">:</span><span class="token hvariable">t</span> <span class="token builtin">not</span> <span class="token comment">-- not :: Bool -&gt; Bool</span>

<span class="token comment">-- Example functions</span>
<span class="token hvariable">add</span> <span class="token punctuation">(</span><span class="token hvariable">x</span><span class="token punctuation">,</span> <span class="token hvariable">y</span><span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token hvariable">x</span> <span class="token operator">+</span> <span class="token hvariable">y</span> <span class="token comment">-- add :: Num a =&gt; (a, a) -&gt; a</span>

<span class="token hvariable">zeroto</span> <span class="token hvariable">n</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token number">0</span><span class="token operator">..</span><span class="token hvariable">n</span><span class="token punctuation">]</span> <span class="token comment">-- zeroto :: (Num a, Enum a) =&gt; a -&gt; [a]</span>
</code></pre>
<h3>Curried Functions</h3>
<p>When a function returns as a result an another function it is called a <em>curried function</em>.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token hvariable">add'</span> <span class="token hvariable">x</span> <span class="token hvariable">y</span> <span class="token operator">=</span> <span class="token hvariable">x</span> <span class="token operator">+</span> <span class="token hvariable">y</span> <span class="token comment">-- add' :: Num a =&gt; a -&gt; a -&gt; a</span>
</code></pre>
<p>Both <code>add</code> and <code>add'</code> produce the same result, where <code>add</code> takes all arguments at the same time, and <code>add'</code> can consume one at a time.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token comment">-- Parenthesis in Haskell are right associative and are omitted for brevity.</span>
<span class="token hvariable">mult</span> <span class="token hvariable">x</span> <span class="token hvariable">y</span> <span class="token hvariable">z</span> <span class="token operator">=</span> <span class="token hvariable">x</span> <span class="token operator">*</span> <span class="token hvariable">y</span> <span class="token operator">*</span> <span class="token hvariable">z</span> <span class="token comment">-- mult :: Num a =&gt; a -&gt; (a -&gt; (a -&gt; a))</span>
</code></pre>
<h4>Why is Currying Useful?</h4>
<p>Currying makes functions more flexible and allows <em>partial application</em>.</p>
<p>Creating a function that increments by one:</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token hvariable">addOne</span> <span class="token operator">=</span> <span class="token hvariable">add'</span> <span class="token number">1</span>
<span class="token hvariable">addOne</span> <span class="token number">2</span> <span class="token comment">-- 3</span>
</code></pre>
<h3>Conventions for Currying</h3>
<p>To avoid excess parentheses when using curried functions there are two conventions:</p>
<ol>
<li>
<p>The <code>-&gt;</code> in type definition associates to the <em>right</em>.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token constant">Int</span> <span class="token operator">-&gt;</span> <span class="token constant">Int</span> <span class="token operator">-&gt;</span> <span class="token constant">Int</span> <span class="token operator">-&gt;</span> <span class="token constant">Int</span> <span class="token comment">-- Int -&gt; (Int -&gt; (Int -&gt; Int))</span>
</code></pre>
</li>
<li>
<p>Function application is associated to the <em>left</em>.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token hvariable">mult</span> <span class="token hvariable">x</span> <span class="token hvariable">y</span> <span class="token hvariable">z</span> <span class="token comment">-- ((mult x) y) z</span>
</code></pre>
</li>
</ol>
<p>Unless explicitly required, all functions in Haskell are defined in the curried form.</p>
<h2>Polymorphic Functions</h2>
<p>A function can be called polymorphic when its type contains one or more type variables</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token comment">-- length takes a 'collection' of type 'a' and returns an 'Int'</span>
<span class="token operator">:</span><span class="token keyword">type</span> <span class="token builtin">length</span> <span class="token comment">-- length :: Foldable t =&gt; t a -&gt; Int</span>

<span class="token builtin">length</span> <span class="token punctuation">[</span><span class="token constant">False</span><span class="token punctuation">,</span> <span class="token constant">True</span><span class="token punctuation">]</span> <span class="token comment">-- 2</span>
<span class="token builtin">length</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">]</span> <span class="token comment">-- 4</span>

<span class="token comment">-- More Examples</span>

<span class="token operator">:</span><span class="token hvariable">t</span> <span class="token builtin">fst</span> <span class="token comment">-- fst :: (a, b) -&gt; a</span>

<span class="token operator">:</span><span class="token hvariable">t</span> <span class="token builtin">head</span> <span class="token comment">-- head :: [a] -&gt; a</span>

<span class="token operator">:</span><span class="token hvariable">t</span> <span class="token builtin">take</span> <span class="token comment">-- take :: Int -&gt; [a] -&gt; [a]</span>

<span class="token operator">:</span><span class="token hvariable">t</span> <span class="token builtin">zip</span> <span class="token comment">-- zip :: [a] -&gt; [b] -&gt; [(a, b)]</span>

<span class="token operator">:</span><span class="token hvariable">t</span> <span class="token builtin">id</span> <span class="token comment">-- id :: a -&gt; a</span>
</code></pre>
<h2>Overloaded Functions</h2>
<p>A polymorphic function is called <em>overloaded</em> if its type contains one or more class constraints.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token comment">-- sum takes a list with numeric type 'a', and returns a value of type 'a'.</span>
<span class="token operator">:</span><span class="token hvariable">t</span> <span class="token builtin">sum</span> <span class="token comment">-- sum :: (Foldable t, Num a) =&gt; t a -&gt; a</span>

<span class="token builtin">sum</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">]</span> <span class="token comment">-- 6</span>
<span class="token builtin">sum</span> <span class="token punctuation">[</span><span class="token number">1.1</span><span class="token punctuation">,</span> <span class="token number">2.2</span><span class="token punctuation">,</span> <span class="token number">3.3</span><span class="token punctuation">]</span> <span class="token operator">-</span> <span class="token number">6.6</span>
<span class="token builtin">sum</span> <span class="token punctuation">[</span><span class="token char string">'a'</span><span class="token punctuation">,</span> <span class="token char string">'b'</span><span class="token punctuation">,</span> <span class="token char string">'c'</span><span class="token punctuation">]</span> <span class="token comment">-- error</span>
</code></pre>
<h2>Classes</h2>
<p>Haskell has a number of type classes:</p>
<ul>
<li><code>Num</code> - Numeric types</li>
<li><code>Eq</code> - Equality types</li>
<li><code>Ord</code> - Ordered types</li>
</ul>
<pre class="language-haskell"><code class="language-haskell"><span class="token operator">:</span><span class="token hvariable">t</span> <span class="token punctuation">(</span><span class="token operator">+</span><span class="token punctuation">)</span> <span class="token comment">-- (+) :: Num a =&gt; a -&gt; a -&gt; a</span>

<span class="token operator">:</span><span class="token hvariable">t</span> <span class="token punctuation">(</span><span class="token operator">==</span><span class="token punctuation">)</span> <span class="token comment">-- (==) :: Eq a =&gt; a -&gt; a -&gt; Bool</span>

<span class="token operator">:</span><span class="token hvariable">t</span> <span class="token punctuation">(</span><span class="token operator">&lt;</span><span class="token punctuation">)</span> <span class="token comment">-- (&lt;) :: Ord a =&gt; a -&gt; a -&gt; Bool</span>
</code></pre>
<p>And that's it for now.</p>]]></content:encoded>
            <author>anton@azdanov.dev (Anton Ždanov)</author>
        </item>
        <item>
            <title><![CDATA[Exploring Haskell: First Steps]]></title>
            <link>https://www.azdanov.dev/articles/2018/exploring-haskell-first-steps</link>
            <guid isPermaLink="false">https://www.azdanov.dev/articles/2018/exploring-haskell-first-steps</guid>
            <pubDate>Wed, 29 Aug 2018 10:32:01 GMT</pubDate>
            <content:encoded><![CDATA[<img alt="exploring haskell first steps" loading="lazy" width="1199" height="630" decoding="async" data-nimg="1" style="color:transparent" srcset="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexploring-haskell-first-steps.0p2ih2nli.r7x.png&amp;w=1200&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexploring-haskell-first-steps.0p2ih2nli.r7x.png&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexploring-haskell-first-steps.0p2ih2nli.r7x.png&amp;w=3840&amp;q=75">
<p>The code samples are adapted from <a href="https://www.edx.org/course/introduction-functional-programming-delftx-fp101x-0">Introduction to Functional Programming</a> course.</p>
<p>Best way to try these out is with <a href="https://repl.it/@azdanov/SardonicFoolishChapters">repl.it</a> where <a href="https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/ghci.html">GHCi</a> is easily accessible.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token comment">-- Basics</span>
<span class="token comment">-- The -- is used for comments</span>
<span class="token number">2</span> <span class="token operator">+</span> <span class="token number">3</span> <span class="token operator">*</span> <span class="token number">4</span> <span class="token comment">-- 14</span>
<span class="token punctuation">(</span><span class="token number">2</span> <span class="token operator">+</span> <span class="token number">3</span><span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token number">4</span> <span class="token comment">-- 20</span>

<span class="token comment">-- Alternative notation</span>
<span class="token punctuation">(</span><span class="token operator">+</span><span class="token punctuation">)</span> <span class="token number">2</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token operator">*</span><span class="token punctuation">)</span> <span class="token number">3</span> <span class="token number">4</span><span class="token punctuation">)</span> <span class="token comment">-- 14</span>
<span class="token punctuation">(</span><span class="token operator">*</span><span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token operator">+</span><span class="token punctuation">)</span> <span class="token number">2</span> <span class="token number">3</span><span class="token punctuation">)</span> <span class="token number">4</span> <span class="token comment">-- 20</span>

<span class="token comment">-- sqrt is a standard library function</span>
<span class="token builtin">sqrt</span> <span class="token punctuation">(</span><span class="token number">3</span><span class="token operator">^</span><span class="token number">2</span> <span class="token operator">+</span> <span class="token number">4</span><span class="token operator">^</span><span class="token number">2</span><span class="token punctuation">)</span> <span class="token comment">-- 5.0</span>

<span class="token comment">-- Anything in [] is a list which</span>
<span class="token comment">-- differs from an array or a vector</span>
<span class="token builtin">head</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token punctuation">,</span><span class="token number">5</span><span class="token punctuation">]</span> <span class="token comment">-- 1</span>
<span class="token builtin">tail</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token punctuation">,</span><span class="token number">5</span><span class="token punctuation">]</span> <span class="token comment">-- [2,3,4,5]</span>

<span class="token comment">-- Index from list at linear time</span>
<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token punctuation">,</span><span class="token number">5</span><span class="token punctuation">]</span> <span class="token operator">!!</span> <span class="token number">2</span> <span class="token comment">-- 3</span>

<span class="token builtin">take</span> <span class="token number">3</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token punctuation">,</span><span class="token number">5</span><span class="token punctuation">]</span> <span class="token comment">-- [1,2,3]</span>
<span class="token builtin">drop</span> <span class="token number">3</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token punctuation">,</span><span class="token number">5</span><span class="token punctuation">]</span> <span class="token comment">-- [4,5]</span>

<span class="token builtin">length</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token punctuation">,</span><span class="token number">5</span><span class="token punctuation">]</span> <span class="token comment">-- 5</span>

<span class="token builtin">sum</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token punctuation">,</span><span class="token number">5</span><span class="token punctuation">]</span> <span class="token comment">-- 15</span>
<span class="token builtin">product</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token punctuation">,</span><span class="token number">5</span><span class="token punctuation">]</span> <span class="token comment">-- 120</span>

<span class="token builtin">reverse</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token punctuation">,</span><span class="token number">5</span><span class="token punctuation">]</span> <span class="token comment">-- [5,4,3,2,1]</span>

<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">]</span> <span class="token operator">++</span> <span class="token punctuation">[</span><span class="token number">4</span><span class="token punctuation">,</span><span class="token number">5</span><span class="token punctuation">]</span> <span class="token comment">-- [1,2,3,4,5]</span>

<span class="token comment">-- Character</span>
<span class="token comment">-- '' are used for single character</span>
<span class="token char string">'H'</span> <span class="token comment">-- Char</span>

<span class="token comment">-- String</span>
<span class="token comment">-- "" are used for a string</span>
<span class="token string">"Hi"</span> <span class="token comment">-- [Char]</span>

<span class="token string">"Hel"</span> <span class="token operator">++</span> <span class="token string">"lo"</span> <span class="token comment">-- "Hello"</span>
<span class="token builtin">length</span> <span class="token string">"Hello"</span> <span class="token comment">-- 5</span>

<span class="token comment">-- Boolean</span>
<span class="token constant">True</span> <span class="token comment">-- True</span>
<span class="token constant">False</span> <span class="token comment">-- False</span>

<span class="token constant">True</span> <span class="token operator">||</span> <span class="token constant">False</span> <span class="token comment">-- True</span>
<span class="token builtin">not</span> <span class="token constant">True</span> <span class="token operator">&amp;&amp;</span> <span class="token constant">False</span> <span class="token comment">-- False</span>

<span class="token comment">-- Functions</span>
<span class="token hvariable">double</span> <span class="token hvariable">x</span> <span class="token operator">=</span> <span class="token hvariable">x</span> <span class="token operator">+</span> <span class="token hvariable">x</span> <span class="token comment">-- Num a =&gt; a -&gt; a</span>
<span class="token hvariable">double</span> <span class="token number">2</span> <span class="token comment">-- 4</span>

<span class="token hvariable">quadruple</span> <span class="token hvariable">x</span> <span class="token operator">=</span> <span class="token hvariable">double</span> <span class="token punctuation">(</span><span class="token hvariable">double</span> <span class="token hvariable">x</span><span class="token punctuation">)</span> <span class="token comment">-- Num a =&gt; a -&gt; a</span>
<span class="token hvariable">quadruple</span> <span class="token number">2</span> <span class="token comment">-- 8</span>

<span class="token hvariable">factorial</span> <span class="token hvariable">n</span> <span class="token operator">=</span> <span class="token builtin">product</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token operator">..</span><span class="token hvariable">n</span><span class="token punctuation">]</span> <span class="token comment">-- (Num a, Enum a) =&gt; a -&gt; a</span>
<span class="token hvariable">factorial</span> <span class="token number">5</span> <span class="token comment">-- 120</span>

<span class="token comment">-- f x y is equal to x `f` y</span>
<span class="token comment">-- `ns` indicates a list which is simplified Hungarian notation</span>
<span class="token hvariable">average</span> <span class="token hvariable">ns</span> <span class="token operator">=</span> <span class="token builtin">sum</span> <span class="token hvariable">ns</span> <span class="token operator">`div`</span> <span class="token builtin">length</span> <span class="token hvariable">ns</span> <span class="token comment">-- Foldable t =&gt; t Int -&gt; Int</span>
<span class="token hvariable">average</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token punctuation">,</span><span class="token number">5</span><span class="token punctuation">]</span> <span class="token comment">-- 3</span>

<span class="token comment">-- Types</span>

<span class="token operator">:</span><span class="token hvariable">t</span> <span class="token number">1</span> <span class="token comment">-- 1 :: Num p =&gt; p</span>
<span class="token operator">:</span><span class="token hvariable">t</span> <span class="token constant">True</span> <span class="token comment">-- True :: Bool</span>
<span class="token operator">:</span><span class="token hvariable">t</span> <span class="token char string">'H'</span> <span class="token comment">-- 'H' :: Char</span>
<span class="token operator">:</span><span class="token hvariable">t</span> <span class="token string">"Hello"</span> <span class="token comment">-- "Hello" :: [Char]</span>

<span class="token operator">:</span><span class="token hvariable">t</span> <span class="token builtin">head</span> <span class="token string">"Hello"</span> <span class="token comment">-- head "Hello" :: Char</span>

<span class="token operator">:</span><span class="token hvariable">t</span> <span class="token builtin">length</span> <span class="token comment">-- length :: Foldable t =&gt; t a -&gt; Int</span>

<span class="token comment">-- Tuples</span>

<span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span> <span class="token comment">-- (Num a, Num b) =&gt; (a, b)</span>

<span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token string">"Hello"</span><span class="token punctuation">)</span> <span class="token comment">-- Num a =&gt; (a, [Char])</span>

<span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">-- (Num a1, Num a2, Num b) =&gt; (a1, (a2, b))</span>

<span class="token builtin">fst</span> <span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token string">"Hello"</span><span class="token punctuation">)</span> <span class="token comment">-- 1</span>

<span class="token builtin">snd</span> <span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token string">"Hello"</span><span class="token punctuation">)</span> <span class="token comment">-- "Hello"</span>

<span class="token operator">:</span><span class="token hvariable">t</span> <span class="token builtin">fst</span> <span class="token comment">-- (a, b) -&gt; a</span>
<span class="token operator">:</span><span class="token hvariable">t</span> <span class="token builtin">snd</span> <span class="token comment">-- (a, b) -&gt; b</span>

<span class="token builtin">fst</span> <span class="token punctuation">(</span><span class="token builtin">snd</span> <span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">-- 2</span>

<span class="token comment">-- That's all folks!</span>
</code></pre>]]></content:encoded>
            <author>anton@azdanov.dev (Anton Ždanov)</author>
        </item>
        <item>
            <title><![CDATA[Being Bad at Something can Actually be Good]]></title>
            <link>https://www.azdanov.dev/articles/2018/being-bad-at-something-can-actually-be-good</link>
            <guid isPermaLink="false">https://www.azdanov.dev/articles/2018/being-bad-at-something-can-actually-be-good</guid>
            <pubDate>Wed, 29 Aug 2018 09:43:09 GMT</pubDate>
            <content:encoded><![CDATA[<img alt="being bad" loading="lazy" width="1024" height="576" decoding="async" data-nimg="1" style="color:transparent" srcset="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fbeing-bad-social.0vbd.u4-aw0pj.jpg&amp;w=1080&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fbeing-bad-social.0vbd.u4-aw0pj.jpg&amp;w=2048&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fbeing-bad-social.0vbd.u4-aw0pj.jpg&amp;w=2048&amp;q=75">
<p>I'm sure everyone had the moment of clear realization that "I'm bad at this", "it is too hard" and it would be much better and easier to quit now before too long. The awesome thing about these thoughts is that they act like road signs, and tell me that this is the right way to go.</p>
<p>Critically, thinking about one's strong and weak points allows adjustments to be made. Tired after climbing a couple of staircases? Do more sports. Bad at math? Find that old college algebra textbook and some exercises. Is memory becoming flaky? Learn more things by heart. Without conscious realization, it's impossible to change one's weak points, unless on the off chance.</p>
<p>So what happens next after realizing of being bad at something? Proper attitude matters. Think of kids, of how they don't give up at doing what is interesting to them. And as an adult, it's much easier to generate a similar attitude.</p>
<img alt="Leveling up" loading="lazy" width="576" height="576" decoding="async" data-nimg="1" style="color:transparent" srcset="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fbeing-bad.0k3-1rlzhbm1n.png&amp;w=640&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fbeing-bad.0k3-1rlzhbm1n.png&amp;w=1200&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fbeing-bad.0k3-1rlzhbm1n.png&amp;w=1200&amp;q=75">
<p>To summarize, a realization of own's weakness is a positive thing that everyone should pursue as often as possible. Afterward, positive attitude matters for the changes to happen.</p>
<p>Personally, I imagine this process as a game, an <a href="https://en.wikipedia.org/wiki/Role-playing_game">RPG</a> where anything is possible as long as there are enough skill points and character attributes are sufficient. Thinking in terms of a game helps me to understand that time and effort are necessary to <em>level up</em>. And as each new level in a game opens up new skills and perks, I am excited to see what's in store for me.</p>]]></content:encoded>
            <author>anton@azdanov.dev (Anton Ždanov)</author>
        </item>
        <item>
            <title><![CDATA[The Journey Begins: Functional Programming]]></title>
            <link>https://www.azdanov.dev/articles/2018/the-journey-begins-functional-programming</link>
            <guid isPermaLink="false">https://www.azdanov.dev/articles/2018/the-journey-begins-functional-programming</guid>
            <pubDate>Sun, 26 Aug 2018 08:51:39 GMT</pubDate>
            <content:encoded><![CDATA[<img alt="Journey" loading="lazy" width="1200" height="630" decoding="async" data-nimg="1" style="color:transparent" srcset="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fjourney-social.0ompmg.q.slsx.png&amp;w=1200&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fjourney-social.0ompmg.q.slsx.png&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fjourney-social.0ompmg.q.slsx.png&amp;w=3840&amp;q=75">
<p>For a while now I wanted to dive into <em>Functional Programming</em> to properly learn how to use <em>functional-lite</em> concepts in JavaScript. It took me some time to window shop for a language that I was satisfied with. The main criteria for me were language usage, popularity, ease of tooling and, most important, learning material. I didn't want to learn just the language, my goal was to learn functional programming and the language should be the medium.</p>
<p>I've looked at <a href="https://www.haskell.org/">Haskell</a> and <a href="https://elm-lang.org/">Elm</a>. Considered <a href="https://www.scala-lang.org/">Scala</a>, <a href="https://clojure.org/">Clojure</a>, and <a href="https://fsharp.org/">F#</a>. Checked out <a href="https://racket-lang.org/">Racket</a>, <a href="https://common-lisp.net/">Lisp</a>, and <a href="https://en.wikipedia.org/wiki/Scheme_(programming_language)">Scheme</a>. And wondered about <a href="https://ocaml.org/">OCaml</a> / <a href="https://reasonml.github.io/">ReasonML</a> and <a href="https://www.erlang.org/">Erlang</a>. That's quite a list, and that's only scratching the surface.</p>
<img alt="Journey" loading="lazy" width="1113" height="1113" decoding="async" data-nimg="1" style="color:transparent" srcset="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fjourney.0bwhtll_5~1pw.png&amp;w=1200&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fjourney.0bwhtll_5~1pw.png&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fjourney.0bwhtll_5~1pw.png&amp;w=3840&amp;q=75">
<p>In the end, my choice fell on <strong>Haskell</strong> because of available learning materials and its purity. It would force me to learn how to properly use <em>functional programming concepts</em> and not revert back to <em>imperative style</em> while facing difficulties.</p>
<h2>Companions</h2>
<ul>
<li><a href="https://www.edx.org/course/introduction-functional-programming-delftx-fp101x-0">Introduction to Functional Programming</a> - The main purpose of this course is to introduce a complete beginner to functional programming with help of Haskell. The language is not the main focus, the course is <em>free</em> and in video format, just what I've been looking for.</li>
<li><a href="http://learnyouahaskell.com/">Learn You a Haskell</a> - A <em>free</em> book that was made with a beginner to functional programming in mind.</li>
<li><a href="http://book.realworldhaskell.org/">Real World Haskell</a> - Another <em>free</em> book that is good for beginners and intermediate Haskell enthusiasts.</li>
<li><a href="https://mostly-adequate.gitbooks.io/mostly-adequate-guide/">Mostly Adequate Guide to FP</a> - This is an excellent and <em>free</em> book that helps with learning how to apply functional programming concepts using JavaScript for daily usage.</li>
<li><a href="http://www.cs.nott.ac.uk/~pszgmh/pih.html">Programming in Haskell</a> - I've heard good things about this book. Which is recommended by <a href="https://www.edx.org/bio/erik-meijer">Erik Meijer</a>, author of Introduction to Functional Programming course.</li>
<li><a href="http://haskellbook.com/">Haskell Programming from first principles</a> - This book was recommended a lot during my online search. A potential buy.</li>
</ul>
<h2>A Taste of Haskell</h2>
<p>An quick example from <a href="https://www.edx.org/course/introduction-functional-programming-delftx-fp101x-0">Introduction to Functional Programming</a> course to whet one's appetite for what's to come.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token comment">-- Quicksort</span>
<span class="token hvariable">f</span> <span class="token operator">::</span> <span class="token punctuation">(</span><span class="token constant">Ord</span> <span class="token hvariable">a</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">[</span><span class="token hvariable">a</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token punctuation">[</span><span class="token hvariable">a</span><span class="token punctuation">]</span>
<span class="token hvariable">f</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>       <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>
<span class="token hvariable">f</span> <span class="token punctuation">(</span><span class="token hvariable">x</span> <span class="token operator">:</span> <span class="token hvariable">xs</span><span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token hvariable">ys</span> <span class="token operator">++</span> <span class="token punctuation">[</span><span class="token hvariable">x</span><span class="token punctuation">]</span> <span class="token operator">++</span> <span class="token hvariable">zs</span>
 <span class="token keyword">where</span>
  <span class="token hvariable">ys</span> <span class="token operator">=</span> <span class="token hvariable">f</span> <span class="token punctuation">[</span> <span class="token hvariable">a</span> <span class="token operator">|</span> <span class="token hvariable">a</span> <span class="token operator">&lt;-</span> <span class="token hvariable">xs</span><span class="token punctuation">,</span> <span class="token hvariable">a</span> <span class="token operator">&lt;=</span> <span class="token hvariable">x</span> <span class="token punctuation">]</span>
  <span class="token hvariable">zs</span> <span class="token operator">=</span> <span class="token hvariable">f</span> <span class="token punctuation">[</span> <span class="token hvariable">a</span> <span class="token operator">|</span> <span class="token hvariable">a</span> <span class="token operator">&lt;-</span> <span class="token hvariable">xs</span><span class="token punctuation">,</span> <span class="token hvariable">a</span> <span class="token operator">&gt;</span> <span class="token hvariable">x</span> <span class="token punctuation">]</span>
</code></pre>
<p>Beautiful.</p>]]></content:encoded>
            <author>anton@azdanov.dev (Anton Ždanov)</author>
        </item>
        <item>
            <title><![CDATA[Refactoring for Fun and Profit: From TypeScript to Flow]]></title>
            <link>https://www.azdanov.dev/articles/2018/refactor-for-fun-and-profit-from-typescript-to-flow</link>
            <guid isPermaLink="false">https://www.azdanov.dev/articles/2018/refactor-for-fun-and-profit-from-typescript-to-flow</guid>
            <pubDate>Fri, 24 Aug 2018 17:28:05 GMT</pubDate>
            <content:encoded><![CDATA[<img alt="Refactor" loading="lazy" width="1199" height="630" decoding="async" data-nimg="1" style="color:transparent" srcset="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Frefactor-social.0d.1i5id61z52.png&amp;w=1200&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Frefactor-social.0d.1i5id61z52.png&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Frefactor-social.0d.1i5id61z52.png&amp;w=3840&amp;q=75">
<p>Initially, I've built this website with TypeScript. During development, I neglected to follow the TDD methodology. Didn't do a thorough research of the eco-system. Had no solid goal of what should be the end-product. And in the end, had to rewrite everything from <a href="https://www.typescriptlang.org/">TypeScript</a> in <a href="https://flow.org/">Flow</a>. Why? There are several points that helped me decide on this rather expensive process of refactoring the whole codebase.</p>
<h2>Decisions</h2>
<ul>
<li><strong>Testing</strong> - <a href="https://jestjs.io/">The Jest testing framework</a> was made for JavaScript. Later on, community-created <a href="https://github.com/facebook/jest/tree/master/packages/babel-jest">babel-jest</a> was made to support newest <a href="https://en.wikipedia.org/wiki/ECMAScript">ECMAScript</a> syntax. For TypeScript, there is <a href="https://github.com/kulshekhar/ts-jest">ts-jest</a>, which work remarkably well. Later on, the babel-jest has been integrated into main Jest repository and remains officially supported, on the other hand, ts-jest, while having great contributors, is unofficial, and thus receives less love from Jest team, and has certain quirks. For me, it was <em>source-maps</em> and <em>babel</em>.</li>
<li><strong>Type Definitions</strong> - <a href="https://definitelytyped.org/">DefinitelyTyped</a> is incredible. How smoothly it integrates with <a href="https://code.visualstudio.com/">VSCode</a>. How fast and easy it is to use. There are thousands of types for all sorts of packages ready to be used. Flow, on the other hand, offers a more modest option: <a href="https://github.com/flow-typed/flow-typed">flow-typed</a>. Although it is well maintained, fewer people use flow and thus contribute less by creating type definitions and supporting existing ones. The issue for me was the nature of TypeScript itself, and how an error in an existing type definition propagates towards end-user. After updating dependencies I've had functioning code blow up on me with type errors due to minor changes in type definitions or even TypeScript itself, which started to drive me crazy. On the other hand Flow by its nature is more of an add-on than a language, with its opt-in behavior. It is much easier to circumvent such annoying behavior. And last but not least, Flow type definitions for React are created, used and supported for Facebook.</li>
<li><strong>Gatsby</strong> - Similar to Jest, <a href="https://www.gatsbyjs.org/">Gatsby</a> is written in JavaScript, with some of its packages in Flow. Overall support for TypeScript exists, but it's, understandably, not the primary concern of Gatsby's team. I've had good experience developing in TypeScript, but issues with debugging, testing and type definitions started to accumulate, and resolution was not in sight. Whereas Flow's opt-in nature allows to freely switch from untyped JavaScript to strict Flow's syntax. It mattered a lot since at the time of the writing <em>Gatsby v2</em> was in beta.</li>
</ul>
<h2>Outcome</h2>
<p>In the end, I'm glad that I've had to experience a complete refactoring process. This allowed me to learn a lot more about TypeScript and Flow, their eco-systems and what pro and cons each language have.</p>
<p>And by no means, one language is better than other. I love both TypeScript and Flow, and cannot imagine starting a new project without using one or the other. Tools and requirements can differ and to choose proper one's matter a lot. But static type-checking is a must.</p>
<img alt="Goku and Vegeta fist bump" loading="lazy" width="1050" height="1050" decoding="async" data-nimg="1" style="color:transparent" srcset="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Frefactor.08x8~4-z3sm_b.png&amp;w=1080&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Frefactor.08x8~4-z3sm_b.png&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Frefactor.08x8~4-z3sm_b.png&amp;w=3840&amp;q=75">]]></content:encoded>
            <author>anton@azdanov.dev (Anton Ždanov)</author>
        </item>
        <item>
            <title><![CDATA[Learning How to Learn]]></title>
            <link>https://www.azdanov.dev/articles/2018/learning-how-to-learn</link>
            <guid isPermaLink="false">https://www.azdanov.dev/articles/2018/learning-how-to-learn</guid>
            <pubDate>Wed, 22 Aug 2018 07:14:23 GMT</pubDate>
            <content:encoded><![CDATA[<img alt="learning" loading="lazy" width="1200" height="630" decoding="async" data-nimg="1" style="color:transparent" srcset="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Flearning-social.16ccmr6-cbmhv.png&amp;w=1200&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Flearning-social.16ccmr6-cbmhv.png&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Flearning-social.16ccmr6-cbmhv.png&amp;w=3840&amp;q=75">
<p>What could be considered the most important skill nowadays? Of course, it depends on the line of work one does. Yet we hear a lot about the importance of so-called <em>soft</em> skills. That <em>math</em> or <em>algorithms</em> or <em>logic</em> is important. It's clear that there is no fixed standard concerning skills.</p>
<p>Let's get to the origin of this stuff. <em>Learning</em>. Without <em>learning</em> would it be possible to acquire knowledge of <em>soft</em> skills? Would it be possible to learn <em>math</em> or <em>programming</em>? Probably impossible.</p>
<h2>Learning</h2>
<p>We now can see that <em>learning</em> is important. But how can <em>learning</em> be learned? And what does it mean to <em>learn</em> something?</p>
<p>The simple answer is <em>practice</em> and <em>repetition</em>. Until familiarity sets in, thus something becomes a <em>skill</em>.</p>
<p>For example <em>juggling</em>, at first, it's hard, unrewarding, and doesn't resemble anything at all. But as it gets familiar, incredible feats can be accomplished. And something clumsy can become a valuable <em>skill</em>.</p>
<p>So <em>learning</em> is the journey, the process of getting from an undesirable place to where one wants to be. And since it is also a skill, then repetition and practice also enhance <em>learning</em>.</p>
<img alt="learning to juggle" loading="lazy" width="4993" height="4020" decoding="async" data-nimg="1" style="color:transparent" srcset="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Flearning.0xr20n5fcsjl7.png&amp;w=3840&amp;q=75 1x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Flearning.0xr20n5fcsjl7.png&amp;w=3840&amp;q=75">
<h2>Resources</h2>
<p>Of course, there are many tips, tricks, and shortcuts one can employ to make the journey comfortable and productive. There are experts in the field of learning, who write books, create videos and whole courses on the subject.</p>
<p>I will share some of them:</p>
<ul>
<li><a href="https://www.coursera.org/learn/learning-how-to-learn">Learning How To Learn</a> - A course which is taught by <a href="https://barbaraoakley.com/">Dr. Barbara Oakley</a> that dives deep into the process of learning, how our brains work, and what are the most efficient ways to learn. A bird's eye view of the learning landscape.</li>
<li><a href="https://www.goodreads.com/book/show/18693655-a-mind-for-numbers">A Mind For Numbers</a> - A companion book to the previously mentioned course. Reading this book along while doing the course really helps to solidify the <em>learning</em> skill. Remember <em>repetition</em> and <em>practice</em>?</li>
<li><a href="https://www.goodreads.com/book/show/590652.The_Slight_Edge">The Slight Edge</a> - Teaches how small consistent chunks of any action, positive or negative, build up to an avalanche, in the end, that will either carry you where you want to get or to some undesirable place. Habits matter.</li>
<li><a href="https://www.goodreads.com/book/show/12609433-the-power-of-habit">The Power of Habit</a> - Habits do govern our lives, whether we notice that or not. This book really helped me to see why I do certain things, and ignore others. Habit forming is detrimental to the <em>learning</em> skill.</li>
<li><a href="https://www.goodreads.com/book/show/6708.The_Power_of_Now">The Power of Now</a> - Mindfulness. Understanding how thoughts can affect us. How and why it is important to "control" the thinking process, is the main idea of this book. In short, <em>letting go</em> is the answer.</li>
</ul>
<p>And a reminder to myself: do reiterate the mentioned resources and continue <em>learning how to learn</em> with other books and courses.</p>]]></content:encoded>
            <author>anton@azdanov.dev (Anton Ždanov)</author>
        </item>
        <item>
            <title><![CDATA[OSS Made Me Do It: Personal Website]]></title>
            <link>https://www.azdanov.dev/articles/2018/oss-made-me-do-it-personal-website</link>
            <guid isPermaLink="false">https://www.azdanov.dev/articles/2018/oss-made-me-do-it-personal-website</guid>
            <pubDate>Mon, 20 Aug 2018 05:14:08 GMT</pubDate>
            <content:encoded><![CDATA[<img alt="OSS" loading="lazy" width="1200" height="630" decoding="async" data-nimg="1" style="color:transparent" srcset="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Foss-social.04-~1uf01a9e~.png&amp;w=1200&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Foss-social.04-~1uf01a9e~.png&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Foss-social.04-~1uf01a9e~.png&amp;w=3840&amp;q=75">
<p>This website would not exist without open-source software. Many applications that are popular would not exist without open-source software. And even some jobs would be impossible without open-source software. So I guess OSS is quite important.</p>
<blockquote><p>If I have seen further it is by standing on the shoulders of giants.</p><cite><p>–<!-- --> </p><a href="https://en.wikipedia.org/wiki/Isaac_Newton?oldformat=true#cite_ref-107"><p>Isaac Newton</p></a></cite></blockquote>
<p>But back to my website. On the outside, it may look simple, but many complicated concepts were used during its creation. Different languages, tools that convert and optimize code, mechanisms for putting everything together. Of course, plain old <code>HTML</code>, <code>CSS</code>, and <code>JS</code> can still be used, but nowadays it's just not enough.</p>
<p>Tech leaders are constantly raising the bar on expectations. Websites are getting faster, they have more features and can do a lot more than before. Sometimes the edge between a desktop application and a web-based one is so thin that it's hard to notice. Consider some of the popular ones like <em>Gmail</em>, <em>Dropbox</em>, <em>Google Docs</em>. Before a user needed an <em>email client</em> installed and configured on a computer. And <em>ftp program</em> with an external preconfigured host to upload and download files. And a locally installed, often heavyweight, <em>word processor</em>.</p>
<p>And by using community made open-source software it is possible to catch up to and even surpass your end-users expectations. And everyone can agree that a happy user is always good for business.</p>
<img alt="OSS made me do it" loading="lazy" width="1200" height="1200" decoding="async" data-nimg="1" style="color:transparent" srcset="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Foss.0z-14_8_1hkmg.png&amp;w=1200&amp;q=75 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Foss.0z-14_8_1hkmg.png&amp;w=3840&amp;q=75 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Foss.0z-14_8_1hkmg.png&amp;w=3840&amp;q=75">
<h2>Acknowledgements</h2>
<p>Many different tools were used in the process of creating this website. If I missed some it's not because they are unimportant <em>(amnesia happens)</em>.</p>
<ul>
<li><a href="https://www.gatsbyjs.org/">Gatsby</a> - Blazingly fast site generator for <a href="https://reactjs.org/">React</a> that can be used for building blogs, e-commerce sites, and full-blown apps.</li>
<li><a href="https://reactjs.org/">React</a> - A library for building modern, fast and maintainable user interfaces and in my case websites.</li>
<li><a href="https://www.typescriptlang.org/">TypeScript</a> - An open-source programming language which is a strict syntactical superset of <em>JavaScript</em>, and adds optional static typing to the language. In other words, building complex projects get a lot easier.</li>
<li><a href="https://sass-lang.com/">SASS</a> - As its name implies, <em>Syntactically Awesome StyleSheets</em>, it's an extension for <a href="https://en.wikipedia.org/wiki/Cascading_Style_Sheets">CSS</a> language, that adds numerous features, which have become an industry standard by this point.</li>
<li><a href="https://nodejs.org/">Node.js</a> - "[…] is an open-source, cross-platform <em>JavaScript</em> run-time environment that executes <em>JavaScript</em> code outside the browser". What was not hard or impossible before, is simple thanks to <em>Node.js</em>.</li>
<li><a href="https://www.netlify.com/">Netlify</a> - A hosting provider that simplifies the building, deploying, and managing of modern web projects. And it's also free.</li>
<li><a href="https://github.com/">GitHub</a> - "[…] brings together the world's largest community of developers to discover, share, and build better software". As their description state, OSS is possible because of <em>GitHub</em> and similar services that simplify cooperation.</li>
<li><a href="https://code.visualstudio.com/">Visual Studio Code</a> - A lightweight but powerful source code editor which runs on your desktop and is available for <em>Windows</em>, <em>macOS</em>, and <em>Linux</em>. It comes with built-in support for <em>JavaScript</em>, <em>TypeScript</em> and <em>Node.js</em> and has a rich ecosystem of extensions for other languages.</li>
</ul>]]></content:encoded>
            <author>anton@azdanov.dev (Anton Ždanov)</author>
        </item>
    </channel>
</rss>