<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Justinas Stankevičius</title><link href="https://justinas.org/" rel="alternate"/><link href="https://justinas.org/feeds/all.atom.xml" rel="self"/><id>https://justinas.org/</id><updated>2024-09-25T16:00:00+00:00</updated><entry><title>The bizarre world of V</title><link href="https://justinas.org/the-bizarre-world-of-v" rel="alternate"/><published>2024-09-25T16:00:00+00:00</published><updated>2024-09-25T16:00:00+00:00</updated><author><name>Justinas Stankevičius</name></author><id>tag:justinas.org,2024-09-25:/the-bizarre-world-of-v</id><summary type="html">&lt;p&gt;V ("The V Programming Language", "vlang") is a programming language
that first emerged in 2019.
A brainchild of Alexander Medvednikov, it is described as a
"[s]imple, fast, safe, compiled language for developing maintainable software"&lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt;,
supposedly drawing inspiration from languages like Go, Rust, Swift, C, among others.
The vision …&lt;/p&gt;</summary><content type="html">&lt;p&gt;V ("The V Programming Language", "vlang") is a programming language
that first emerged in 2019.
A brainchild of Alexander Medvednikov, it is described as a
"[s]imple, fast, safe, compiled language for developing maintainable software"&lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt;,
supposedly drawing inspiration from languages like Go, Rust, Swift, C, among others.
The vision for V is a language that combines
all the good parts of the aforementioned inspirations,
while avoiding most of the complexity.&lt;/p&gt;
&lt;p&gt;V's tall ambitions and its barebone state upon release
resulted in mixed reception in online spaces.
This article aims to summarize the situation,
covering V's unfulfilled promises, questionable decisions,
and its uncertain future.&lt;/p&gt;
&lt;h1 id="table-of-contents"&gt;Table of Contents&lt;/h1&gt;
&lt;p&gt;The article has a loose structure of
starting with the more easily falsifiable claims about V,
and getting more into subjective criticisms later on.&lt;/p&gt;
&lt;!-- vim-markdown-toc GFM --&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="#disclaimers"&gt;Disclaimers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#analysis"&gt;Analysis&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="#shifting-timelines"&gt;Shifting timelines&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="#cc-translation"&gt;C/C++ translation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#native-x64-code-generation"&gt;Native x64 code generation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#memory-unmanagement"&gt;Memory unmanagement&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="#early-v"&gt;Early V&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#v-02-and-the-zero-leaks-demo"&gt;V 0.2 and the "zero leaks" demo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#status-quo"&gt;Status quo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#redefining-terms"&gt;Redefining terms&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="#undefined-behavior"&gt;Undefined behavior&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#static-binaries-that-are-not"&gt;Static binaries that are not&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#other-misnomers"&gt;Other misnomers&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#casting-a-wide-net"&gt;Casting a wide net&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="#backends"&gt;Backends&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#batteries-included-but-not-yet-charged"&gt;Batteries included (but not yet charged)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#v-10-and-the-stability-guarantee"&gt;V 1.0 and the stability guarantee&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#the-author"&gt;The author&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="#its-just-a-bug"&gt;"It's just a bug"&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#things-change"&gt;"Things change"&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#a-broader-pattern"&gt;A broader pattern&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#he-just-like-me-fr"&gt;He just like me fr&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#outro"&gt;Outro&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="#recommended-reading"&gt;Recommended reading&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#footnotes"&gt;Footnotes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;!-- vim-markdown-toc --&gt;

&lt;h1 id="disclaimers"&gt;Disclaimers&lt;/h1&gt;
&lt;p&gt;Some of you may ask, why write this article, especially at this point in time?
The flamewars have mostly ceased, V has a small, passionate community of contributors
who have not been detracted from their goals by criticism
and keep driving the project forward.&lt;/p&gt;
&lt;p&gt;The simple answer is, I usually speak (er, write) about such topics
only when I think I have something to say that has not been said before.
In this case, I have not seen anyone take this broad of a look at V in a while &amp;mdash;
one that would look at both the historical context and the current state of V,
while at the same time providing the &lt;em&gt;receipts&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;V &lt;em&gt;will&lt;/em&gt; get discussed outside of its own community again.
Someone will ask "what was the V controversy all about anyway?",
and the creator will dismiss any arguments on frivolous basis again.
I think it's better for me to write down my observations
once in a long-form blog post, rather than in various ephemeral discussions.&lt;/p&gt;
&lt;p&gt;One thing I must note is, I have no experience developing programming languages.
Because of that, this article contains minimal criticisms
on hardcore technical / scientific PL development basis,
and mostly takes the perspective of a programming language &lt;em&gt;user&lt;/em&gt; instead.&lt;/p&gt;
&lt;p&gt;I'd also like to clearly state that I have zero intention
to cause any harassment to Alex or any other V community member.
Let's keep the discussion grounded and professional.&lt;/p&gt;
&lt;h1 id="analysis"&gt;Analysis&lt;/h1&gt;
&lt;h2 id="shifting-timelines"&gt;Shifting timelines&lt;/h2&gt;
&lt;p&gt;This section mostly deals with historical claims about V's functionality.
Anyone evaluating V for use today should obviously make judgement
based on the language's current state.
However, I think it is crucial to pay attention to the fact that at V's inception,
many claims were made that were even more fantastical than the ones V makes nowadays.&lt;/p&gt;
&lt;p&gt;As we will see shortly, many of these claims were not true
on V's initial release in 2019.
Instead of the functionality reaching parity with the promises made,
statements about V's features were slowly watered down over time,
until some of them quietly disappeared altogether.
V as it exists in 2024 still does not live up to even these (now weaker) promises.&lt;/p&gt;
&lt;h3 id="cc-translation"&gt;C/C++ translation&lt;/h3&gt;
&lt;p&gt;The ability of the V compiler to translate arbitrary C and C++ code to V
was a feature advertised very early on in V's lifecycle.
On February 2019, V's website stated:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;V can translate your entire C/C++ project and offer you the safety, simplicity, and up to 200x compilation speed up.&lt;/p&gt;
&lt;p&gt;[...]&lt;/p&gt;
&lt;p&gt;[The translator] supports the latest standard of notoriously complex C++ and allows full automatic conversion to human readable code.&lt;sup id="fnref:2"&gt;&lt;a class="footnote-ref" href="#fn:2"&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This claim was supplemented by links to supposed articles
detailing the translation of popular C and C++ software:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Read about translating Doom &amp;amp; Doom 3, LevelDB, SQLite.&lt;sup id="fnref2:2"&gt;&lt;a class="footnote-ref" href="#fn:2"&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The "Doom &amp;amp; Doom 3" anchor linked to &lt;code&gt;https://vlang.io/doom&lt;/code&gt;,
which may have existed at some point,
but has not been archived by the Wayback Machine.
Meanwhile, the LevelDB and SQLite links were placeholders (linking to &lt;code&gt;#&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;The promised articles then failed to appear in the next few months:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;As of March 3rd, 2019, the hyperlinks become inactive.
  &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; tags are replaced &lt;code&gt;&amp;lt;u&amp;gt;&lt;/code&gt; tags &amp;mdash; underlined to look like links.
  The section describing this feature ends with:&lt;blockquote&gt;
&lt;p&gt;[...] LevelDB, SQLite (coming in March).&lt;sup id="fnref4:3"&gt;&lt;a class="footnote-ref" href="#fn:3"&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;On April 4th, 2019, it states "coming in early April" instead.&lt;sup id="fnref2:4"&gt;&lt;a class="footnote-ref" href="#fn:4"&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;On May 6th, 2019, the text becomes simply "coming soon".&lt;sup id="fnref:5"&gt;&lt;a class="footnote-ref" href="#fn:5"&gt;5&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To this day, the home page says that the (single) article is coming:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A blog post about translating DOOM will be published. &lt;sup id="fnref7:24"&gt;&lt;a class="footnote-ref" href="#fn:24"&gt;24&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Although in 2022, a &lt;code&gt;tutorials/C2V. Translating simple programs and DOOM./README.md&lt;/code&gt;
appeared in the GitHub repository.&lt;sup id="fnref:46"&gt;&lt;a class="footnote-ref" href="#fn:46"&gt;46&lt;/a&gt;&lt;/sup&gt;
This is probably the article in question,
and Alex just forgot to link it from the homepage.&lt;/p&gt;
&lt;p&gt;Now, I'll let one who has never procrastinated on their side project or an article
cast the first stone,
but let's see what Alex says about the actual functionality elsewhere.
In a Hacker News thread in late March 2019, he states:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;C++ translation will be done by the time the language is open sourced. I can already compile simpler projects.&lt;/p&gt;
&lt;p&gt;I support [translating] STL and even plan to support Boost&lt;sup id="fnref:6"&gt;&lt;a class="footnote-ref" href="#fn:6"&gt;6&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;On May 19, 2019, vlang.io states:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[The translator] already supports C and will soon support the latest standard of notoriously complex C++.&lt;sup id="fnref:7"&gt;&lt;a class="footnote-ref" href="#fn:7"&gt;7&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The claim of "supporting the latest standard of notoriously complex C++"
has been downgraded to "will soon support".&lt;/p&gt;
&lt;p&gt;Sometime before June 24, 2019, the "C++ translation", among an assortment of other features, gets a "WIP" (work in progress) label on the website&lt;sup id="fnref:29"&gt;&lt;a class="footnote-ref" href="#fn:29"&gt;29&lt;/a&gt;&lt;/sup&gt;,
seemingly as a reaction to the lukewarm reception in the Hacker News thread
about the open-source release on June 22, 2019.&lt;sup id="fnref:8"&gt;&lt;a class="footnote-ref" href="#fn:8"&gt;8&lt;/a&gt;&lt;/sup&gt;
One commenter points out:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Now that (part of?) the code has been released, it seems to be little more than a transpiler from V to C, with allowed inlined C, with most advertised features stubbed out.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There might have been further developments on the translation feature during
mid-2019 to end of 2020. I have only so much willingness to scour the archives.&lt;/p&gt;
&lt;p&gt;On New Year's Day 2021, V's Twitter account announces:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;C2V itself will be open-sourced next week.&lt;sup id="fnref:9"&gt;&lt;a class="footnote-ref" href="#fn:9"&gt;9&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;More time passes without any official news. Then, on June 22, 2022 &amp;mdash;
roughly 1.5 years after the "next week" announcement &amp;mdash;
an "Initial commit" is made to the C2V repository.&lt;sup id="fnref:10"&gt;&lt;a class="footnote-ref" href="#fn:10"&gt;10&lt;/a&gt;&lt;/sup&gt; The &lt;code&gt;v translate&lt;/code&gt; compiler command is finally officially released in V 0.3 a week later.&lt;sup id="fnref:11"&gt;&lt;a class="footnote-ref" href="#fn:11"&gt;11&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;To summarize C2V, the public was once promised that V
"supports the latest standard of notoriously complex C++ [...]".
5 years later, it is nowhere near these capabilities.
It seems to be able to translate &lt;em&gt;some C code&lt;/em&gt;, although features as simple as
reading the command line arguments produce invalid V code&lt;sup id="fnref:62"&gt;&lt;a class="footnote-ref" href="#fn:62"&gt;62&lt;/a&gt;&lt;/sup&gt;.
V's roadmap states that full C99 support is slated for version 1.0&lt;sup id="fnref:18"&gt;&lt;a class="footnote-ref" href="#fn:18"&gt;18&lt;/a&gt;&lt;/sup&gt;,
indicating that the C translation feature is still incomplete
(C99 is not really some exotic thing anymore).&lt;/p&gt;
&lt;p&gt;C++ translation is nowhere to be seen:
C2V's &lt;code&gt;tests&lt;/code&gt; directory seemingly does not contain a single C++ test case.
The part of the code that would seem to be responsible for C++ translation
has not been touched since January of 2023,
and the method handling declarations of destructors (an essential feature of C++)
is empty.&lt;sup id="fnref:12"&gt;&lt;a class="footnote-ref" href="#fn:12"&gt;12&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;Indeed, it looks like V can not translate any C++:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;v&lt;span class="w"&gt; &lt;/span&gt;version
&lt;span class="go"&gt;V 0.4.6 fccd7cd&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;trivial.cpp
&lt;span class="gp"&gt;#&lt;/span&gt;include&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;iostream&amp;gt;
&lt;span class="go"&gt;using namespace std;&lt;/span&gt;

&lt;span class="go"&gt;int main() {&lt;/span&gt;
&lt;span class="go"&gt;  cout &amp;lt;&amp;lt; &amp;quot;Hello from V?&amp;quot; &amp;lt;&amp;lt; endl;&lt;/span&gt;
&lt;span class="go"&gt;  return 0;&lt;/span&gt;
&lt;span class="go"&gt;}&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;v&lt;span class="w"&gt; &lt;/span&gt;translate&lt;span class="w"&gt; &lt;/span&gt;trivial.cpp
&lt;span class="go"&gt;C to V translator 0.4.0&lt;/span&gt;
&lt;span class="go"&gt;  translating /home/justinas/vlang-box/trivial.cpp ... C++ top level&lt;/span&gt;
&lt;span class="go"&gt;C++ top level&lt;/span&gt;
&lt;span class="go"&gt;C++ top level&lt;/span&gt;
&lt;span class="go"&gt;C++ top level&lt;/span&gt;
&lt;span class="go"&gt;C++ top level&lt;/span&gt;
&lt;span class="go"&gt;C2V command: &amp;#39;/home/justinas/.vmodules/c2v/c2v&amp;#39; &amp;#39;trivial.cpp&amp;#39;&lt;/span&gt;
&lt;span class="go"&gt;C2V failed to translate the C files. Please report it via GitHub.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="native-x64-code-generation"&gt;Native x64 code generation&lt;/h3&gt;
&lt;p&gt;Producing native code without the use of LLVM or a C compiler as an intermediary
was another claim made at the very start of V's public existence.&lt;/p&gt;
&lt;p&gt;On February 2019, the V homepage stated:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Does V use LLVM?&lt;/p&gt;
&lt;p&gt;No. &lt;strong&gt;V compiles directly to machine code.&lt;/strong&gt; It's one of the main reasons it's so light and fast. Right now only x64 architecture is supported.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;V can also emit human readable C&lt;/strong&gt;, which can then be compiled to run on any platform.&lt;sup id="fnref3:2"&gt;&lt;a class="footnote-ref" href="#fn:2"&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The parts emphasized (by me) seem to imply that
the native code generation backend is the main one,
and is one of the primary reasons behind V's claims of fast compilation,
while the C generation backend is merely an additional option.&lt;/p&gt;
&lt;p&gt;On March 30, 2019, Alex once again reiterates on a Hacker News thread:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Right now [V] can emit x64 machine code&lt;sup id="fnref:13"&gt;&lt;a class="footnote-ref" href="#fn:13"&gt;13&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;V's initial open-source release on June 22, 2019&lt;sup id="fnref:14"&gt;&lt;a class="footnote-ref" href="#fn:14"&gt;14&lt;/a&gt;&lt;/sup&gt; seemingly did not contain any code implementing a native x64 backend.
What looks like a call to the supposed x64 backend is &lt;a href="https://github.com/vlang/v/blob/d32e538073e55c603992b5b65ebc837b01c28576/compiler/main.v#L264"&gt;commented out&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;That same day, Alex stated in a Hacker News comment:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Work on x64 generation started back in August [...] I haven't touched it in a while, and it simply doesn't compile at the moment.&lt;sup id="fnref:15"&gt;&lt;a class="footnote-ref" href="#fn:15"&gt;15&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;NB: Seeing as this comment was made in July 2019, "August" might be a mistake,
unless he meant August 2018 or similar.&lt;/p&gt;
&lt;p&gt;As with many other features, "direct machine code generation" gained a "WIP" flag soon after the open-source release.&lt;sup id="fnref2:8"&gt;&lt;a class="footnote-ref" href="#fn:8"&gt;8&lt;/a&gt;&lt;/sup&gt;
Once again, I did not bother to go through the entire Git history.
However, it seems that the native x64 backend in some state
first appeared in a commit made on Nov 22, 2019&lt;sup id="fnref:16"&gt;&lt;a class="footnote-ref" href="#fn:16"&gt;16&lt;/a&gt;&lt;/sup&gt;,
and the feature is mentioned in the release notes for version 0.1.23&lt;sup id="fnref:17"&gt;&lt;a class="footnote-ref" href="#fn:17"&gt;17&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Still to this day, it does not seem that the native backend is in a functional state.
For example, it fails as soon as one tries to declare an array:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;v&lt;span class="w"&gt; &lt;/span&gt;version
&lt;span class="go"&gt;V 0.4.6 4a7c70c&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;hello.v
&lt;span class="go"&gt;fn main() {&lt;/span&gt;
&lt;span class="go"&gt;    foo := [1, 2, 3]&lt;/span&gt;
&lt;span class="go"&gt;    println(foo)&lt;/span&gt;
&lt;span class="go"&gt;}&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;v&lt;span class="w"&gt; &lt;/span&gt;-b&lt;span class="w"&gt; &lt;/span&gt;native&lt;span class="w"&gt; &lt;/span&gt;hello.v
&lt;span class="go"&gt;/home/justinas/vlang-box/compiler/vlib/builtin/builtin.c.v:358:1: warning: globals are not supported yet&lt;/span&gt;
&lt;span class="go"&gt;  356 | }&lt;/span&gt;
&lt;span class="go"&gt;  357 |&lt;/span&gt;
&lt;span class="go"&gt;  358 | __global total_m = i64(0)&lt;/span&gt;
&lt;span class="go"&gt;      | ~~~~~~~~~~~~~~~~~~~~~~~~~&lt;/span&gt;
&lt;span class="go"&gt;  359 | // malloc dynamically allocates a `n` bytes block of memory on the heap.&lt;/span&gt;
&lt;span class="go"&gt;  360 | // malloc returns a `byteptr` pointing to the memory address of the allocated space.&lt;/span&gt;
&lt;span class="go"&gt;/home/justinas/vlang-box/compiler/vlib/builtin/builtin.c.v:718:1: warning: globals are not supported yet&lt;/span&gt;
&lt;span class="go"&gt;  716 |&lt;/span&gt;
&lt;span class="go"&gt;  717 | @[markused]&lt;/span&gt;
&lt;span class="go"&gt;  718 | __global g_main_argc = int(0)&lt;/span&gt;
&lt;span class="go"&gt;      | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~&lt;/span&gt;
&lt;span class="go"&gt;  719 |&lt;/span&gt;
&lt;span class="go"&gt;  720 | @[markused]&lt;/span&gt;
&lt;span class="go"&gt;/home/justinas/vlang-box/compiler/vlib/builtin/builtin.c.v:721:1: warning: globals are not supported yet&lt;/span&gt;
&lt;span class="go"&gt;  719 |&lt;/span&gt;
&lt;span class="go"&gt;  720 | @[markused]&lt;/span&gt;
&lt;span class="go"&gt;  721 | __global g_main_argv = unsafe { nil }&lt;/span&gt;
&lt;span class="go"&gt;      | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~&lt;/span&gt;
&lt;span class="go"&gt;  722 |&lt;/span&gt;
&lt;span class="go"&gt;  723 | @[if vplayground ?]&lt;/span&gt;
&lt;span class="go"&gt;/home/justinas/vlang-box/compiler/vlib/builtin/builtin.v:25:1: warning: globals are not supported yet&lt;/span&gt;
&lt;span class="go"&gt;   23 |&lt;/span&gt;
&lt;span class="go"&gt;   24 | // will be filled in cgen&lt;/span&gt;
&lt;span class="go"&gt;   25 | __global as_cast_type_indexes []VCastTypeIndexName&lt;/span&gt;
&lt;span class="go"&gt;      | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~&lt;/span&gt;
&lt;span class="go"&gt;   26 |&lt;/span&gt;
&lt;span class="go"&gt;   27 | fn __as_cast(obj voidptr, obj_type int, expected_type int) voidptr {&lt;/span&gt;
&lt;span class="go"&gt;native error: unknown variable `foo`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Or a map:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;map.v
&lt;span class="go"&gt;fn main() {&lt;/span&gt;
&lt;span class="go"&gt;    mut a := map[string]int{}&lt;/span&gt;
&lt;span class="go"&gt;    a[&amp;quot;foo&amp;quot;] = 42&lt;/span&gt;
&lt;span class="go"&gt;    println(a)&lt;/span&gt;
&lt;span class="go"&gt;}&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;v&lt;span class="w"&gt; &lt;/span&gt;-b&lt;span class="w"&gt; &lt;/span&gt;native&lt;span class="w"&gt; &lt;/span&gt;map.v&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;tail&lt;span class="w"&gt; &lt;/span&gt;-n&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;
&lt;span class="go"&gt;native error: expr: unhandled node type: v.ast.MapInit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Or a struct:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;struct.v
&lt;span class="go"&gt;struct Foo {&lt;/span&gt;
&lt;span class="go"&gt;    greeting string&lt;/span&gt;
&lt;span class="go"&gt;}&lt;/span&gt;

&lt;span class="go"&gt;fn main() {&lt;/span&gt;
&lt;span class="go"&gt;    foo := Foo{greeting: &amp;quot;hello&amp;quot;}&lt;/span&gt;
&lt;span class="go"&gt;    println(foo)&lt;/span&gt;
&lt;span class="go"&gt;}&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;v&lt;span class="w"&gt; &lt;/span&gt;-b&lt;span class="w"&gt; &lt;/span&gt;native&lt;span class="w"&gt; &lt;/span&gt;struct.v&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;error&amp;quot;&lt;/span&gt;
&lt;span class="go"&gt;native error: unsupported type for mov_reg_to_var ast.TypeInfo(ast.Struct{&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You get the idea. "Compilation directly to machine code",
touted as the secret of V's fast build times in 2019,
may as well not exist even in 2024, let alone back then.
It does not seem like there is much effort to change this situation either:
the change log for the recent V 0.4.6 release
lists 27 merged pull requests in the "C backend" category,
whereas the only mention of the native backend is
"ci: update native backend ci matrix"&lt;sup id="fnref:41"&gt;&lt;a class="footnote-ref" href="#fn:41"&gt;41&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;h2 id="memory-unmanagement"&gt;Memory unmanagement&lt;/h2&gt;
&lt;p&gt;One of the main selling points of V from the very beginning was
"innovative memory management".&lt;/p&gt;
&lt;p&gt;For context, it is well known that all mainstream paradigms of memory management
have certain problems:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Garbage collection usually has a non-negligible performance cost at runtime.&lt;/li&gt;
&lt;li&gt;Manual memory management à la C's &lt;code&gt;malloc()&lt;/code&gt; and &lt;code&gt;free()&lt;/code&gt; is error prone,
  and in practice results in issues such as memory leaks, double frees,
  and use-after-free.&lt;/li&gt;
&lt;li&gt;The RAII + ownership + borrow checking model of Rust avoids the disadvantages of
  the two previously mentioned models, but comes with its own cognitive cost
  of having to explicitly encode information about lifetimes into the program
  when the compiler is not smart enough to figure it out automatically.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The memory management model of V
was envisioned to solve all of these problems at once:
there would be no garbage collector,
and you wouldn't need to manage memory manually either.
Instead, the compiler would take care of freeing memory for you ("like Rust"&lt;sup id="fnref:4"&gt;&lt;a class="footnote-ref" href="#fn:4"&gt;4&lt;/a&gt;&lt;/sup&gt;),
but without having to struggle with lifetime specifiers or anything of the sort.&lt;/p&gt;
&lt;h3 id="early-v"&gt;Early V&lt;/h3&gt;
&lt;p&gt;In early 2019, V's website stated:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Is there garbage collection?&lt;/p&gt;
&lt;p&gt;No. V's memory management is similar to Rust but much easier to use. More information about it will be posted in the near future.&lt;sup id="fnref3:3"&gt;&lt;a class="footnote-ref" href="#fn:3"&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;About a month later, this section was expanded:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Is there garbage collection?&lt;/p&gt;
&lt;p&gt;No. V manages memory at compilation time (like Rust). Right now only basic cases are handled. For others, manual memory management is required for now. The right approach to solve this will be figured out in the near future.&lt;sup id="fnref3:4"&gt;&lt;a class="footnote-ref" href="#fn:4"&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;After V's initial release, the docs were updated to describe the unimpressive status quo:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;There's no garbage collection or reference counting. V cleans up what it can during compilation. For example:&lt;/p&gt;
&lt;p&gt;[...]&lt;/p&gt;
&lt;p&gt;The strings [...] are cleaned up when the function exits. &lt;/p&gt;
&lt;p&gt;[...]&lt;/p&gt;
&lt;p&gt;For more complex cases manual memory management is required. This will be fixed soon.&lt;/p&gt;
&lt;p&gt;V will detect memory leaks at runtime and report them. To clean up, for example, an array, use the &lt;code&gt;free()&lt;/code&gt; method[.]&lt;sup id="fnref:19"&gt;&lt;a class="footnote-ref" href="#fn:19"&gt;19&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I did not go and check whether V 0.0.12 lived up to these promises as documented,
because I have no clue how to correctly compile early versions of V.
I was, however, able to pull V 0.1.21 (released Sep 30th, 2019) from nixpkgs,
and compile a version of the example in the above documentation
(after applying some syntax fixes).
Valgrind is not happy with it.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;v&lt;span class="w"&gt; &lt;/span&gt;version&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# NB: version in nixpkgs is tagged 0.1.21, V self-identifies as 0.1.20.&lt;/span&gt;
&lt;span class="go"&gt;V 0.1.20 5ac62bb&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;autofree_initial.v
&lt;span class="go"&gt;import strings&lt;/span&gt;

&lt;span class="go"&gt;fn draw_text(s string, x, y int) {&lt;/span&gt;
&lt;span class="go"&gt;    /* empty */&lt;/span&gt;
&lt;span class="go"&gt;}&lt;/span&gt;

&lt;span class="go"&gt;fn draw_scene() {&lt;/span&gt;
&lt;span class="go"&gt;    name1 := &amp;#39;Alice&amp;#39;&lt;/span&gt;
&lt;span class="go"&gt;    name2 := &amp;#39;Bob&amp;#39;&lt;/span&gt;
&lt;span class="go"&gt;    draw_text(&amp;#39;hello $name1&amp;#39;, 10, 10)&lt;/span&gt;
&lt;span class="go"&gt;    draw_text(&amp;#39;hello $name2&amp;#39;, 100, 10)&lt;/span&gt;
&lt;span class="go"&gt;    draw_text(strings.repeat(`X`, 10000), 10, 50)&lt;/span&gt;
&lt;span class="go"&gt;}&lt;/span&gt;

&lt;span class="go"&gt;fn main() {&lt;/span&gt;
&lt;span class="go"&gt;    for i := 0; i &amp;lt; 1000; i++ {&lt;/span&gt;
&lt;span class="go"&gt;        draw_scene()&lt;/span&gt;
&lt;span class="go"&gt;    }&lt;/span&gt;
&lt;span class="go"&gt;}&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;valgrind&lt;span class="w"&gt; &lt;/span&gt;./autofree_initial&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;definitely lost&amp;quot;&lt;/span&gt;
&lt;span class="go"&gt;==1107111==    definitely lost: 10,024,000 bytes in 4,000 blocks&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Seeing how &lt;code&gt;draw_scene&lt;/code&gt; allocates roughly 10&lt;sup&gt;4&lt;/sup&gt; bytes,
and it is called 10&lt;sup&gt;3&lt;/sup&gt; times,
Valgrind reporting about 10&lt;sup&gt;7&lt;/sup&gt; bytes is an indication
that every single string allocated is leaked.
In the intermediate C code (generated via &lt;code&gt;v -o autofree_initial.c autofree_initial.v&lt;/code&gt;)
it is evident that &lt;a href="https://gist.github.com/justinas/6b6192a187738a30dd77a08ff1ae44fe#file-autofree_initial-c-L3948-L3960"&gt;&lt;code&gt;draw_scene&lt;/code&gt;&lt;/a&gt; does not contain any calls to &lt;code&gt;free()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;At around the same time, V decided to aim for an even stronger guarantee:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;(Work in progress) [...] If your V program compiles, it's guaranteed that it's going to be leak free.&lt;sup id="fnref:63"&gt;&lt;a class="footnote-ref" href="#fn:63"&gt;63&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Even Rust, despite having compile-time memory management,
does not promise complete freedom from memory leaks,
and in its documentation demonstrates a scenario in which memory leaks happen.&lt;sup id="fnref:64"&gt;&lt;a class="footnote-ref" href="#fn:64"&gt;64&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;h3 id="v-02-and-the-zero-leaks-demo"&gt;V 0.2 and the "zero leaks" demo&lt;/h3&gt;
&lt;p&gt;It's not a surprise that V pre-0.2 leaked so much memory,
because despite the claims in documentation,
"autofree" seemingly did not exist at all back then.
It was finally officially introduced, gated behind an &lt;code&gt;-autofree&lt;/code&gt; flag,
in V 0.2 half a year later.&lt;sup id="fnref:20"&gt;&lt;a class="footnote-ref" href="#fn:20"&gt;20&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;As an addition, that same day Alex released a video that supposedly
demonstrates how autofree prevents leaks&lt;sup id="fnref:21"&gt;&lt;a class="footnote-ref" href="#fn:21"&gt;21&lt;/a&gt;&lt;/sup&gt;.
All the demo shows is that the Ved editor,
after opening it and scrolling through a large text file once,
caps at a certain, lower amount of memory used
when compiled with &lt;code&gt;-autofree&lt;/code&gt; compared to the same program compiled without autofree
(i.e. using the pre-0.2 behavior of "YOLO leak everything").
In no way does it prove (as Alex would later state it does&lt;sup id="fnref:23"&gt;&lt;a class="footnote-ref" href="#fn:23"&gt;23&lt;/a&gt;&lt;/sup&gt;)
that the program has "zero leaks".
For that, at the very least, I would expect the compiled executable to be analysed via Valgrind.&lt;/p&gt;
&lt;p&gt;I will add that a video like this is may be a great tool to hype up your creation,
but a terrible way to actually prove your feature works,
since there are multiple ways in which such demo
could be "enhanced" to misrepresent the actual situation.
The only proof accepted by the wider community
should be instructions that allow one to independently reproduce the results.&lt;/p&gt;
&lt;p&gt;But such instructions were not made available, so let's try our best to reproduce
by getting V 0.2 and the version of Ved that was available at that time:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;wget&lt;span class="w"&gt; &lt;/span&gt;https://github.com/vlang/v/releases/download/0.2/v_linux.zip
&lt;span class="gp"&gt;$ &lt;/span&gt;unzip&lt;span class="w"&gt; &lt;/span&gt;v_linux.zip
&lt;span class="gp"&gt;$ &lt;/span&gt;mv&lt;span class="w"&gt; &lt;/span&gt;v&lt;span class="w"&gt; &lt;/span&gt;v0.2
&lt;span class="gp"&gt;$ &lt;/span&gt;./v0.2/v&lt;span class="w"&gt; &lt;/span&gt;version
&lt;span class="go"&gt;V 0.2 e4f94b6&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;clone&lt;span class="w"&gt; &lt;/span&gt;https://github.com/vlang/ved
&lt;span class="gp"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ved
&lt;span class="gp"&gt;$ &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;checkout&lt;span class="w"&gt; &lt;/span&gt;afa14852b78df5234072a3b321e2d1ecb611e120&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;# last Ved commit before V 0.2 release&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;wget&lt;span class="w"&gt; &lt;/span&gt;https://raw.githubusercontent.com/azadkuh/sqlite-amalgamation/master/sqlite3.c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# get an 8MB file to test with&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To test, I will compile Ved, then run it under Valgrind. Once Ved starts,
I'll hold the "Page Down" key on my keyboard to scroll to the end of the file,
and then promptly close the application so that Valgrind reports the results.&lt;/p&gt;
&lt;p&gt;Let's try without any flags first:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;../v0.2/v&lt;span class="w"&gt; &lt;/span&gt;.
&lt;span class="go"&gt;Compilation with tcc failed. Retrying with cc ...&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;valgrind&lt;span class="w"&gt; &lt;/span&gt;./ved&lt;span class="w"&gt; &lt;/span&gt;./sqlite3.c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;definitely lost&amp;quot;&lt;/span&gt;
&lt;span class="go"&gt;==397075==    definitely lost: 23,386,605 bytes in 3,350,781 blocks&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Without autofree, Ved leaks 23 megabytes. What about with autofree?&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;../v0.2/v&lt;span class="w"&gt; &lt;/span&gt;-autofree&lt;span class="w"&gt; &lt;/span&gt;.
&lt;span class="go"&gt;Compilation with tcc failed. Retrying with cc ...&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;valgrind&lt;span class="w"&gt; &lt;/span&gt;./ved&lt;span class="w"&gt; &lt;/span&gt;./sqlite3.c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;definitely lost&amp;quot;&lt;/span&gt;
&lt;span class="go"&gt;==398821==    definitely lost: 1,584,084 bytes in 1,573,227 blocks&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That's much better, Ved only leaks 1.5 megabytes.
However, that is not the same as "[a]ll objects are freed during compilation"
as the V homepage still states today.&lt;sup id="fnref:24"&gt;&lt;a class="footnote-ref" href="#fn:24"&gt;24&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;The V 0.2 release notes&lt;sup id="fnref2:20"&gt;&lt;a class="footnote-ref" href="#fn:20"&gt;20&lt;/a&gt;&lt;/sup&gt; also promised that autofree would be
"enabled by default in 0.3", presumably because it was expected to become good enough by that point.
That, of course, did not happen. Instead, before the V 0.2.4 release,
garbage collection based on Boehm GC was added&lt;sup id="fnref:22"&gt;&lt;a class="footnote-ref" href="#fn:22"&gt;22&lt;/a&gt;&lt;/sup&gt;,
and remains the default memory management option to this day.
In a GitHub discussion about autofree, Alex explains the reasons behind this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;When I started working on V, I was very anti-GC, expecting them to be slow and use a lot more RAM. I integrated a GC just for a test, and was surprised at how well it worked with V [...]&lt;/p&gt;
&lt;p&gt;What started as a test and a temporary way to allow developers to write leak free programs, became the stable and well working default option. &lt;sup id="fnref4:23"&gt;&lt;a class="footnote-ref" href="#fn:23"&gt;23&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I'll give it to him, that is fair reasoning: GC performs "well enough",
and for now, does a better job than autofree could.&lt;/p&gt;
&lt;h3 id="status-quo"&gt;Status quo&lt;/h3&gt;
&lt;p&gt;What bothers me the most is how no solid &lt;em&gt;principle&lt;/em&gt; behind autofree
has ever been explained (at least to my knowledge).
V's homepage simply states:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[T]he compiler inserts necessary free calls automatically during compilation.&lt;sup id="fnref8:24"&gt;&lt;a class="footnote-ref" href="#fn:24"&gt;24&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This simplistic statement sounds like a thought that any young programmer
might have when they encounter manual memory management for the first time:
"computers are good at automating stuff,
so why can't the compiler insert calls to &lt;code&gt;free()&lt;/code&gt; for me?".
I don't know enough about PL theory to confidently state
whether that is possible in the general case,
but people smarter than me seem to think it is not&lt;sup id="fnref:72"&gt;&lt;a class="footnote-ref" href="#fn:72"&gt;72&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;When asked about how autofree will function,
V's creator sometimes draws parallels to languages
such as Rust&lt;sup id="fnref:3"&gt;&lt;a class="footnote-ref" href="#fn:3"&gt;3&lt;/a&gt;&lt;/sup&gt; and Lobster&lt;sup id="fnref:25"&gt;&lt;a class="footnote-ref" href="#fn:25"&gt;25&lt;/a&gt;&lt;/sup&gt;, the latter of which I know little about.
There are no explanations on how the ideas from these languages
would be implemented, nor how V would avoid limitations of their memory management models.&lt;/p&gt;
&lt;p&gt;The GitHub discussion&lt;sup id="fnref2:23"&gt;&lt;a class="footnote-ref" href="#fn:23"&gt;23&lt;/a&gt;&lt;/sup&gt; about autofree only gives a couple of notes
about techniques that enable autofree to function.
One technique mentioned is simple
&lt;a href="https://en.wikipedia.org/wiki/Escape_analysis"&gt;escape analysis&lt;/a&gt;:
heap-allocated types that do not leave the function they were created in
are said to be deallocated at the end of the scope.&lt;/p&gt;
&lt;p&gt;Bizarrely, the example that is supposed to demonstrate
that autofree handles this case, fails:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;v&lt;span class="w"&gt; &lt;/span&gt;version
&lt;span class="go"&gt;V 0.4.6 4a7c70c&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;autofree.v
&lt;span class="go"&gt;struct Foo {&lt;/span&gt;
&lt;span class="go"&gt;    x int&lt;/span&gt;
&lt;span class="go"&gt;}&lt;/span&gt;

&lt;span class="go"&gt;fn foo() {&lt;/span&gt;
&lt;span class="go"&gt;    foo := &amp;amp;Foo{x: 3} // never escapes&lt;/span&gt;
&lt;span class="go"&gt;    println(foo)&lt;/span&gt;
&lt;span class="go"&gt;}&lt;/span&gt;

&lt;span class="go"&gt;fn main() {&lt;/span&gt;
&lt;span class="go"&gt;    foo()&lt;/span&gt;
&lt;span class="go"&gt;}&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;v&lt;span class="w"&gt; &lt;/span&gt;-autofree&lt;span class="w"&gt; &lt;/span&gt;autofree.v
&lt;span class="gp"&gt;$ &lt;/span&gt;valgrind&lt;span class="w"&gt; &lt;/span&gt;./autofree&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;definitely lost&amp;quot;&lt;/span&gt;
&lt;span class="go"&gt;==146888==    definitely lost: 20 bytes in 2 blocks&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Strings, on their own, are covered by escape analysis:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;string.v
&lt;span class="go"&gt;import strings&lt;/span&gt;

&lt;span class="go"&gt;fn produce_str() string {&lt;/span&gt;
&lt;span class="go"&gt;    foo := strings.repeat(`A`, 10)&lt;/span&gt;
&lt;span class="go"&gt;    return foo&lt;/span&gt;
&lt;span class="go"&gt;}&lt;/span&gt;

&lt;span class="go"&gt;fn main() {&lt;/span&gt;
&lt;span class="go"&gt;    println(produce_str())&lt;/span&gt;
&lt;span class="go"&gt;}&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;v&lt;span class="w"&gt; &lt;/span&gt;-autofree&lt;span class="w"&gt; &lt;/span&gt;string.v
&lt;span class="gp"&gt;$ &lt;/span&gt;valgrind&lt;span class="w"&gt; &lt;/span&gt;./string&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;no leaks&amp;quot;&lt;/span&gt;
&lt;span class="go"&gt;==597912== All heap blocks were freed -- no leaks are possible&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;But if you put them in a struct, they leak:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;struct.v
&lt;span class="go"&gt;import strings&lt;/span&gt;

&lt;span class="go"&gt;struct Foo {&lt;/span&gt;
&lt;span class="go"&gt;    x string&lt;/span&gt;
&lt;span class="go"&gt;}&lt;/span&gt;

&lt;span class="go"&gt;fn new_foo() Foo {&lt;/span&gt;
&lt;span class="go"&gt;    return Foo{x: strings.repeat(`A`, 10)}&lt;/span&gt;
&lt;span class="go"&gt;}&lt;/span&gt;

&lt;span class="go"&gt;fn main() {&lt;/span&gt;
&lt;span class="go"&gt;    println(new_foo())&lt;/span&gt;
&lt;span class="go"&gt;}&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;v&lt;span class="w"&gt; &lt;/span&gt;-autofree&lt;span class="w"&gt; &lt;/span&gt;struct.v
&lt;span class="gp"&gt;$ &lt;/span&gt;valgrind&lt;span class="w"&gt; &lt;/span&gt;./struct&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;definitely lost&amp;quot;&lt;/span&gt;
&lt;span class="go"&gt;==598343==    definitely lost: 11 bytes in 1 blocks&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Not even primitive types are safe: trying to take a pointer to an integer
automatically promotes this integer
to a heap allocation that is never deallocated&lt;sup id="fnref:45"&gt;&lt;a class="footnote-ref" href="#fn:45"&gt;45&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Escape analysis fails in the other direction too.
Trying to return a &lt;code&gt;&amp;amp;string&lt;/code&gt; from a function triggers a null pointer dereference,
because the string's inner buffer is freed and its address overwritten by &lt;code&gt;0&lt;/code&gt;
before returning:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;v&lt;span class="w"&gt; &lt;/span&gt;-autofree&lt;span class="w"&gt; &lt;/span&gt;dangling.v
&lt;span class="gp"&gt;$ &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;dangling.v
&lt;span class="go"&gt;import strings&lt;/span&gt;

&lt;span class="go"&gt;fn produce_str() &amp;amp;string {&lt;/span&gt;
&lt;span class="go"&gt;    str1 := strings.repeat(`A`, 10)&lt;/span&gt;
&lt;span class="go"&gt;    str2 := &amp;amp;str1&lt;/span&gt;
&lt;span class="go"&gt;    return str2&lt;/span&gt;
&lt;span class="go"&gt;}&lt;/span&gt;

&lt;span class="go"&gt;fn main() {&lt;/span&gt;
&lt;span class="go"&gt;    println(produce_str())&lt;/span&gt;
&lt;span class="go"&gt;}&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;v&lt;span class="w"&gt; &lt;/span&gt;-autofree&lt;span class="w"&gt; &lt;/span&gt;dangling.v
&lt;span class="gp"&gt;$ &lt;/span&gt;./dangling
&lt;span class="go"&gt;7f04dab88a80 : at ???: RUNTIME ERROR: invalid memory access&lt;/span&gt;
&lt;span class="go"&gt;/tmp/v_1000/dangling.01J1QTVGTZXJMVJVDE3CKG1WAQ.tmp.c:9761: by string_clone&lt;/span&gt;
&lt;span class="go"&gt;/tmp/v_1000/dangling.01J1QTVGTZXJMVJVDE3CKG1WAQ.tmp.c:11231: by string_str&lt;/span&gt;
&lt;span class="go"&gt;/tmp/v_1000/dangling.01J1QTVGTZXJMVJVDE3CKG1WAQ.tmp.c:13086: by main__main&lt;/span&gt;
&lt;span class="go"&gt;/tmp/v_1000/dangling.01J1QTVGTZXJMVJVDE3CKG1WAQ.tmp.c:13131: by main&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If we remove the secondary function, V narrowly avoids a double free.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;double.v
&lt;span class="go"&gt;import strings&lt;/span&gt;

&lt;span class="go"&gt;fn main() {&lt;/span&gt;
&lt;span class="go"&gt;    str1 := strings.repeat(`A`, 10)&lt;/span&gt;
&lt;span class="go"&gt;    str2 := &amp;amp;str1&lt;/span&gt;
&lt;span class="go"&gt;    println(str2)&lt;/span&gt;
&lt;span class="go"&gt;}&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;v&lt;span class="w"&gt; &lt;/span&gt;-autofree&lt;span class="w"&gt; &lt;/span&gt;double.v
&lt;span class="gp"&gt;$ &lt;/span&gt;./double
&lt;span class="go"&gt;&amp;amp;AAAAAAAAAA&lt;/span&gt;
&lt;span class="go"&gt;double string.free() detected&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The "double free detected" log message in this case comes from
&lt;a href="https://gist.github.com/justinas/ae80aebfe399a9cfddfbdb15260d32e4#file-double-c-L11426-L11448"&gt;V itself&lt;/a&gt;,
not a sanitizer or the allocator.
V string type's &lt;code&gt;is_lit&lt;/code&gt; field acts as
something resembling Rust's drop flags&lt;sup id="fnref:44"&gt;&lt;a class="footnote-ref" href="#fn:44"&gt;44&lt;/a&gt;&lt;/sup&gt; here.&lt;/p&gt;
&lt;p&gt;Dangling pointers can also be produced using an array:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$ cat array.v
fn ref_from_array() &amp;amp;int {
    a := [1, 2, 3]
    return &amp;amp;a[0]
}

fn main() {
    println(ref_from_array())
}
$ v -autofree array.v
$ valgrind ./array |&amp;amp; grep -A 4 &amp;quot;Invalid read&amp;quot;
==594613== Invalid read of size 4
==594613==    at 0x634B7B: main__main (in /home/justinas/vlang-testcases/array)
==594613==    by 0x63515C: main (in /home/justinas/vlang-testcases/array)
==594613==  Address 0x4a750f0 is 0 bytes inside a block of size 12 free&amp;#39;d
==594613==    at 0x484988F: free (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The only other "technique" described&lt;sup id="fnref3:23"&gt;&lt;a class="footnote-ref" href="#fn:23"&gt;23&lt;/a&gt;&lt;/sup&gt;  is not worth discussing in detail.
It simply states that assigning a string variable to another one (&lt;code&gt;foo := bar&lt;/code&gt;)
copies the string instead of aliasing.
This is true, however not sufficient to avoid memory management issues
(as we've demonstrated by using string pointers).
Alex also adds that for arrays, bare by-value assignment is forbidden,
and the user is always asked to &lt;code&gt;clone()&lt;/code&gt; the array explicitly.
This is not true (anymore?), arrays are cloned implicitly, just like strings:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;array.v
&lt;span class="go"&gt;fn main() {&lt;/span&gt;
&lt;span class="go"&gt;    foo := [1, 2, 3]&lt;/span&gt;
&lt;span class="go"&gt;    bar := foo&lt;/span&gt;
&lt;span class="go"&gt;    println(bar)&lt;/span&gt;
&lt;span class="go"&gt;}&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;v&lt;span class="w"&gt; &lt;/span&gt;run&lt;span class="w"&gt; &lt;/span&gt;array.v
&lt;span class="go"&gt;[1, 2, 3]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To summarize, autofree in mid-2024:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Eagerly frees standalone strings and arrays
  at the end of the block and does not leak them,
  but this results in dangling pointers and null dereferences.&lt;/li&gt;
&lt;li&gt;Does not handle structs at all, and introducing a struct in the mix
  breaks the small amount of functionality that otherwise works for strings and arrays.&lt;/li&gt;
&lt;li&gt;Does not free primitive types that needlessly escape to the heap in the first place.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In 2019 it was stated that there is no garbage collection&lt;sup id="fnref2:3"&gt;&lt;a class="footnote-ref" href="#fn:3"&gt;3&lt;/a&gt;&lt;/sup&gt;
(implying V's "innovative memory management" eliminates the need for GC
&amp;mdash; it did not say "there is no GC, but we will add it soon and it will be the main technique").
Today, autofree is impotent, only handling a few individual patterns of allocation,
and often still getting them wrong.
This is an embarrassing state of affairs.
V is not a language with "innovative memory management",
it is a language using an off-the-shelf garbage collector by default,
with an "autofree" option that is not viable in any meaningful way.&lt;/p&gt;
&lt;p&gt;To be fair, autofree is at least described on the current website as
"still experimental and not production ready yet".
However, in the same paragraph, it says that, when used,
"[autofree] takes care of most objects (~90-100%)"&lt;sup id="fnref2:24"&gt;&lt;a class="footnote-ref" href="#fn:24"&gt;24&lt;/a&gt;&lt;/sup&gt;.
To my knowledge, Alex has never shared a methodology to measure this.&lt;/p&gt;
&lt;p&gt;I would test autofree using present-day Ved and the latest V compiler,
alas, it immediately crashes if compiled with autofree.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;
&lt;span class="go"&gt;/home/justinas/vlang-testcases/ved&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;rev-parse&lt;span class="w"&gt; &lt;/span&gt;HEAD
&lt;span class="go"&gt;91d395901829d3c23073ff7d4ae1b137f1a14742&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;v&lt;span class="w"&gt; &lt;/span&gt;version
&lt;span class="go"&gt;V 0.4.6 b6c7b46&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;v&lt;span class="w"&gt; &lt;/span&gt;-autofree&lt;span class="w"&gt; &lt;/span&gt;.
&lt;span class="gp"&gt;$ &lt;/span&gt;./ved
&lt;span class="go"&gt;size=gg.Size{&lt;/span&gt;
&lt;span class="go"&gt;    width: 2560&lt;/span&gt;
&lt;span class="go"&gt;    height: 1440&lt;/span&gt;
&lt;span class="go"&gt;}&lt;/span&gt;
&lt;span class="go"&gt;V panic: as cast: cannot cast `map[string]toml.ast.Value` to `[]toml.ast.Value`&lt;/span&gt;
&lt;span class="go"&gt;v hash: b6c7b46&lt;/span&gt;
&lt;span class="go"&gt;/tmp/v_1000/ved.01J1JK2CEB2HCB4CA18WYEWKQB.tmp.c:16660: at _v_panic: Backtrace&lt;/span&gt;
&lt;span class="go"&gt;/tmp/v_1000/ved.01J1JK2CEB2HCB4CA18WYEWKQB.tmp.c:17160: by __as_cast&lt;/span&gt;
&lt;span class="go"&gt;/tmp/v_1000/ved.01J1JK2CEB2HCB4CA18WYEWKQB.tmp.c:48683: by toml__Doc_value_&lt;/span&gt;
&lt;span class="go"&gt;/tmp/v_1000/ved.01J1JK2CEB2HCB4CA18WYEWKQB.tmp.c:48652: by toml__Doc_value&lt;/span&gt;
&lt;span class="go"&gt;/tmp/v_1000/ved.01J1JK2CEB2HCB4CA18WYEWKQB.tmp.c:49387: by main__Config_init_colors&lt;/span&gt;
&lt;span class="go"&gt;/tmp/v_1000/ved.01J1JK2CEB2HCB4CA18WYEWKQB.tmp.c:49359: by main__Config_reload_config&lt;/span&gt;
&lt;span class="go"&gt;/tmp/v_1000/ved.01J1JK2CEB2HCB4CA18WYEWKQB.tmp.c:51422: by main__main&lt;/span&gt;
&lt;span class="go"&gt;/tmp/v_1000/ved.01J1JK2CEB2HCB4CA18WYEWKQB.tmp.c:55727: by main&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Why enabling autofree makes TOML serialization crash remains an open question.&lt;/p&gt;
&lt;p&gt;V's website has since pivoted from advertising "innovative memory management"&lt;sup id="fnref:65"&gt;&lt;a class="footnote-ref" href="#fn:65"&gt;65&lt;/a&gt;&lt;/sup&gt;
to "flexible memory management"&lt;sup id="fnref3:24"&gt;&lt;a class="footnote-ref" href="#fn:24"&gt;24&lt;/a&gt;&lt;/sup&gt;, boasting 4 distinct ways of managing memory.
Another review of V, linked in &lt;a href="#recommended-reading"&gt;"recommended reading"&lt;/a&gt;
goes into more detail about why swapping between these models
is not at all as seamless as the docs suggest.&lt;/p&gt;
&lt;h2 id="redefining-terms"&gt;Redefining terms&lt;/h2&gt;
&lt;p&gt;More bizzareties lie in the smaller bullet points of V's feature list,
where V authors outline several more hefty goals
which are not achieved, and at times seemingly not even well understood by the team.&lt;/p&gt;
&lt;h3 id="undefined-behavior"&gt;Undefined behavior&lt;/h3&gt;
&lt;p&gt;V's current homepage proudly proclaims that the language allows "[n]o undefined behavior"&lt;sup id="fnref4:24"&gt;&lt;a class="footnote-ref" href="#fn:24"&gt;24&lt;/a&gt;&lt;/sup&gt;.
The claim even has a "new!" tag, indicating that this has recently been achieved,
as opposed to when this feature was marked "WIP" back in 2022&lt;sup id="fnref:30"&gt;&lt;a class="footnote-ref" href="#fn:30"&gt;30&lt;/a&gt;&lt;/sup&gt;
(although the "WIP" caveat remains in the README on GitHub&lt;sup id="fnref2:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt;).&lt;/p&gt;
&lt;p&gt;However, the claim of "no undefined behavior" is far from holding up.
In many cases, primitive V code is translated
1-to-1 to syntactically equivalent C code
with all the nasty implications of it.&lt;/p&gt;
&lt;p&gt;For example, V code that attempts to divide by zero is translated
to C code that attempts to divide by zero,
a well known case of undefined behavior in C&lt;sup id="fnref:31"&gt;&lt;a class="footnote-ref" href="#fn:31"&gt;31&lt;/a&gt;&lt;/sup&gt;.
An issue about this was created in V's issue tracker 3 years ago,
and then promptly closed by contributors claiming that
"the behavior is the same as Go"&lt;sup id="fnref:32"&gt;&lt;a class="footnote-ref" href="#fn:32"&gt;32&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Whether the behavior is "the same as Go" is irrelevant here,
since V's claim is that it produces no undefined behavior,
not that integer division works "exactly as in Go".
It is trivial to demonstrate that the behavior is, in fact,
not always the same as in Go:
in my comment on the issue, I gave an example of V
(or rather the C compiler that it delegates to)
producing a program that yields &lt;code&gt;1/0 = 0&lt;/code&gt;, which is already different from Go.
The behavior of &lt;code&gt;1/0 = 0&lt;/code&gt; would perhaps be an okay trade-off
&lt;em&gt;if&lt;/em&gt; it was defined by V and did not trigger undefined behavior in the intermediate C code
But it's not, and it does.&lt;/p&gt;
&lt;p&gt;The misunderstanding of what undefined behavior means
is not limited to external V contributors.
When this issue was brought up in a Hacker News thread,
Alex reiterated the obviously false claim that division works "just like in Go"&lt;sup id="fnref:33"&gt;&lt;a class="footnote-ref" href="#fn:33"&gt;33&lt;/a&gt;&lt;/sup&gt;.
The only way that I imagine one could argue that V produces no undefined behavior here
is by applying some mental gymnastics à la "division by zero in V is &lt;em&gt;defined&lt;/em&gt;
to produce undefined behavior in the intermediate C code".&lt;/p&gt;
&lt;p&gt;I get it, undefined behavior is not a straightforward concept to grasp.
I myself did not understand it well until I read some great articles&lt;sup id="fnref:34"&gt;&lt;a class="footnote-ref" href="#fn:34"&gt;34&lt;/a&gt;&lt;/sup&gt;&lt;sup id="fnref:73"&gt;&lt;a class="footnote-ref" href="#fn:73"&gt;73&lt;/a&gt;&lt;/sup&gt;.
The problem is claiming that your language has a property X,
where X generally has an agreed upon meaning,
and then moving the goalposts of what constitutes X.&lt;/p&gt;
&lt;h3 id="static-binaries-that-are-not"&gt;Static binaries that are not&lt;/h3&gt;
&lt;p&gt;V's current homepage&lt;sup id="fnref5:24"&gt;&lt;a class="footnote-ref" href="#fn:24"&gt;24&lt;/a&gt;&lt;/sup&gt; claims that:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[By compiling V code y]ou get a single statically linked binary [...] without any dependencies.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;However, this is easily confirmed as false:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;hello.v
&lt;span class="go"&gt;fn main() {&lt;/span&gt;
&lt;span class="go"&gt;    println(&amp;quot;hello world&amp;quot;)&lt;/span&gt;
&lt;span class="go"&gt;}&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;v&lt;span class="w"&gt; &lt;/span&gt;hello.v
&lt;span class="gp"&gt;$ &lt;/span&gt;file&lt;span class="w"&gt; &lt;/span&gt;hello
&lt;span class="go"&gt;hello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, not stripped&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;ldd&lt;span class="w"&gt; &lt;/span&gt;hello
&lt;span class="go"&gt;        linux-vdso.so.1 (0x00007ffe0bdb1000)&lt;/span&gt;
&lt;span class="go"&gt;        libc.so.6 =&amp;gt; /lib/x86_64-linux-gnu/libc.so.6 (0x00007f0c90200000)&lt;/span&gt;
&lt;span class="go"&gt;        /lib64/ld-linux-x86-64.so.2 (0x00007f0c905f5000)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;By default, V produces a binary that is both dynamically linked
and relies on the C standard library.&lt;/p&gt;
&lt;p&gt;I don't have a bone to pick with the decision to use libc.
As Alex rightly points out, for some OSes, libc is the only stable system API&lt;sup id="fnref:35"&gt;&lt;a class="footnote-ref" href="#fn:35"&gt;35&lt;/a&gt;&lt;/sup&gt;.
I do have a small issue with saying "libc is not really a dependency",
because a dependency is a dependency.&lt;/p&gt;
&lt;p&gt;But my main qualm with the claim is that "static binary" has a defined meaning,
and V does not output static binaries by default.
In fact, it is hard to find any documentation on
how to produce static binaries in V at all.
In a GitHub discussion thread, Alex suggests using &lt;code&gt;musl-gcc&lt;/code&gt; for this&lt;sup id="fnref2:35"&gt;&lt;a class="footnote-ref" href="#fn:35"&gt;35&lt;/a&gt;&lt;/sup&gt;.
Let's ignore the fact that &lt;code&gt;musl-gcc&lt;/code&gt; is an external tool
which one must acquire separately, and try the suggestion:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;apt&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;musl-tools
&lt;span class="go"&gt;&amp;lt;...&amp;gt;&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;v&lt;span class="w"&gt; &lt;/span&gt;-cc&lt;span class="w"&gt; &lt;/span&gt;musl-gcc&lt;span class="w"&gt; &lt;/span&gt;hello.v
&lt;span class="go"&gt;==================&lt;/span&gt;
&lt;span class="go"&gt;/usr/bin/ld: pthread_start.c:(.text+0xa9): undefined reference to `__pthread_unregister_cancel&amp;#39;&lt;/span&gt;
&lt;span class="go"&gt;collect2: error: ld returned 1 exit status&lt;/span&gt;
&lt;span class="go"&gt;...&lt;/span&gt;
&lt;span class="go"&gt;==================&lt;/span&gt;
&lt;span class="gp gp-VirtualEnv"&gt;(Use `v -cg` to print the entire error message)&lt;/span&gt;

&lt;span class="go"&gt;builder error:&lt;/span&gt;
&lt;span class="go"&gt;==================&lt;/span&gt;
&lt;span class="go"&gt;C error found. It should never happen, when compiling pure V code.&lt;/span&gt;
&lt;span class="go"&gt;This is a V compiler bug, please report it using `v bug file.v`,&lt;/span&gt;
&lt;span class="go"&gt;or goto https://github.com/vlang/v/issues/new/choose .&lt;/span&gt;
&lt;span class="go"&gt;You can also use #help on Discord: https://discord.gg/vlang .&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It does not work.&lt;/p&gt;
&lt;p&gt;StackOverflow points me to the &lt;code&gt;-freestanding&lt;/code&gt; flag&lt;sup id="fnref:36"&gt;&lt;a class="footnote-ref" href="#fn:36"&gt;36&lt;/a&gt;&lt;/sup&gt;.
Let's try that out:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;array.v
&lt;span class="go"&gt;fn main() {&lt;/span&gt;
&lt;span class="go"&gt;    mut foo := [1, 2, 3]&lt;/span&gt;
&lt;span class="go"&gt;    foo.sort()&lt;/span&gt;
&lt;span class="go"&gt;    println(foo)&lt;/span&gt;
&lt;span class="go"&gt;}&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;v&lt;span class="w"&gt; &lt;/span&gt;-freestanding&lt;span class="w"&gt; &lt;/span&gt;array.v
&lt;span class="gp"&gt;$ &lt;/span&gt;file&lt;span class="w"&gt; &lt;/span&gt;./array
&lt;span class="go"&gt;./array: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, BuildID[sha1]=19986c1fa887f421581deb1982106b06a5a33ee6, not stripped&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;./array
&lt;span class="go"&gt;V panicsort does not work with -freestanding&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;-freestanding&lt;/code&gt; flag does make V produce a static binary,
but it also has the effect of not linking to libc at all.
Combined with the fact that V implements core functionality like sorting an array
by delegating to C standard library functions&lt;sup id="fnref:37"&gt;&lt;a class="footnote-ref" href="#fn:37"&gt;37&lt;/a&gt;&lt;/sup&gt;,
this means that a "freestanding" V program can barely do anything non-trivial.&lt;/p&gt;
&lt;p&gt;Finally, after filing an issue on V's GitHub I was pointed by a kind stranger to
the (obvious in hindsight) solution of using &lt;code&gt;-cflags '-static'&lt;/code&gt;&lt;sup id="fnref:42"&gt;&lt;a class="footnote-ref" href="#fn:42"&gt;42&lt;/a&gt;&lt;/sup&gt;. That works:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;v&lt;span class="w"&gt; &lt;/span&gt;-cflags&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;-static&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;hello.v
&lt;span class="gp"&gt;$ &lt;/span&gt;file&lt;span class="w"&gt; &lt;/span&gt;hello
&lt;span class="go"&gt;hello: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, BuildID[sha1]=fa28c8ba332aa9a6f7b5e490e5b8442d6b840ee6, for GNU/Linux 3.2.0, not stripped&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Since all this does is request static linkage from the C compiler that V delegates to,
I am not sure if there is a way to attempt
static linking when using the native code generation backend.
But given the state of that backend as a whole, it is currently a pointless exercise.&lt;/p&gt;
&lt;p&gt;In short, I think if V promises static binaries,
it should either produce them by default,
or give an easy, documented way to switch to static linking
(e.g. a &lt;code&gt;-static&lt;/code&gt; flag in the &lt;code&gt;v&lt;/code&gt; command-line tool).&lt;/p&gt;
&lt;p&gt;Previously, Alex has stated that "statically linking glibc is not possible"&lt;sup id="fnref:43"&gt;&lt;a class="footnote-ref" href="#fn:43"&gt;43&lt;/a&gt;&lt;/sup&gt;,
which is not technically true as we've just shown
(although glibc is definitely not an &lt;em&gt;ideal&lt;/em&gt; candidate for static linking&lt;sup id="fnref:38"&gt;&lt;a class="footnote-ref" href="#fn:38"&gt;38&lt;/a&gt;&lt;/sup&gt;).
I am confused why V's homepage promises something
that Alex thinks is impossible to achieve.&lt;/p&gt;
&lt;h3 id="other-misnomers"&gt;Other misnomers&lt;/h3&gt;
&lt;p&gt;Among its other safety features, V claims:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;No null (allowed in unsafe code)&lt;sup id="fnref9:24"&gt;&lt;a class="footnote-ref" href="#fn:24"&gt;24&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;As we have now come to expect, this is not universally true,
but at least in this case, the detailed docs spell it out:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Zero-value references, or nil pointers, will NOT be supported in the future, for now data structures such as Linked Lists or Binary Trees that rely on reference fields that can use the value 0, understanding that it is unsafe, and that it can cause a panic.&lt;sup id="fnref:39"&gt;&lt;a class="footnote-ref" href="#fn:39"&gt;39&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Strangely, &lt;code&gt;nil&lt;/code&gt; requires &lt;code&gt;unsafe&lt;/code&gt;,
but the equivalent &lt;code&gt;0&lt;/code&gt; literal in a pointer context does not.
This suggests very primitive reasoning by the compiler:
an "evil" keyword is forbidden,
but completely equivalent code without the keyword is allowed.&lt;/p&gt;
&lt;p&gt;Option types have existed in V since version 0.3&lt;sup id="fnref2:11"&gt;&lt;a class="footnote-ref" href="#fn:11"&gt;11&lt;/a&gt;&lt;/sup&gt;
(before that, they were a weird Option/Result mix).
With that in mind, it is weird why it is still allowed
to have a &lt;code&gt;0&lt;/code&gt; valued pointer in safe code instead of forcing users to use &lt;code&gt;?&amp;amp;T&lt;/code&gt;
to achieve the goal of having an optional reference.
Perhaps it is because a bunch of places in the standard library use &lt;code&gt;0&lt;/code&gt; pointers
and nobody has fixed that yet?&lt;/p&gt;
&lt;p&gt;Coincidentally, it was also the version 0.3 change log that announced
"[n]ull can be used in unsafe only (for example, for C interop)"&lt;sup id="fnref3:11"&gt;&lt;a class="footnote-ref" href="#fn:11"&gt;11&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;I don't think it is honest to advertise "no null" on the front page,
and then immediately walk it back in the docs.
In addition, dereferencing a null pointer is undefined behavior in C,
yet again proving that "no undefined behavior" claims are unsubstantiated.&lt;/p&gt;
&lt;p&gt;V also previously claimed "pure functions by default"&lt;sup id="fnref2:29"&gt;&lt;a class="footnote-ref" href="#fn:29"&gt;29&lt;/a&gt;&lt;/sup&gt;,
and many people at the time pointed out that allowing I/O in functions
is usually a dealbreaker for considering functions "pure".&lt;/p&gt;
&lt;p&gt;Today, "purity" as a term is not used, but V's documentation makes the strange claim
that "[function] evaluation has no side effects (unless the function uses I/O)"&lt;sup id="fnref:40"&gt;&lt;a class="footnote-ref" href="#fn:40"&gt;40&lt;/a&gt;&lt;/sup&gt;.
I am entirely unsure why the authors decided to make this claim,
which sounds as empty as "your programs are guaranteed to be bug-free
as long as you do not introduce any bugs".
In my opinion, this section of the documentation would look a lot more solid
if it only contained the core, unambiguous claims:
global variables are not allowed by default,
and function arguments are immutable by default.&lt;/p&gt;
&lt;h2 id="casting-a-wide-net"&gt;Casting a wide net&lt;/h2&gt;
&lt;p&gt;Another thing I find strange about the V project
is just how much secondary ground it intends to cover,
despite the core language being in an unfinished state.
I have no problem with community projects
like &lt;a href="https://github.com/vlang/vinix/"&gt;Vinix&lt;/a&gt; &amp;mdash;
I think it is very cool to build a complex software project,
such as an operating system,
as a proof-of-concept that your creation is not a toy language.
What concerns me is bloat in the core &lt;code&gt;v&lt;/code&gt; project itself,
the current state of these secondary features,
and the impact it may have on the ETA of the eventual V 1.0 release.&lt;/p&gt;
&lt;h3 id="backends"&gt;Backends&lt;/h3&gt;
&lt;p&gt;For one, take V's several &lt;a href="https://en.wikipedia.org/wiki/Compiler#Back_end"&gt;backends&lt;/a&gt;.
We've already discussed how C code generation is V's main backend,
and the direct-to-machine code backend, once claimed to be the main one,
is in a state where all it can compile is essentially "hello world".&lt;/p&gt;
&lt;p&gt;That did not stop V from gaining additional backends.
A prominent one is the JavaScript backend, which comes in four flavours:&lt;sup id="fnref:26"&gt;&lt;a class="footnote-ref" href="#fn:26"&gt;26&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;    * `js`                - V outputs JS source code which can be passed to NodeJS to be ran.
    * `js_browser`        - V outputs JS source code ready for the browser.
    * `js_node`           - V outputs JS source code to run with nodejs.
    * `js_freestanding`   - V outputs JS source code with no hard runtime dependency.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The list is majorly confusing, because from the descriptions it is unclear
how &lt;code&gt;js&lt;/code&gt; and &lt;code&gt;js_node&lt;/code&gt; different.
It is also unclear what "no hard runtime dependency" means.
Perhaps it is supposed to only generate code that fits some ECMAScript standard,
and does not assume any browser-ish or Node.js-ish constructs to be present?&lt;/p&gt;
&lt;p&gt;Either way, trying to figure out the supposed differences between these backends
is moot, since all four produce the same code
that hard-depends on a Node.js-like environment.&lt;sup id="fnref:27"&gt;&lt;a class="footnote-ref" href="#fn:27"&gt;27&lt;/a&gt;&lt;/sup&gt;
That's right, using &lt;code&gt;v -b js_browser&lt;/code&gt;
&lt;em&gt;does not&lt;/em&gt; produce JS code that can run in a browser.
The generation of code for Node.js works to some degree,
but ends up producing invalid JavaScript syntax when trying to do very simple things
such as splitting a string into characters.&lt;sup id="fnref:28"&gt;&lt;a class="footnote-ref" href="#fn:28"&gt;28&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;But I'm not worried about syntax. What I think is hard
in transpiling something like V into something like JavaScript is &lt;em&gt;semantics&lt;/em&gt;.
For example, V utilizes a &lt;em&gt;traditional&lt;/em&gt; synchronous model
with explicit threads and coroutines,
while JS usually runs on an implicit, single-threaded event loop.&lt;/p&gt;
&lt;p&gt;These two models of concurrency are not directly compatible.
So how does V solve this?
We can observe that threading in V works normally when using the C backend:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;threads.v
&lt;span class="go"&gt;import rand&lt;/span&gt;
&lt;span class="go"&gt;import rand.seed&lt;/span&gt;
&lt;span class="go"&gt;import rand.pcg32&lt;/span&gt;
&lt;span class="go"&gt;import time&lt;/span&gt;

&lt;span class="go"&gt;fn run (i int) {&lt;/span&gt;
&lt;span class="go"&gt;    println(&amp;quot;hello from thread ${i}&amp;quot;)&lt;/span&gt;
&lt;span class="go"&gt;    mut rng := &amp;amp;rand.PRNG(pcg32.PCG32RNG{})&lt;/span&gt;
&lt;span class="go"&gt;    rng.seed(seed.time_seed_array(pcg32.seed_len))&lt;/span&gt;
&lt;span class="go"&gt;    duration := rng.i64_in_range(100_000, 1_000_000) or { panic(err) }&lt;/span&gt;
&lt;span class="go"&gt;    time.sleep(duration)&lt;/span&gt;
&lt;span class="go"&gt;    println(&amp;quot;goodbye from thread ${i}&amp;quot;)&lt;/span&gt;
&lt;span class="go"&gt;}&lt;/span&gt;

&lt;span class="go"&gt;fn main() {&lt;/span&gt;
&lt;span class="go"&gt;    for i := 0; i &amp;lt; 10; i++ {&lt;/span&gt;
&lt;span class="go"&gt;        spawn run(i)&lt;/span&gt;
&lt;span class="go"&gt;    }&lt;/span&gt;

&lt;span class="go"&gt;    // I should build up an array of threads here and use threads.wait(),&lt;/span&gt;
&lt;span class="go"&gt;    // but that does not compile with the JS backend.&lt;/span&gt;
&lt;span class="go"&gt;    time.sleep(10_000_000)&lt;/span&gt;
&lt;span class="go"&gt;}&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;v&lt;span class="w"&gt; &lt;/span&gt;run&lt;span class="w"&gt; &lt;/span&gt;threads.v
&lt;span class="go"&gt;hello from thread 0&lt;/span&gt;
&lt;span class="go"&gt;hello from thread 1&lt;/span&gt;
&lt;span class="go"&gt;hello from thread 2&lt;/span&gt;
&lt;span class="go"&gt;goodbye from thread 1&lt;/span&gt;
&lt;span class="go"&gt;hello from thread 3&lt;/span&gt;
&lt;span class="go"&gt;hello from thread 4&lt;/span&gt;
&lt;span class="go"&gt;hello from thread 5&lt;/span&gt;
&lt;span class="go"&gt;hello from thread 6&lt;/span&gt;
&lt;span class="go"&gt;hello from thread 7&lt;/span&gt;
&lt;span class="go"&gt;hello from thread 8&lt;/span&gt;
&lt;span class="go"&gt;goodbye from thread 3&lt;/span&gt;
&lt;span class="go"&gt;hello from thread 9&lt;/span&gt;
&lt;span class="go"&gt;goodbye from thread 0&lt;/span&gt;
&lt;span class="go"&gt;goodbye from thread 6&lt;/span&gt;
&lt;span class="go"&gt;goodbye from thread 5&lt;/span&gt;
&lt;span class="go"&gt;goodbye from thread 9&lt;/span&gt;
&lt;span class="go"&gt;goodbye from thread 2&lt;/span&gt;
&lt;span class="go"&gt;goodbye from thread 4&lt;/span&gt;
&lt;span class="go"&gt;goodbye from thread 7&lt;/span&gt;
&lt;span class="go"&gt;goodbye from thread 8&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Threads interleave as expected.
But what happens if transpile the same code to JS and run it in Node?&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;v&lt;span class="w"&gt; &lt;/span&gt;-b&lt;span class="w"&gt; &lt;/span&gt;js&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;threads.js&lt;span class="w"&gt; &lt;/span&gt;threads.v
&lt;span class="gp"&gt;$ &lt;/span&gt;timeout&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;nodejs&lt;span class="w"&gt; &lt;/span&gt;threads.js
&lt;span class="go"&gt;hello from thread 0&lt;/span&gt;
&lt;span class="go"&gt;goodbye from thread 0&lt;/span&gt;
&lt;span class="go"&gt;hello from thread 1&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;timeout&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;nodejs&lt;span class="w"&gt; &lt;/span&gt;threads.js
&lt;span class="go"&gt;hello from thread 0&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;timeout&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;nodejs&lt;span class="w"&gt; &lt;/span&gt;threads.js
&lt;span class="go"&gt;hello from thread 0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It just... hangs? Non-deterministically?
There's plenty wrong with the generated code: threads are
&lt;a href="https://gist.github.com/justinas/9f3bb9cec262b08c8dfa2d52b269ab7c#file-threads-js-L12804-L12806"&gt;converted to Promises&lt;/a&gt;
and &lt;a href="https://gist.github.com/justinas/9f3bb9cec262b08c8dfa2d52b269ab7c#file-threads-js-L9199"&gt;&lt;code&gt;time.sleep&lt;/code&gt; is implemented as a busy-wait&lt;/a&gt;,
so the "threads" block the event loop and never interleave.
Despite all this, I am still unsure why the program "hangs"
and a random thread will seemingly block forever (or for a very long time).&lt;/p&gt;
&lt;p&gt;I'll leave it as an exercise to the reader to figure out what
V's &lt;code&gt;os.read_file&lt;/code&gt; translates to in JS. Hint: it's a no-no in asynchronous code.&lt;/p&gt;
&lt;p&gt;What about the Go backend?&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;hello.v
&lt;span class="go"&gt;fn main() {&lt;/span&gt;
&lt;span class="go"&gt;    println(&amp;quot;hello world&amp;quot;)&lt;/span&gt;
&lt;span class="go"&gt;}&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;v&lt;span class="w"&gt; &lt;/span&gt;-b&lt;span class="w"&gt; &lt;/span&gt;go&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;hello.go&lt;span class="w"&gt; &lt;/span&gt;hello.v
&lt;span class="go"&gt;using Go WIP backend...&lt;/span&gt;
&lt;span class="go"&gt;hello.v:2:5: error: unknown function: println&lt;/span&gt;
&lt;span class="go"&gt;    1 | fn main() {&lt;/span&gt;
&lt;span class="go"&gt;    2 |     println(&amp;quot;hello world&amp;quot;)&lt;/span&gt;
&lt;span class="go"&gt;      |     ~~~~~~~~~~~~~~~~~~~~~~&lt;/span&gt;
&lt;span class="go"&gt;    3 | }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Let the record show that neither Go nor JS backends are marked as "experimental"
in the &lt;code&gt;v build&lt;/code&gt; docs, although the &lt;code&gt;native&lt;/code&gt; and &lt;code&gt;wasm&lt;/code&gt; backends are&lt;sup id="fnref2:26"&gt;&lt;a class="footnote-ref" href="#fn:26"&gt;26&lt;/a&gt;&lt;/sup&gt;.
The JavaScript backend is also listed as a "key feature" alongside the C backend
in V's GitHub README, implying some degree of importance&lt;sup id="fnref3:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt;.
Again, V 0.4.6 release notes do not seem to mention JavaScript or Go backends at all,
suggesting that not much is being done to drive them forward.&lt;/p&gt;
&lt;p&gt;The value proposition of having so many different backends
is generally unclear to me.
Targeting JavaScript because it is the only language
that runs natively in the browser (apart from WebAssembly, which is still limited)
is somewhat understandable,
but compiling to another high-level language such as Go,
which V shares a lot of design goals with anyway,
seems like a giant timesink.
It also raises some of the same questions about semantics:
will both of V's threads and coroutines be backed by Go goroutines,
or just one of them? How will threads and coroutines differ when targeting Go?&lt;/p&gt;
&lt;p&gt;The fact that the compiler does not seem to have an intermediate representation,
and every backend has to generate code directly from the AST
also means there is a lot of the same work necessary for each backend.&lt;/p&gt;
&lt;h3 id="batteries-included-but-not-yet-charged"&gt;Batteries included (but not yet charged)&lt;/h3&gt;
&lt;p&gt;Drawing most of its inspiration from Go,
V intends to be a small, "simple" language,
but at the same time, have a rich standard library.
While the breadth of V's stdlib is impressive,
there is a lot of work to be done regarding its quality.
I only took a cursory look at V's standard library,
but it was enough to observe current incoherences.&lt;/p&gt;
&lt;p&gt;For one, &lt;code&gt;io.Reader&lt;/code&gt; and &lt;code&gt;io.Writer&lt;/code&gt; interfaces appeared in V 0.2&lt;sup id="fnref3:20"&gt;&lt;a class="footnote-ref" href="#fn:20"&gt;20&lt;/a&gt;&lt;/sup&gt;,
yet to this day the standard library only consumes these interfaces in a few places.
Instead, most of the modules require the user to fully buffer the data in memory.&lt;/p&gt;
&lt;p&gt;For example, the &lt;code&gt;net.http&lt;/code&gt; module&lt;sup id="fnref:47"&gt;&lt;a class="footnote-ref" href="#fn:47"&gt;47&lt;/a&gt;&lt;/sup&gt; only accepts
the request body as an in-memory string,
and returns the response body as a single in-memory buffer as well.
To stream the response body instead, one must either:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Manually set the &lt;code&gt;on_progress&lt;/code&gt; callback and the &lt;code&gt;stop_copying_limit&lt;/code&gt; property&lt;/li&gt;
&lt;li&gt;Use the strange &lt;code&gt;Downloader&lt;/code&gt; interface, which uses the above under the hood.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There does not seem to be an obvious way to stream the request body.&lt;/p&gt;
&lt;p&gt;This is a weirdly high-level and inefficient-by-default interface
for a language that claims to target, among others, systems engineers,
and aims to be "as fast as C"&lt;sup id="fnref6:24"&gt;&lt;a class="footnote-ref" href="#fn:24"&gt;24&lt;/a&gt;&lt;/sup&gt;.
The same pattern of "take a buffer with the entire input,
return a new allocation with the entire output"
is prevalent in other modules such as &lt;code&gt;compress&lt;/code&gt; and &lt;code&gt;encoding&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;context&lt;/code&gt; module, introduced before V 0.2.4&lt;sup id="fnref:48"&gt;&lt;a class="footnote-ref" href="#fn:48"&gt;48&lt;/a&gt;&lt;/sup&gt;
and modelled after Go's module of the same name,
intends to implement request cancellation and deadline functionality.
Yet, three years later, the only meaningful usage of the &lt;code&gt;context.Context&lt;/code&gt; type
outside of tests seems to be in the &lt;code&gt;vweb&lt;/code&gt; web framework,
where a &lt;code&gt;context.EmptyContext{}&lt;/code&gt; is used once&lt;sup id="fnref:49"&gt;&lt;a class="footnote-ref" href="#fn:49"&gt;49&lt;/a&gt;&lt;/sup&gt;.
Request cancellation is a problem that is generally applicable
to any subroutine that does I/O or any other kind of potentially long-running task,
not just V's web framework.&lt;/p&gt;
&lt;p&gt;There are a lot of smaller weirdnesses in V's stdlib,
but I have no intention to delve deep into code quality in this article.
All of these flaws seem fixable without changes to the core language itself.&lt;/p&gt;
&lt;p&gt;That said, I'd like to mention one more decision I feel dubious about.
Features like threads and channels being first-class citizens in the language
have the advantage of creating a very good developer experience
when the included tools are sufficient.
However, this also means that versions of these primitives created by third parties
can not take advantage of the syntax/compiler level support.&lt;/p&gt;
&lt;p&gt;This is also one of my gripes with Go, the language I used professionally
for the past few years:
while the built-in primitives are good enough in many cases,
once you hit their limitations and need to reach for a 3rd-party library,
you lose the fluent integration with the language.
You can't &lt;code&gt;go&lt;/code&gt; an alternative thread implementation,
nor can you &lt;code&gt;select&lt;/code&gt; and &lt;code&gt;&amp;lt;-&lt;/code&gt; from a third-party channel.
Before the introduction of generics in Go,
similar "second-class citizen" status applied
to other abstractions outside the standard library, such as data structures.&lt;/p&gt;
&lt;p&gt;Where V, in my opinion, takes this to the extreme,
is the introduction of language-level SQL syntax that supports its built-in ORM&lt;sup id="fnref:50"&gt;&lt;a class="footnote-ref" href="#fn:50"&gt;50&lt;/a&gt;&lt;/sup&gt;.
While SQL is still seen as the king in the database world,
it does feel strange that support for this specific technology is embedded
so deeply into the V toolchain itself.
Given the fact that V currently offers no way for users to
introduce similar language syntax extensions by themselves
(which can be done in some other languages, e.g. in Rust via macros),
this means that interacting with any non-SQL databases will feel massively less nice.&lt;/p&gt;
&lt;p&gt;At the very least, it seems possible for 3rd-party SQL database drivers to
utilize integration with the &lt;code&gt;sql&lt;/code&gt; keyword
by implementing the &lt;code&gt;orm.Connection&lt;/code&gt; interface,
although if the database uses a different dialect,
then the support for the dialect needs to either be upstreamed to the &lt;code&gt;orm&lt;/code&gt; module,
or the database backend needs to re-implement parts of the lower-level &lt;code&gt;orm&lt;/code&gt; logic.&lt;/p&gt;
&lt;h3 id="v-10-and-the-stability-guarantee"&gt;V 1.0 and the stability guarantee&lt;/h3&gt;
&lt;p&gt;The reason why V's extensive scope matters is the implications it has
for deliverability of a stable V 1.0 release. V's GitHub repo states:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The V core APIs (primarily the &lt;code&gt;os&lt;/code&gt; module) will also have minor changes until they are stabilized in V 1.0. Of course, the APIs will grow after that, but without breaking existing code.&lt;/p&gt;
&lt;p&gt;After the 1.0 release V is going to be in the "feature freeze" mode. That means no breaking changes in the language, only bug fixes and performance improvements. Similar to Go.&lt;/p&gt;
&lt;p&gt;Will there be V 2.0? Not within a decade after 1.0, perhaps not ever.&lt;sup id="fnref4:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is not too dissimilar to 1.0 stability guarantees
that languages like Go or Rust provide.
V's stability goals are not documented in as much detail, but at the very least
we can infer that the syntax of the language itself should not change after 1.0,
which seems like an obvious and achievable goal.&lt;/p&gt;
&lt;p&gt;Additionally, while V's standard library will continue to evolve,
V promises to not make breaking changes to it
(e.g. removing any public items or changing function signatures)
after the 1.0 release.
Given the current state of the stdlib,
this will require a huge undertaking of its own.
Because no detailed standards for idiomatic V code were set early-on, over time
the standard library accumulated modules with very different coding conventions.
Before V 1.0 can be released, someone, or a group of people, will need to
go through every single element of the ever-growing standard library and
ensure that these interfaces fit together well and do not hamper future evolution.&lt;/p&gt;
&lt;p&gt;Given how small the core V team is &amp;mdash;
a quick look at the GitHub stats indicates that only a few developers
have been consistently commiting code for the past couple of years
and at most a couple dozen are merging PRs &amp;mdash;
this responsibility will likely fall on Alex himself.&lt;/p&gt;
&lt;p&gt;V's roadmap for version 1.0 also mentions the goals to
make autofree production-ready and
implement full support for the C99 standard in C2V&lt;sup id="fnref:51"&gt;&lt;a class="footnote-ref" href="#fn:51"&gt;51&lt;/a&gt;&lt;/sup&gt;.
It does not say anything about additional backends,
such as direct x86-64 code generation or the JavaScript backend.
If it is intended for these to reach complete parity with the C backend,
such that users of V can switch between the 2 or 3 first-class backends seamlessly,
V 1.0 may take many more years, if not decades,
to complete at the current development pace
(or, frankly, at any development pace).&lt;/p&gt;
&lt;h2 id="the-author"&gt;The author&lt;/h2&gt;
&lt;p&gt;This will be the only section where I talk about Alexander,
the creator of V, as a person, or rather his online presence.
Once again, I'll remind the reader that it is not my intention to bully anyone,
and I'll try to only bring up Alex's behavior
as it is relevant to his public software projects.&lt;/p&gt;
&lt;h3 id="its-just-a-bug"&gt;"It's just a bug"&lt;/h3&gt;
&lt;p&gt;I am not the first to criticise V (and I might not be the last).
The criticism is not always taken in stride by Alex or the contributors.&lt;/p&gt;
&lt;p&gt;One common answer to commenters pointing out the deficiencies of V
is "it's just a bug, we will fix this / we have already fixed this since",
or pointing out that the language is at version 0.X,
and thus should obviously be seen as pre-production.&lt;/p&gt;
&lt;p&gt;I agree that bugs are normal in any software project.
However, there must be a line somewhere marking the difference between
"generally works, but has some bugs", and "generally does not work".
Otherwise, to invoke &lt;em&gt;reductio ad absurdum&lt;/em&gt; for one moment,
I could claim to have solved the halting problem by writing a program
that answers the halting question for one specific application,
and then stating that the fact of it not working for &lt;em&gt;any and every&lt;/em&gt; program
is "just a bug".&lt;/p&gt;
&lt;p&gt;I'd like to think that the sections above have pointed out several core areas in V
where the problems run deeper than "just having a few bugs here and there".
The lack of solid principles while aiming to surpass everything that has come before,
the almost complete lack of a plan on how to get there,
and at times the V team not fully understanding what they're promising
does not inspire confidence.&lt;/p&gt;
&lt;p&gt;There are other ways Alex deflects criticism,
such as stating that critical blog posts come from "V haters",
or that the critics are either creators of other similar programming languages,
or shills for these PLs, and thus have a vested interest in scrutinizing V unfairly.
To give Alex some credit here, I've seen one or two novelty accounts on Hacker News
dedicated solely to critical or outright mean comments regarding V,
and I don't think that's a very cool thing to do.
As for the second point, I'm aware that at least the creator of Odin
did criticize V before the initial release&lt;sup id="fnref:61"&gt;&lt;a class="footnote-ref" href="#fn:61"&gt;61&lt;/a&gt;&lt;/sup&gt;,
and I won't claim that all of his criticisms were completely valid
(although V's closed-source nature and a somewhat ambiguous feature list
back then did not make it easy to fully evaluate the language).&lt;/p&gt;
&lt;h3 id="things-change"&gt;"Things change"&lt;/h3&gt;
&lt;p&gt;As I've covered before, V's memory management claims have changed over time from
"at compile time, like Rust" to "mostly at compile time, falling back to RC"
to "mostly at compile time, falling back to tracing GC".&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;bheadmaster: The documentation I've quoted and posted a source to specifically says that all objects are freed either by 1) autofree or 2) reference counting.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;amedvednikov: You pointed to an old version of the documentation. RC was changed to tracing GC. Things can change in the design.&lt;sup id="fnref:67"&gt;&lt;a class="footnote-ref" href="#fn:67"&gt;67&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;My problem with this is that every time without fail new features,
whatever state of quality (or existence) they are in, are announced loudly,
but when these plans eventually hit a wall,
the deprioritization or material downgrades in these features
are but a footnote or a silent change to the homepage.&lt;/p&gt;
&lt;p&gt;At some point, we have to admit that V is having an identity crisis.
V was supposed to be "safe", but does not enforce data race safety,
ensure valid memory references, or prevent undefined behavior.
It was supposed to be "as fast as C",
but the creator does not consider 5% slowdown a meaningful difference,
using the strange argument that companies such as Facebook / Meta
must not care about such performance delta
[on the backend, where V would most likely be used],
because they ship heavy JavaScript to their users' browsers&lt;sup id="fnref:68"&gt;&lt;a class="footnote-ref" href="#fn:68"&gt;68&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;V is "compiled" and it could be argued that it is "simple",
so at least 2 out of its 4 defining qualifiers stand.
What &lt;em&gt;is&lt;/em&gt; V today, other than a much less mature &lt;em&gt;sparkling Go&lt;/em&gt;?&lt;/p&gt;
&lt;h3 id="a-broader-pattern"&gt;A broader pattern&lt;/h3&gt;
&lt;p&gt;Before V, there was Volt &amp;ndash; Alex's project to create
a "fast native desktop client for all major messaging services"&lt;sup id="fnref:52"&gt;&lt;a class="footnote-ref" href="#fn:52"&gt;52&lt;/a&gt;&lt;/sup&gt;.
Although the archive of Volt's website is only available starting from 2018,
it seems that in 2017, Volt already existed as Eul&lt;sup id="fnref:53"&gt;&lt;a class="footnote-ref" href="#fn:53"&gt;53&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Volt seems to have followed a similar "overpromise and underdeliver" path as V.
A snapshot of the site taken on June 15th, 2018&lt;sup id="fnref2:52"&gt;&lt;a class="footnote-ref" href="#fn:52"&gt;52&lt;/a&gt;&lt;/sup&gt;
contains the claim that the 1.0 release for Volt
is slated for June 15 (that very same day),
and the support for most chat platforms &amp;mdash;
everything from Telegram to Signal &amp;mdash;
is supposed to come in June (presumably 2018).&lt;/p&gt;
&lt;p&gt;This seemingly did not happen, as commenters on a
Hacker News thread in early 2019 point out&lt;sup id="fnref:54"&gt;&lt;a class="footnote-ref" href="#fn:54"&gt;54&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I want to like this, ever since it was called eul. But features are consistently pushed back which suggests that the dev doesnt have a great handle on what is going on, the availability of mac/linux versions seems consistently misleading, it’s not open source, and it uses icons of services not available (e.g. gmail) in a way that seems dishonest. idk.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;

&lt;blockquote&gt;
&lt;p&gt;More than a little disingenuous. While they advertise that the app supports a number of services, when you actually download the app and try it only Slack and Skype are available - the rest are "coming later in February"&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Volt's current website&lt;sup id="fnref:55"&gt;&lt;a class="footnote-ref" href="#fn:55"&gt;55&lt;/a&gt;&lt;/sup&gt; offers a download of version 0.96
for ARM-based Mac OS machines only (other platforms are to be supported "soon").
Icons for messaging services seem to indicate that only
Slack, Gmail, Twitter and Discord are supported,
with support for 9 more services yet to come.
Volt's GitHub repository seems to only be used as a deserted issue tracker
and downloads page, despite the 5 year old README stating that
"In 2021 [...] the app [will be] open-sourced"&lt;sup id="fnref:56"&gt;&lt;a class="footnote-ref" href="#fn:56"&gt;56&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Despite not taking the messaging world by storm, Volt led to creation of V.
Before V had a dedicated website, it had a section on volt.ws&lt;sup id="fnref:57"&gt;&lt;a class="footnote-ref" href="#fn:57"&gt;57&lt;/a&gt;&lt;/sup&gt;.
Many of the more impressive claims about V seem to have first been published 
on that page, including the C/C++ translator "translat[ing] your entire C/C++ codebase", generating x64 code directly, and automatic memory management ("similar to Rust, but [...] much easier")&lt;sup id="fnref:58"&gt;&lt;a class="footnote-ref" href="#fn:58"&gt;58&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;If I was any meaner, I would perhaps point and laugh
at the tutorial that was supposed to demonstrate
using V to develop a 3D shooter game,
but only shows code to animate a bouncing square
(à la the iconic DVD screensaver)&lt;sup id="fnref2:58"&gt;&lt;a class="footnote-ref" href="#fn:58"&gt;58&lt;/a&gt;&lt;/sup&gt;,
but at least that tutorial was clearly marked as an "unfinished draft".
It's a pity it was never completed, because I would gladly read an article like that,
especially targeting people otherwise not experienced in game development.&lt;/p&gt;
&lt;p&gt;Before Volt was Volt, back in 2017, there was Gitly, a minimal alternative
to the likes of GitHub and GitLab&lt;sup id="fnref:59"&gt;&lt;a class="footnote-ref" href="#fn:59"&gt;59&lt;/a&gt;&lt;/sup&gt;.
Gitly might have been Alex's first public project of this scale,
and it garnered some pretty positive feedback in the Hacker News thread.
The selling points seemed to be similar to ones Volt and V
would later tout: simple, fast, lightweight.&lt;/p&gt;
&lt;p&gt;However, that version of Gitly seems to have eventually been abandoned,
at least according to another Hacker News commenter:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I realized the other day that the V author is the same person that created gitly, which was a really nice looking git forge. I believe the author's stated plan was to open source it, but the website went offline after some time without an open source release ever happening. I hope the author follows through on this one, because both projects look(ed) pretty neat!&lt;sup id="fnref:60"&gt;&lt;a class="footnote-ref" href="#fn:60"&gt;60&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;To which Alex responded:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It will be back, open source, re-written in V[.]&lt;/p&gt;
&lt;p&gt;[...]&lt;/p&gt;
&lt;p&gt;I started developing Volt/V in the middle of developing gitly.&lt;/p&gt;
&lt;p&gt;That's my biggest drawback. I finish 90% of the project, and jump to a different thing.&lt;/p&gt;
&lt;p&gt;I've grown a lot since then, and I'm slowly wrapping up everything.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;To be fair, Gitly &lt;em&gt;was&lt;/em&gt; in fact rewritten in V,
and does exist as an alpha-state open-source project&lt;sup id="fnref:66"&gt;&lt;a class="footnote-ref" href="#fn:66"&gt;66&lt;/a&gt;&lt;/sup&gt;.
Nevertheless, the above comment from Alex sheds a light on
why his projects consistently fail to get to a production-ready state.&lt;/p&gt;
&lt;p&gt;Another commenter on Hacker News claims (I have not verified this independently):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I loved the idea [of V] [...] [b]ut it just didn't seem to go anywhere.&lt;/p&gt;
&lt;p&gt;[...]&lt;/p&gt;
&lt;p&gt;At one point I even searched in the Discord for messages by Alex that contained "this week", "this month" and "this year", also using "next" instead of "this". It came out to 50+ times that deadlines had been missed (closer to 80+ probably).&lt;sup id="fnref:69"&gt;&lt;a class="footnote-ref" href="#fn:69"&gt;69&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="he-just-like-me-fr"&gt;He just like me fr&lt;/h3&gt;
&lt;p&gt;I will not call Alex a fraud or a scammer as many have done before.
My most charitable interpretation is that Alex is just like many programmers,
including myself.
We think of a cool new idea, implement a prototype and it fills us with joy:
something that moments ago only existed in our imagination is now a functioning thing.
Both "constantly abandoning side projects for new ones" and
the inaccuracy of software development estimations are giant memes for a reason.&lt;/p&gt;
&lt;p&gt;The author of V is not wrong in his defense
that implementation details or even the direction
of a software project might change in the course of its development,
or that timeline might get adjusted.
My problem with that is, again, the lack of transparency
in how these changes are made.
It is the fact that Alex, to my knowledge, never answers criticisms on this basis
in a humble way, admitting that the initial goals were too lofty,
deadlines too aggressive, or that the Hacker News commenters
doubting that V could do all these things back in 2019 were partially right.&lt;/p&gt;
&lt;p&gt;"Failure" does not have to be a failure,
and V itself does not have to be the sole product of V's development.
Alex has time and time again promised to write blog articles
on various aspects of V's development.
Had he done that, instead of silently backpedalling on claims about V,
we could have had very interesting reads
reflecting on the challenges of creating a new programming language.
An article covering, say,
"how we tried to create autofree and why we're changing course",
would in my eyes be much more interesting
than the current broken version of autofree itself.
Not to mention that it would serve as
a much needed piece of communication to V's users and the broader community.&lt;/p&gt;
&lt;p&gt;There have also been claims of Alex unjustly banning people from the V community.&lt;sup id="fnref:70"&gt;&lt;a class="footnote-ref" href="#fn:70"&gt;70&lt;/a&gt;&lt;/sup&gt;&lt;sup id="fnref:71"&gt;&lt;a class="footnote-ref" href="#fn:71"&gt;71&lt;/a&gt;&lt;/sup&gt;
I can't say I'm particularly interested in looking into each of these cases
and evaluating whether the banhammer was deserved.
As for &lt;a href="https://github.com/issues?q=org%3Avlang+author%3Ajustinas"&gt;my contributions to the V issue tracker&lt;/a&gt;,
I'd like to think that any outside observer would recognize them
as made in good faith, and I hope to avoid the banhammer myself.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Edited on 2024-09-27&lt;/em&gt;: About 9 hours after publishing this article
and posting it on &lt;a href="https://reddit.com/r/programming"&gt;r/programming&lt;/a&gt;,
I was &lt;a href="https://social.treehouse.systems/@justinas/113202378818966269"&gt;"temporarily muted" from V's subreddit&lt;/a&gt;.
To my knowledge, I have never interacted in the subreddit,
nor was I planning on promoting this article in any community spaces of the V project.&lt;/p&gt;
&lt;h1 id="outro"&gt;Outro&lt;/h1&gt;
&lt;p&gt;This kind of article is unusual for me and I truly do not know how to end it.
Is V all that it claims it is? Certainly not.
Is V "unfixable"? Not necessarily, but it needs &lt;em&gt;so much&lt;/em&gt; to get "fixed".
Not just refocusing in terms of its goals, not just a lot of technical work,
but also a major change in the attitude of its creator.&lt;/p&gt;
&lt;h2 id="recommended-reading"&gt;Recommended reading&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://n-skvortsov-1997.github.io/reviews/"&gt;V Language Review (2023)&lt;/a&gt;
goes into more detail on several technical aspects of V,
notably the problems that arise when swapping between V's memory management modes,
and the flawed implementation of the newly-introduced coroutines.&lt;/p&gt;
&lt;h1 id="footnotes"&gt;Footnotes&lt;/h1&gt;
&lt;div class="footnote"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;&lt;a href="https://web.archive.org/web/20240620191916/github.com/vlang/v"&gt;Snapshot of V's GitHub repository as of 2024-06-20&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref2:1" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref3:1" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref4:1" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;&lt;a href="https://web.archive.org/web/20190225154211/https://vlang.io/"&gt;Snapshot of V's website as of 2019-02-22&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:2" title="Jump back to footnote 2 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref2:2" title="Jump back to footnote 2 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref3:2" title="Jump back to footnote 2 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:3"&gt;
&lt;p&gt;&lt;a href="https://web.archive.org/web/20190303184805/https://vlang.io/"&gt;Snapshot of V's website as of 2019-03-03&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:3" title="Jump back to footnote 3 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref2:3" title="Jump back to footnote 3 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref3:3" title="Jump back to footnote 3 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref4:3" title="Jump back to footnote 3 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:4"&gt;
&lt;p&gt;&lt;a href="https://web.archive.org/web/20190404175030/https://vlang.io/"&gt;Snapshot of V's website as of 2019-04-04&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:4" title="Jump back to footnote 4 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref2:4" title="Jump back to footnote 4 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref3:4" title="Jump back to footnote 4 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:5"&gt;
&lt;p&gt;&lt;a href="https://web.archive.org/web/20190506001436/https://vlang.io/"&gt;Snapshot of V's website as of 2019-05-06&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:5" title="Jump back to footnote 5 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:6"&gt;
&lt;p&gt;&lt;a href="https://news.ycombinator.com/item?id=19527569"&gt;Part of Hacker News thread about the V playground&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:6" title="Jump back to footnote 6 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:7"&gt;
&lt;p&gt;&lt;a href="https://web.archive.org/web/20190519042237/https://vlang.io/"&gt;Snapshot of V's website as of 2019-05-19&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:7" title="Jump back to footnote 7 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:8"&gt;
&lt;p&gt;&lt;a href="https://news.ycombinator.com/item?id=20250990"&gt;Hacker News: "The V Programming Language is open source"&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:8" title="Jump back to footnote 8 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref2:8" title="Jump back to footnote 8 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:9"&gt;
&lt;p&gt;&lt;a href="https://web.archive.org/web/20210101182927/https://twitter.com/v_language/status/1345074628176334849"&gt;Tweet from @v_language on 2021-01-01&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:9" title="Jump back to footnote 9 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:10"&gt;
&lt;p&gt;&lt;a href="https://web.archive.org/web/20240624140457/https://github.com/vlang/c2v/commit/7c7741904a4ac7d032aad8b56d8d5d2861f0cb84"&gt;C2V's initial commit on GitHub&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:10" title="Jump back to footnote 10 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:11"&gt;
&lt;p&gt;&lt;a href="https://web.archive.org/web/20220701054531/https://github.com/vlang/v/releases/tag/0.3"&gt;V 0.3 release on GitHub&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:11" title="Jump back to footnote 11 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref2:11" title="Jump back to footnote 11 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref3:11" title="Jump back to footnote 11 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:12"&gt;
&lt;p&gt;&lt;a href="https://github.com/vlang/c2v/blob/b0dc0fa684cb2f0a441695fa34611364428ddc1e/src/cpp.v#L260-L262"&gt;cpp.v in C2V repo&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:12" title="Jump back to footnote 12 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:13"&gt;
&lt;p&gt;&lt;a href="https://news.ycombinator.com/item?id=19527375"&gt;Part of Hacker News thread about the V playground&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:13" title="Jump back to footnote 13 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:14"&gt;
&lt;p&gt;&lt;a href="https://github.com/vlang/v/commit/d32e538073e55c603992b5b65ebc837b01c28576"&gt;V 0.0.12: initial open-source release&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:14" title="Jump back to footnote 14 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:15"&gt;
&lt;p&gt;&lt;a href="https://news.ycombinator.com/item?id=20252316"&gt;Alex's comment on a Hacker News thread about V's initial open-source release&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:15" title="Jump back to footnote 15 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:16"&gt;
&lt;p&gt;&lt;a href="https://github.com/vlang/v/commit/9712213f50e34e411490eac30284b7b35ccdc85f"&gt;A commit introducing x64 machine code generation in V&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:16" title="Jump back to footnote 16 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:17"&gt;
&lt;p&gt;&lt;a href="https://github.com/vlang/v/releases/tag/0.1.23"&gt;V 0.1.23 release on GitHub&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:17" title="Jump back to footnote 17 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:18"&gt;
&lt;p&gt;&lt;a href="https://github.com/vlang/v/blob/4a7c70c90949df7fb6c8c84eb7e86b725b4bf86e/ROADMAP.md#L59"&gt;V's ROADMAP.md as of 2024-03-04&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:18" title="Jump back to footnote 18 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:19"&gt;
&lt;p&gt;&lt;a href="https://web.archive.org/web/20190623015404/https://vlang.io/docs#memory"&gt;V's documentation on memory management as of 2019-06-23&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:19" title="Jump back to footnote 19 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:20"&gt;
&lt;p&gt;&lt;a href="https://github.com/vlang/v/discussions/7474"&gt;V 0.2 release&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:20" title="Jump back to footnote 20 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref2:20" title="Jump back to footnote 20 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref3:20" title="Jump back to footnote 20 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:21"&gt;
&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=gmB8ea8uLsM"&gt;Demo of Ved compiled with autofree&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:21" title="Jump back to footnote 21 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:22"&gt;
&lt;p&gt;&lt;a href="https://github.com/vlang/v/commit/8810af76df00943c5c8bef881a0116690fc6a57d"&gt;Commit adding Boehm GC to V&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:22" title="Jump back to footnote 22 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:23"&gt;
&lt;p&gt;&lt;a href="https://github.com/vlang/v/discussions/17419"&gt;"How autofree works", a discussion on V's GitHub repository&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:23" title="Jump back to footnote 23 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref2:23" title="Jump back to footnote 23 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref3:23" title="Jump back to footnote 23 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref4:23" title="Jump back to footnote 23 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:24"&gt;
&lt;p&gt;&lt;a href="https://web.archive.org/web/20240625174905/https://vlang.io/"&gt;Snapshot of V's website as of 2024-06-25&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:24" title="Jump back to footnote 24 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref2:24" title="Jump back to footnote 24 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref3:24" title="Jump back to footnote 24 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref4:24" title="Jump back to footnote 24 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref5:24" title="Jump back to footnote 24 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref6:24" title="Jump back to footnote 24 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref7:24" title="Jump back to footnote 24 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref8:24" title="Jump back to footnote 24 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref9:24" title="Jump back to footnote 24 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:25"&gt;
&lt;p&gt;&lt;a href="https://github.com/vlang/v/issues/17100"&gt;"Info about Lobster?" on V's GitHub&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:25" title="Jump back to footnote 25 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:26"&gt;
&lt;p&gt;&lt;a href="https://github.com/vlang/v/blob/4a7c70c90949df7fb6c8c84eb7e86b725b4bf86e/vlib/v/help/build/build.txt#L37"&gt;&lt;code&gt;v build&lt;/code&gt; documentation as of 2024-06-19&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:26" title="Jump back to footnote 26 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref2:26" title="Jump back to footnote 26 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:27"&gt;
&lt;p&gt;&lt;a href="https://github.com/vlang/v/issues/21758"&gt;'"Hello world" does not work in browser with the "js_browser" backend' on V's GitHub&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:27" title="Jump back to footnote 27 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:28"&gt;
&lt;p&gt;&lt;a href="https://github.com/vlang/v/issues/20500"&gt;"str.runes() fails on the JavaScript backend" on V's GitHub&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:28" title="Jump back to footnote 28 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:29"&gt;
&lt;p&gt;&lt;a href="https://web.archive.org/web/20190624052507/https://vlang.io/"&gt;Snapshot of V's website as of 2019-06-24&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:29" title="Jump back to footnote 29 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref2:29" title="Jump back to footnote 29 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:30"&gt;
&lt;p&gt;&lt;a href="https://web.archive.org/web/20220731042922/https://vlang.io/"&gt;Snapshot of V's website as of 2022-07-31&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:30" title="Jump back to footnote 30 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:31"&gt;
&lt;p&gt;&lt;a href="https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2310.pdf"&gt;C2x standard draft&lt;/a&gt;, section 6.5.5&amp;#160;&lt;a class="footnote-backref" href="#fnref:31" title="Jump back to footnote 31 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:32"&gt;
&lt;p&gt;&lt;a href="https://github.com/vlang/v/issues/11059"&gt;"Division by zero is undefined behavior" on V's GitHub&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:32" title="Jump back to footnote 32 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:33"&gt;
&lt;p&gt;&lt;a href="https://news.ycombinator.com/item?id=31947787"&gt;Part of a Hacker News thread about V 0.3 release&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:33" title="Jump back to footnote 33 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:34"&gt;
&lt;p&gt;&lt;a href="https://www.ralfj.de/blog/2019/07/14/uninit.html"&gt;"What The Hardware Does" is not What Your Program Does: Uninitialized Memory&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:34" title="Jump back to footnote 34 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:35"&gt;
&lt;p&gt;&lt;a href="https://github.com/vlang/v/discussions/19792"&gt;'How to build small "native binaries without any dependencies"?' on V's GitHub&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:35" title="Jump back to footnote 35 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref2:35" title="Jump back to footnote 35 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:36"&gt;
&lt;p&gt;&lt;a href="https://stackoverflow.com/questions/72855645/how-vlang-compile-static-binary"&gt;"How vlang compile static binary?" on StackOverflow&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:36" title="Jump back to footnote 36 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:37"&gt;
&lt;p&gt;&lt;a href="https://github.com/vlang/v/blob/b6c7b46dcf95c9485407838e965e923844641b31/vlib/builtin/array.v#L864"&gt;&lt;code&gt;array.v&lt;/code&gt; in V's source code&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:37" title="Jump back to footnote 37 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:38"&gt;
&lt;p&gt;&lt;a href="https://stackoverflow.com/questions/57476533/why-is-statically-linking-glibc-discouraged"&gt;"Why is statically linking glibc discouraged?" on StackOverflow&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:38" title="Jump back to footnote 38 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:39"&gt;
&lt;p&gt;&lt;a href="https://github.com/vlang/v/blob/b6c7b46dcf95c9485407838e965e923844641b31/doc/docs.md#structs-with-reference-fields"&gt;V docs: Structs with reference fields&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:39" title="Jump back to footnote 39 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:40"&gt;
&lt;p&gt;&lt;a href="https://web.archive.org/web/20240629140645/https://docs.vlang.io/functions-2.html"&gt;"Functions 2" in V docs&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:40" title="Jump back to footnote 40 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:41"&gt;
&lt;p&gt;&lt;a href="https://github.com/vlang/v/releases/tag/0.4.6"&gt;V 0.4.6 release on GitHub&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:41" title="Jump back to footnote 41 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:42"&gt;
&lt;p&gt;&lt;a href="https://github.com/vlang/v/issues/21760"&gt;"Unclear how to compile a static binary" on V's GitHub&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:42" title="Jump back to footnote 42 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:43"&gt;
&lt;p&gt;&lt;a href="https://github.com/vlang/v/issues/2091"&gt;"Question static linked binary v compiler" on V's GitHub&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:43" title="Jump back to footnote 43 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:44"&gt;
&lt;p&gt;&lt;a href="https://doc.rust-lang.org/nomicon/drop-flags.html"&gt;"Drop Flags" in the Rustonomicon&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:44" title="Jump back to footnote 44 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:45"&gt;
&lt;p&gt;&lt;a href="https://github.com/vlang/v/issues/14913"&gt;"Trivial program puts variable on heap unnecessarily, autofree does not free it" on V's GitHub&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:45" title="Jump back to footnote 45 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:46"&gt;
&lt;p&gt;&lt;a href="https://github.com/vlang/v/blob/ae2183043b3c8c589b78ac9c82eaf09d5e6a4532/tutorials/C2V.%20Translating%20simple%20programs%20and%20DOOM./README.md"&gt;&lt;code&gt;tutorials/C2V. Translating simple programs and DOOM./README.md&lt;/code&gt; in V's GitHub&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:46" title="Jump back to footnote 46 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:47"&gt;
&lt;p&gt;&lt;a href="https://web.archive.org/web/20240702133422/https://modules.vlang.io/net.http.html"&gt;&lt;code&gt;net.http&lt;/code&gt; in V docs as of 2024-07-02&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:47" title="Jump back to footnote 47 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:48"&gt;
&lt;p&gt;&lt;a href="https://github.com/vlang/v/pull/9563"&gt;"context: Adds module context based on Golang's context" on V's GitHub&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:48" title="Jump back to footnote 48 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:49"&gt;
&lt;p&gt;&lt;a href="https://web.archive.org/web/20240702135114/https://modules.vlang.io/vweb.html"&gt;&lt;code&gt;vweb&lt;/code&gt; in V's docs as of 2024-07-02&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:49" title="Jump back to footnote 49 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:50"&gt;
&lt;p&gt;&lt;a href="https://web.archive.org/web/20240702141105/https://modules.vlang.io/orm.html"&gt;&lt;code&gt;orm&lt;/code&gt; in V's docs as of 2024-07-02&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:50" title="Jump back to footnote 50 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:51"&gt;
&lt;p&gt;&lt;a href="https://github.com/vlang/v/blob/209063ffd09d7cbc272d47931523471e236841e4/ROADMAP.md"&gt;V's roadmap as of 2024-03-04&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:51" title="Jump back to footnote 51 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:52"&gt;
&lt;p&gt;&lt;a href="https://web.archive.org/web/20180615121501/https://volt.ws/"&gt;Volt's website as of 2018-06-15&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:52" title="Jump back to footnote 52 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref2:52" title="Jump back to footnote 52 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:53"&gt;
&lt;p&gt;&lt;a href="https://web.archive.org/web/20170715190553/https://eul.im/"&gt;Eul's website as of 2017-07-15&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:53" title="Jump back to footnote 53 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:54"&gt;
&lt;p&gt;&lt;a href="https://news.ycombinator.com/item?id=19145768"&gt;"Volt: Fast native desktop client for Slack and Skype" on Hacker News&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:54" title="Jump back to footnote 54 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:55"&gt;
&lt;p&gt;&lt;a href="https://web.archive.org/web/20240530051805/https://volt-app.com/"&gt;Volt's website as of 2024-05-30&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:55" title="Jump back to footnote 55 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:56"&gt;
&lt;p&gt;&lt;a href="https://github.com/voltapp/volt"&gt;Volt's GitHub repository&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:56" title="Jump back to footnote 56 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:57"&gt;
&lt;p&gt;&lt;a href="https://web.archive.org/web/20190210174447/https://volt.ws/lang"&gt;Description of V on Volt's website as of 2019-02-10&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:57" title="Jump back to footnote 57 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:58"&gt;
&lt;p&gt;&lt;a href="https://web.archive.org/web/20190207110558/https://volt.ws/game"&gt;"Writing a 3D shooter in V/pure OpenGL in an hour"&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:58" title="Jump back to footnote 58 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref2:58" title="Jump back to footnote 58 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:59"&gt;
&lt;p&gt;&lt;a href="https://news.ycombinator.com/item?id=13819447"&gt;Show HN: Gitly.io – high performance Git service with a 10s installation time&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:59" title="Jump back to footnote 59 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:60"&gt;
&lt;p&gt;&lt;a href="https://news.ycombinator.com/item?id=19527379"&gt;Part of Hacker News thread about the V playground&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:60" title="Jump back to footnote 60 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:61"&gt;
&lt;p&gt;&lt;a href="https://github.com/vlang/v/issues/35"&gt;"This language is not as advertised" on V's GitHub&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:61" title="Jump back to footnote 61 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:62"&gt;
&lt;p&gt;&lt;a href="https://github.com/vlang/c2v/issues/180"&gt;"C2V does not translate parameters in main()" on V's GitHub&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:62" title="Jump back to footnote 62 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:63"&gt;
&lt;p&gt;&lt;a href="https://web.archive.org/web/20191008201530/https://vlang.io/docs"&gt;Snapshot of V docs page as of 2019-10-08&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:63" title="Jump back to footnote 63 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:64"&gt;
&lt;p&gt;&lt;a href="https://doc.rust-lang.org/book/ch15-06-reference-cycles.html"&gt;"Reference Cycles Can Leak Memory" in "The Rust Programming Language" book&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:64" title="Jump back to footnote 64 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:65"&gt;
&lt;p&gt;&lt;a href="https://web.archive.org/web/20210428050431/https://vlang.io/"&gt;Snapshot of V's website as of 2021-04-28&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:65" title="Jump back to footnote 65 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:66"&gt;
&lt;p&gt;&lt;a href="https://github.com/vlang/gitly/"&gt;Gitly's repo on GitHub&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:66" title="Jump back to footnote 66 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:67"&gt;
&lt;p&gt;&lt;a href="https://news.ycombinator.com/item?id=37310515"&gt;Part of Hacker News thread about V 0.4 release&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:67" title="Jump back to footnote 67 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:68"&gt;
&lt;p&gt;&lt;a href="https://github.com/vlang/v/discussions/14222#discussioncomment-2705347"&gt;tzsharing's thread in a discussion on V's GitHub&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:68" title="Jump back to footnote 68 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:69"&gt;
&lt;p&gt;&lt;a href="https://news.ycombinator.com/item?id=39503446"&gt;_ramj's comment on a Hacker News thread about "V Language Review (2023)"&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:69" title="Jump back to footnote 69 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:70"&gt;
&lt;p&gt;&lt;a href="https://xeiaso.net/blog/v-vvork-in-progress-2020-01-03/"&gt;"V is for Vvork in Progress" by Xe Iaso&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:70" title="Jump back to footnote 70 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:71"&gt;
&lt;p&gt;&lt;a href="https://docs.google.com/presentation/d/1WaCUyEVRwMU61IHfrdVdw9P7HkPrPCS10j5cwqpA4p4/"&gt;"V is an Ethical Disaster", author unknown&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:71" title="Jump back to footnote 71 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:72"&gt;
&lt;p&gt;&lt;a href="https://cs.stackexchange.com/questions/68635/why-dont-compilers-automatically-insert-deallocations"&gt;"Why don't compilers automatically insert deallocations?" on Computer Science Stack Exchange&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:72" title="Jump back to footnote 72 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:73"&gt;
&lt;p&gt;&lt;a href="https://queue.acm.org/detail.cfm?id=3212479"&gt;"C Is Not a Low-level Language" on ACM Queue&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:73" title="Jump back to footnote 73 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</content><category term="Programming"/></entry><entry><title>NixOS in the Cloud, step-by-step: part 2</title><link href="https://justinas.org/nixos-in-the-cloud-step-by-step-part-2" rel="alternate"/><published>2021-01-11T18:00:00+00:00</published><updated>2021-01-11T18:00:00+00:00</updated><author><name>Justinas Stankevičius</name></author><id>tag:justinas.org,2021-01-11:/nixos-in-the-cloud-step-by-step-part-2</id><summary type="html">&lt;p&gt;In the &lt;a href="/nixos-in-the-cloud-step-by-step-part-1"&gt;previous article&lt;/a&gt;,
we deployed a basic cloud server running NixOS on DigitalOcean
and set up a declarative deployment definition for it using Morph.&lt;/p&gt;
&lt;p&gt;In this part, we are taking it a step further. We will utilize
both Morph and &lt;a href="https://www.terraform.io/"&gt;Terraform&lt;/a&gt;
to spin-up a network of 3 web servers …&lt;/p&gt;</summary><content type="html">&lt;p&gt;In the &lt;a href="/nixos-in-the-cloud-step-by-step-part-1"&gt;previous article&lt;/a&gt;,
we deployed a basic cloud server running NixOS on DigitalOcean
and set up a declarative deployment definition for it using Morph.&lt;/p&gt;
&lt;p&gt;In this part, we are taking it a step further. We will utilize
both Morph and &lt;a href="https://www.terraform.io/"&gt;Terraform&lt;/a&gt;
to spin-up a network of 3 web servers,
sitting behind 2 load-balancers,
managed by declarative configuration.
We will also learn an approach that utilizes Terraform state
in Morph network definition, making Morph automatically aware
of changes to your infrastructure.&lt;/p&gt;
&lt;p&gt;For the uninitiated, Terraform is a popular
&lt;a href="https://en.wikipedia.org/wiki/Infrastructure_as_code"&gt;infrastructure as code&lt;/a&gt; tool.
It has basically become a de-facto standard across the industry.
We will use it to spin up multiple servers on DigitalOcean
without the need to point-and-click in the dashboard.&lt;/p&gt;
&lt;h1 id="preparation"&gt;Preparation&lt;/h1&gt;
&lt;p&gt;Although we are starting from a blank state, I assume you have read the
&lt;a href="/nixos-in-the-cloud-step-by-step-part-1"&gt;initial article of the series&lt;/a&gt;.
You will need to utilize the knowledge you've already gained,
as well as the resources created in your DigitalOcean account:
the NixOS disk image and your uploaded SSH public key.&lt;/p&gt;
&lt;p&gt;Let's create a directory and enter it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;mkdir&lt;span class="w"&gt; &lt;/span&gt;part2&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;part2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="nix-shell"&gt;nix-shell&lt;/h2&gt;
&lt;p&gt;Then, let's create a &lt;code&gt;shell.nix&lt;/code&gt; file with the tools we will need:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt; pkgs &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="l"&gt;&amp;lt;nixpkgs&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt;
  &lt;span class="ss"&gt;myTerraform&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; pkgs&lt;span class="o"&gt;.&lt;/span&gt;terraform&lt;span class="o"&gt;.&lt;/span&gt;withPlugins &lt;span class="p"&gt;(&lt;/span&gt;tp&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; tp&lt;span class="o"&gt;.&lt;/span&gt;digitalocean &lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="ss"&gt;ter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; pkgs&lt;span class="o"&gt;.&lt;/span&gt;writeShellScriptBin &lt;span class="s2"&gt;&amp;quot;ter&amp;quot;&lt;/span&gt; &lt;span class="s s-Multiline"&gt;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;    terraform $@ &amp;amp;&amp;amp; terraform show -json &amp;gt; show.json&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;  &amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;in&lt;/span&gt;
pkgs&lt;span class="o"&gt;.&lt;/span&gt;mkShell &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="ss"&gt;buildInputs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; pkgs&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; curl jq morph myTerraform ter &lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Notably, besides Terraform, Morph and basic command line utilities,
we add &lt;code&gt;ter&lt;/code&gt;, a wrapper for the &lt;code&gt;terraform&lt;/code&gt; command that will
also dump the state from &lt;code&gt;terraform show -json&lt;/code&gt;
into the current directory. This will come in use soon.&lt;/p&gt;
&lt;p&gt;Enter the shell and test that all commands work:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;nix-shell
&lt;span class="gp"&gt;$ &lt;/span&gt;curl&lt;span class="w"&gt; &lt;/span&gt;--version&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;head&lt;span class="w"&gt; &lt;/span&gt;-n&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;
&lt;span class="go"&gt;curl 7.72.0 (x86_64-pc-linux-gnu) libcurl/7.72.0 OpenSSL/1.1.1i zlib/1.2.11 libssh2/1.9.0 nghttp2/1.41.0&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;jq&lt;span class="w"&gt; &lt;/span&gt;--version
&lt;span class="go"&gt;jq-1.6&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;morph&lt;span class="w"&gt; &lt;/span&gt;--version
&lt;span class="go"&gt;1.5.0&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;terraform&lt;span class="w"&gt; &lt;/span&gt;version&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;head&lt;span class="w"&gt; &lt;/span&gt;-n&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;
&lt;span class="go"&gt;Terraform v0.14.3&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;ter&lt;span class="w"&gt; &lt;/span&gt;version&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;head&lt;span class="w"&gt; &lt;/span&gt;-n&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;
&lt;span class="go"&gt;Terraform v0.14.3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="digitalocean-api-token"&gt;DigitalOcean API token&lt;/h2&gt;
&lt;p&gt;To use DigitalOcean programmatically, create a
&lt;a href="https://www.digitalocean.com/docs/apis-clis/api/create-personal-access-token/"&gt;personal access token&lt;/a&gt;
in the DigitalOcean control panel.
Keep it in a safe place (e.g. your password manager),
as it allows full access to your droplets and other account data.&lt;/p&gt;
&lt;p&gt;Upon creation, let's safely set it in our shell session and verify:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;read&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-s&lt;span class="w"&gt; &lt;/span&gt;DIGITALOCEAN_TOKEN
&lt;span class="go"&gt;&amp;lt;...enter token here and press Enter...&amp;gt;&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;DIGITALOCEAN_TOKEN
&lt;span class="gp"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;DIGITALOCEAN_TOKEN
&lt;span class="go"&gt;7fba5cca53d8b6f9565037804a503029451495fac6708392cd6d3646f2e8fe8f&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;When using &lt;code&gt;read -s&lt;/code&gt;, the token will not be echoed
(i.e. represented on the screen, not even as asterisks),
similar to how entering password for &lt;code&gt;sudo&lt;/code&gt; works.&lt;/p&gt;
&lt;h2 id="digitalocean-resource-ids"&gt;DigitalOcean resource IDs&lt;/h2&gt;
&lt;p&gt;We need to use two existing resources on our DigitalOcean account:
our SSH public key and the NixOS custom image.
While we could &lt;a href="https://www.terraform.io/docs/import/index.html"&gt;import&lt;/a&gt;
them to our Terraform state, or even use a tool like
&lt;a href="https://github.com/GoogleCloudPlatform/terraformer"&gt;Terraformer&lt;/a&gt; to do it for us,
let's stick with a manual approach for brevity.&lt;/p&gt;
&lt;p&gt;Use curl and jq to query the
&lt;a href="https://developers.digitalocean.com/documentation/v2/"&gt;DigitalOcean API&lt;/a&gt;
and find out the IDs of the custom image and our SSH key respectively:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;curl&lt;span class="w"&gt; &lt;/span&gt;-s&lt;span class="w"&gt; &lt;/span&gt;-H&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$DIGITALOCEAN_TOKEN&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;https://api.digitalocean.com/v2/images?private=true&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;jq&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.images[] | select(.name == &amp;quot;nixos.qcow2.gz&amp;quot;) | .id&amp;#39;&lt;/span&gt;
&lt;span class="go"&gt;75674995&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;curl&lt;span class="w"&gt; &lt;/span&gt;-s&lt;span class="w"&gt; &lt;/span&gt;-H&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$DIGITALOCEAN_TOKEN&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;https://api.digitalocean.com/v2/account/keys&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;jq&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.ssh_keys[0].id&amp;#39;&lt;/span&gt;
&lt;span class="go"&gt;27010799&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The second command assumes you only have one SSH public key
set-up in your DigitalOcean account.
If that is not the case, you might need to inspect the full response from the API.&lt;/p&gt;
&lt;h1 id="creating-our-droplets"&gt;Creating our droplets&lt;/h1&gt;
&lt;p&gt;We are now ready to make a basic resource definition.
Let's create a &lt;code&gt;main.tf&lt;/code&gt; file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kr"&gt;provider&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;&amp;quot;digitalocean&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="kr"&gt;resource&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;&amp;quot;digitalocean_droplet&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;&amp;quot;backend&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;backend${count.index + 1}&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;ams3&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;s-1vcpu-1gb&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;75674995&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="na"&gt;ssh_keys&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;27010799&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;resource&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;&amp;quot;digitalocean_droplet&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;&amp;quot;loadbalancer&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;loadbalancer${count.index + 1}&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;ams3&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;s-1vcpu-1gb&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;75674995&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="na"&gt;ssh_keys&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;27010799&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This file defines a &lt;code&gt;digitalocean&lt;/code&gt; resource provider
and two &lt;code&gt;digitalocean_droplet&lt;/code&gt; resources: both &lt;code&gt;backend&lt;/code&gt; and &lt;code&gt;loadbalancer&lt;/code&gt;
resources will produce 2 servers with dynamically generated names:
&lt;code&gt;backend1&lt;/code&gt;, &lt;code&gt;backend2&lt;/code&gt;, &lt;code&gt;loadbalancer1&lt;/code&gt;, and &lt;code&gt;loadbalancer2&lt;/code&gt;.
Neither DigitalOcean, nor Terraform seem to enforce unique names
for droplets, but it is a requirement for what we will want to do later,
and a good idea in general.&lt;/p&gt;
&lt;p&gt;The definition also utilizes the previously-acquired identifiers
to specify that the droplet has to be spawned with our NixOS custom image
and include our public SSH key for authentication.&lt;/p&gt;
&lt;p&gt;Keys &lt;code&gt;region&lt;/code&gt; and &lt;code&gt;size&lt;/code&gt; are also required.
If you do not live in Europe, you might be better off choosing
&lt;a href="https://www.digitalocean.com/docs/platform/availability-matrix/"&gt;a region close to you&lt;/a&gt;.
We will not use any special features of particular regions, but we will use private networking,
so the droplets have to all be in the same region.
The examples of the possible values for &lt;code&gt;size&lt;/code&gt; can be found on
&lt;a href="https://slugs.do-api.dev/"&gt;a dedicated webpage&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We also need to create a &lt;code&gt;versions.tf&lt;/code&gt; file to define
the version and full path for the &lt;code&gt;digitalocean&lt;/code&gt; provider:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nb"&gt;terraform&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nb"&gt;required_providers&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;digitalocean&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;digitalocean/digitalocean&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;2.2.0&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Let's apply our changes, using the &lt;code&gt;ter&lt;/code&gt; wrapper to call Terraform:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$ ter init # only required the first time, or after new modules or providers are added
$ ter apply
&amp;lt;...confirm this with &amp;#39;yes&amp;#39;...&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In my experience, launching new droplets took about 30 to 40 seconds.&lt;/p&gt;
&lt;p&gt;Note: be really careful and always read what &lt;code&gt;ter apply&lt;/code&gt; is planning to do.
With great power of Terraform also comes great potential for destruction.
If, for example, you delete a resource definition from &lt;code&gt;main.tf&lt;/code&gt;,
or reduce the count of machines, the "obsolete" machines will get destroyed.
Terraform will always ask you to confirm the changes,
but you have to actually read through them!&lt;/p&gt;
&lt;p&gt;By this point, you should have 4 cloud servers launched.
We can query the current state via commands like &lt;code&gt;terraform show&lt;/code&gt; (or &lt;code&gt;ter show&lt;/code&gt;).
Feel free to play around and see what information Terraform provides.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;ter&lt;span class="w"&gt; &lt;/span&gt;show&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;head&lt;span class="w"&gt; &lt;/span&gt;-n&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;
&lt;span class="gp"&gt;# &lt;/span&gt;digitalocean_droplet.backend&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;:
&lt;span class="go"&gt;resource &amp;quot;digitalocean_droplet&amp;quot; &amp;quot;backend&amp;quot; {&lt;/span&gt;
&lt;span class="go"&gt;    backups              = false&lt;/span&gt;
&lt;span class="go"&gt;    created_at           = &amp;quot;2020-12-29T19:48:34Z&amp;quot;&lt;/span&gt;
&lt;span class="go"&gt;    disk                 = 25&lt;/span&gt;
&lt;span class="go"&gt;    id                   = &amp;quot;223901656&amp;quot;&lt;/span&gt;
&lt;span class="go"&gt;    image                = &amp;quot;75674995&amp;quot;&lt;/span&gt;
&lt;span class="go"&gt;    ipv4_address         = &amp;quot;198.51.100.41&amp;quot;&lt;/span&gt;
&lt;span class="go"&gt;    ipv4_address_private = &amp;quot;10.110.0.13&amp;quot;&lt;/span&gt;
&lt;span class="go"&gt;    ipv6                 = false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Terraform allows not only to create new servers,
but also to modify the current infrastructure, e.g.
increase the amount of instances for a specific resource.
Let's add one more backend server:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gh"&gt;diff --git a/part2/main.tf b/part2/main.tf&lt;/span&gt;
&lt;span class="gh"&gt;index 3957178..1b9a65d 100644&lt;/span&gt;
&lt;span class="gd"&gt;--- a/part2/main.tf&lt;/span&gt;
&lt;span class="gi"&gt;+++ b/part2/main.tf&lt;/span&gt;
&lt;span class="gu"&gt;@@ -7,7 +7,7 @@ resource &amp;quot;digitalocean_droplet&amp;quot; &amp;quot;backend&amp;quot; {&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;  image    = 75674995
&lt;span class="w"&gt; &lt;/span&gt;  ssh_keys = [27010799]

&lt;span class="gd"&gt;-  count = 2&lt;/span&gt;
&lt;span class="gi"&gt;+  count = 3&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Apply the changes once again:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;ter&lt;span class="w"&gt; &lt;/span&gt;apply
&lt;span class="go"&gt;&amp;lt;...confirm this with &amp;#39;yes&amp;#39;...&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you run &lt;code&gt;terraform show&lt;/code&gt; again, it should now show 5 machines in total.
Terraform can also provide a JSON-based output of your state by passing the &lt;code&gt;-json&lt;/code&gt; flag.
Let's try that feature out and inspect our current infrastructure:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;terraform&lt;span class="w"&gt; &lt;/span&gt;show&lt;span class="w"&gt; &lt;/span&gt;-json&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;jq&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.values.root_module.resources[] | {name: .values.name, ip: .values.ipv4_address}&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="go"&gt;{&lt;/span&gt;
&lt;span class="go"&gt;  &amp;quot;name&amp;quot;: &amp;quot;backend1&amp;quot;,&lt;/span&gt;
&lt;span class="go"&gt;  &amp;quot;ip&amp;quot;: &amp;quot;198.51.100.41&amp;quot;&lt;/span&gt;
&lt;span class="go"&gt;}&lt;/span&gt;
&lt;span class="go"&gt;{&lt;/span&gt;
&lt;span class="go"&gt;  &amp;quot;name&amp;quot;: &amp;quot;backend2&amp;quot;,&lt;/span&gt;
&lt;span class="go"&gt;  &amp;quot;ip&amp;quot;: &amp;quot;198.51.100.36&amp;quot;&lt;/span&gt;
&lt;span class="go"&gt;}&lt;/span&gt;
&lt;span class="go"&gt;{&lt;/span&gt;
&lt;span class="go"&gt;  &amp;quot;name&amp;quot;: &amp;quot;backend3&amp;quot;,&lt;/span&gt;
&lt;span class="go"&gt;  &amp;quot;ip&amp;quot;: &amp;quot;203.0.113.74&amp;quot;&lt;/span&gt;
&lt;span class="go"&gt;}&lt;/span&gt;
&lt;span class="go"&gt;{&lt;/span&gt;
&lt;span class="go"&gt;  &amp;quot;name&amp;quot;: &amp;quot;loadbalancer1&amp;quot;,&lt;/span&gt;
&lt;span class="go"&gt;  &amp;quot;ip&amp;quot;: &amp;quot;198.51.100.42&amp;quot;&lt;/span&gt;
&lt;span class="go"&gt;}&lt;/span&gt;
&lt;span class="go"&gt;{&lt;/span&gt;
&lt;span class="go"&gt;  &amp;quot;name&amp;quot;: &amp;quot;loadbalancer2&amp;quot;,&lt;/span&gt;
&lt;span class="go"&gt;  &amp;quot;ip&amp;quot;: &amp;quot;203.0.113.122&amp;quot;&lt;/span&gt;
&lt;span class="go"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;5 servers at our whim. I would call that a success!&lt;/p&gt;
&lt;p&gt;As Morph uses SSH to deploy, it obeys SSH's
&lt;a href="https://en.wikipedia.org/wiki/Trust_on_first_use"&gt;trust on first use&lt;/a&gt;.
So, when we deploy our network for the first time,
it will ask us to confirm the fingerprint for each machine.
For our own convenience, let's pre-fetch the SSH keys for our servers in advance,
so we can avoid the manual intervention later and have the deployment proceed automatically.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;terraform&lt;span class="w"&gt; &lt;/span&gt;show&lt;span class="w"&gt; &lt;/span&gt;-json&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;jq&lt;span class="w"&gt; &lt;/span&gt;-r&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.values.root_module.resources[].values.ipv4_address&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;show.json&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;xargs&lt;span class="w"&gt; &lt;/span&gt;ssh-keyscan&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;~/.ssh/known_hosts
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h1 id="using-terraform-state-from-nix"&gt;Using Terraform state from Nix&lt;/h1&gt;
&lt;p&gt;Terraform state is now the source of truth about the servers we have created.
We would like to use the information provided by &lt;code&gt;terraform show -json&lt;/code&gt;
in our network definition and automatically deploy the relevant configuration
to all of the services that share a role.&lt;/p&gt;
&lt;p&gt;By now, we should have a file called &lt;code&gt;show.json&lt;/code&gt; in the current directory.
It has been created by the &lt;code&gt;ter&lt;/code&gt; wrapper we defined,
and updated after each operation, such as &lt;code&gt;ter apply&lt;/code&gt;.
This file will help us greatly.
Nix has a function called &lt;code&gt;builtins.fromJSON&lt;/code&gt;,
which can deserialize arbitrary JSON data to Nix types.
Nix is also a proper functional programming language,
which will allow us to do the necessary manipulations with that data.&lt;/p&gt;
&lt;p&gt;Put all of this together, and we can read &lt;code&gt;show.json&lt;/code&gt;, deserialize it
and transform it to a useful data structure
which we can use in our network definition.
To achieve this, I made a utility file called &lt;code&gt;parsetf.nix&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt; pkgs &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="l"&gt;&amp;lt;nixpkgs&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;,&lt;/span&gt; lib &lt;span class="o"&gt;?&lt;/span&gt; pkgs&lt;span class="o"&gt;.&lt;/span&gt;lib
&lt;span class="p"&gt;}:&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt;
  &lt;span class="ss"&gt;resourcesInModule&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; type&lt;span class="p"&gt;:&lt;/span&gt; module&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;builtins&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;filter &lt;span class="p"&gt;(&lt;/span&gt;r&lt;span class="p"&gt;:&lt;/span&gt; r&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; type&lt;span class="p"&gt;)&lt;/span&gt; module&lt;span class="o"&gt;.&lt;/span&gt;resources &lt;span class="o"&gt;++&lt;/span&gt;
    lib&lt;span class="o"&gt;.&lt;/span&gt;flatten &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;resourcesInModule type&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;module&lt;span class="o"&gt;.&lt;/span&gt;child_modules &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;]));&lt;/span&gt;
  &lt;span class="ss"&gt;resourcesByType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; type&lt;span class="p"&gt;:&lt;/span&gt; resourcesInModule type payload&lt;span class="o"&gt;.&lt;/span&gt;values&lt;span class="o"&gt;.&lt;/span&gt;root_module&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="ss"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;builtins&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;fromJSON &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;builtins&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;readFile &lt;span class="l"&gt;./show.json&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;in&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;inherit&lt;/span&gt; resourcesByType&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It defines a function named &lt;code&gt;resourcesByType&lt;/code&gt;.
When this function is called like &lt;code&gt;resourcesByType "digitalocean_droplet"&lt;/code&gt;,
it will return all the droplets we have set-up with Terraform.&lt;/p&gt;
&lt;p&gt;It intentionally operates on a single resource type.
As time goes on, you might also provision other resources on DigitalOcean,
for example, block storage or floating IPs.
You will be able to use the information about these resources as well,
simply by changing the argument to this function.
&lt;code&gt;resourcesByType&lt;/code&gt; will even recurse into
child &lt;a href="https://www.terraform.io/docs/modules/index.html"&gt;modules&lt;/a&gt;,
which will come in handy once you start using that feature.&lt;/p&gt;
&lt;p&gt;Let's see how it works by experimenting in the Nix REPL:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;nix&lt;span class="w"&gt; &lt;/span&gt;repl
&lt;span class="go"&gt;Welcome to Nix version 2.3.9. Type :? for help.&lt;/span&gt;

&lt;span class="go"&gt;nix-repl&amp;gt; :l parsetf.nix&lt;/span&gt;
&lt;span class="go"&gt;Added 1 variables.&lt;/span&gt;

&lt;span class="go"&gt;nix-repl&amp;gt; droplets = resourcesByType &amp;quot;digitalocean_droplet&amp;quot;&lt;/span&gt;

&lt;span class="go"&gt;nix-repl&amp;gt; droplets&lt;/span&gt;
&lt;span class="go"&gt;[ { ... } { ... } { ... } { ... } { ... } ]&lt;/span&gt;

&lt;span class="go"&gt;nix-repl&amp;gt; (builtins.head droplets).name&lt;/span&gt;
&lt;span class="go"&gt;&amp;quot;backend&amp;quot;&lt;/span&gt;

&lt;span class="go"&gt;nix-repl&amp;gt; (builtins.head droplets).values.name&lt;/span&gt;
&lt;span class="go"&gt;&amp;quot;backend1&amp;quot;&lt;/span&gt;

&lt;span class="go"&gt;nix-repl&amp;gt; (builtins.head droplets).values.ipv4_address&lt;/span&gt;
&lt;span class="go"&gt;&amp;quot;198.51.100.41&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;First, we loaded everything that &lt;code&gt;parsetf.nix&lt;/code&gt; defines into the global namespace.
In our case, that's a single function called &lt;code&gt;resourcesByType&lt;/code&gt;.
When we call it with the proper resource type, we see that it returns a list of five objects,
as we currently have 5 servers.
Once we get the first element from the list via &lt;code&gt;builtins.head&lt;/code&gt;,
we can evaluate any of its properties.&lt;/p&gt;
&lt;p&gt;Note that &lt;code&gt;.name&lt;/code&gt; will always return the name we specified for the Terraform resource,
which will be the same for all the instances that this resource defined.
Meanwhile &lt;code&gt;.values.name&lt;/code&gt; will return the &lt;code&gt;name&lt;/code&gt; property defined &lt;em&gt;inside&lt;/em&gt; of the resource.
This is the property that decides the droplet's actual hostname.
As we have made this unique for each droplet,
we will be able to use this to uniquely identify them.&lt;/p&gt;
&lt;p&gt;Let's continue our REPL session:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="go"&gt;nix-repl&amp;gt; balancers = (builtins.filter (d: d.name == &amp;quot;loadbalancer&amp;quot;) droplets)&lt;/span&gt;

&lt;span class="go"&gt;nix-repl&amp;gt; map (b: b.values.ipv4_address) balancers&lt;/span&gt;
&lt;span class="go"&gt;[ &amp;quot;198.51.100.42&amp;quot; &amp;quot;203.0.113.122&amp;quot; ]&lt;/span&gt;

&lt;span class="go"&gt;nix-repl&amp;gt; firstBalancer = builtins.head (builtins.filter (d: d.values.name == &amp;quot;loadbalancer1&amp;quot;) balancers)&lt;/span&gt;

&lt;span class="go"&gt;nix-repl&amp;gt; firstBalancer.values.name&lt;/span&gt;
&lt;span class="go"&gt;&amp;quot;loadbalancer1&amp;quot;&lt;/span&gt;

&lt;span class="go"&gt;nix-repl&amp;gt; firstBalancer.values.ipv4_address&lt;/span&gt;
&lt;span class="go"&gt;&amp;quot;198.51.100.42&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;As you can see, it is now possible to extract the needed information
for both a single machine and a class of machines.
All we need is the &lt;code&gt;map&lt;/code&gt; and &lt;code&gt;filter&lt;/code&gt; operations,
familiar from most other programming languages.&lt;/p&gt;
&lt;p&gt;Some might ask: why not just read the &lt;code&gt;terraform.tfstate&lt;/code&gt; file directly?
For one, there will be no such file if using a remote state backend,
such as Terraform Cloud, which is a no-brainer when working in a team.
The &lt;a href="https://www.terraform.io/docs/state/index.html#format"&gt;official documentation&lt;/a&gt;
also says this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;State snapshots are stored in JSON format and new Terraform versions are generally backward compatible with state snapshots produced by earlier versions. However, the state format is subject to change in new Terraform versions, so if you build software that parses or modifies it directly you should expect to perform ongoing maintenence of that software as the state format evolves in new versions.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The output of &lt;code&gt;terraform show -json&lt;/code&gt;, meanwhile,
has a &lt;a href="https://www.terraform.io/docs/internals/json-format.html"&gt;detailed specification&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Well, what about calling &lt;code&gt;terraform show -json&lt;/code&gt; directly from Nix?
That is not possible without
&lt;a href="https://elvishjerricco.github.io/2018/06/24/secure-declarative-key-management.html#sharing-secrets"&gt;jumping through some hoops&lt;/a&gt;,
and that is possibly for the better.
As I do not think it would be a good idea to let my expressions run arbitrary commands,
I've gone with the wrapper approach.
So far it has served me well: you just have to remember
to always use &lt;code&gt;ter&lt;/code&gt; rather than &lt;code&gt;terraform&lt;/code&gt; for operations
that might modify the state of your infrastructure.&lt;/p&gt;
&lt;h1 id="marrying-terraform-and-morph"&gt;Marrying Terraform and Morph&lt;/h1&gt;
&lt;p&gt;Now that we have the ability to use information about resources managed by Terraform
in our Nix expressions, let's make a minimal &lt;code&gt;network.nix&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# 1.&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt;
  &lt;span class="ss"&gt;resourcesByType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="l"&gt;./parsetf.nix&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;resourcesByType&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="ss"&gt;droplets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; resourcesByType &lt;span class="s2"&gt;&amp;quot;digitalocean_droplet&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="ss"&gt;backends&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;builtins&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;filter &lt;span class="p"&gt;(&lt;/span&gt;d&lt;span class="p"&gt;:&lt;/span&gt; d&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;backend&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; droplets&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="ss"&gt;loadbalancers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;builtins&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;filter &lt;span class="p"&gt;(&lt;/span&gt;d&lt;span class="p"&gt;:&lt;/span&gt; d&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;loadbalancer&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; droplets&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;# 2.&lt;/span&gt;
  &lt;span class="ss"&gt;mkBackend&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; resource&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; modulesPath&lt;span class="p"&gt;,&lt;/span&gt; lib&lt;span class="p"&gt;,&lt;/span&gt; name&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="ss"&gt;imports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; lib&lt;span class="o"&gt;.&lt;/span&gt;optional &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;builtins&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;pathExists &lt;span class="l"&gt;./do-userdata.nix&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="l"&gt;./do-userdata.nix&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;modulesPath &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/virtualisation/digital-ocean-config.nix&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;];&lt;/span&gt;
    deployment&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;targetHost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; resource&lt;span class="o"&gt;.&lt;/span&gt;values&lt;span class="o"&gt;.&lt;/span&gt;ipv4_address&lt;span class="p"&gt;;&lt;/span&gt;
    deployment&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;targetUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;root&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    networking&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;hostName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; resource&lt;span class="o"&gt;.&lt;/span&gt;values&lt;span class="o"&gt;.&lt;/span&gt;name&lt;span class="p"&gt;;&lt;/span&gt;
    system&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;stateVersion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;21.11&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="ss"&gt;mkLoadBalancer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; resource&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; modulesPath&lt;span class="p"&gt;,&lt;/span&gt; lib&lt;span class="p"&gt;,&lt;/span&gt; name&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="ss"&gt;imports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; lib&lt;span class="o"&gt;.&lt;/span&gt;optional &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;builtins&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;pathExists &lt;span class="l"&gt;./do-userdata.nix&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="l"&gt;./do-userdata.nix&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;modulesPath &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/virtualisation/digital-ocean-config.nix&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;];&lt;/span&gt;
    deployment&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;targetHost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; resource&lt;span class="o"&gt;.&lt;/span&gt;values&lt;span class="o"&gt;.&lt;/span&gt;ipv4_address&lt;span class="p"&gt;;&lt;/span&gt;
    deployment&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;targetUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;root&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    networking&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;hostName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; resource&lt;span class="o"&gt;.&lt;/span&gt;values&lt;span class="o"&gt;.&lt;/span&gt;name&lt;span class="p"&gt;;&lt;/span&gt;
    system&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;stateVersion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;21.11&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;in&lt;/span&gt;
&lt;span class="c1"&gt;# 3.&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="ss"&gt;network&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="ss"&gt;pkgs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;builtins&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;fetchGit &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="ss"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;nixos-21.11-2021-12-19&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="ss"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;https://github.com/NixOS/nixpkgs&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="ss"&gt;ref&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;refs/heads/nixos-21.11&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="ss"&gt;rev&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;e6377ff35544226392b49fa2cf05590f9f0c4b43&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="c1"&gt;# 5.&lt;/span&gt;
&lt;span class="c1"&gt;# 4.&lt;/span&gt;
&lt;span class="nb"&gt;builtins&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;listToAttrs &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;r&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; r&lt;span class="o"&gt;.&lt;/span&gt;values&lt;span class="o"&gt;.&lt;/span&gt;name&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="ss"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; mkBackend r&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; backends&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="c1"&gt;# 5.&lt;/span&gt;
&lt;span class="nb"&gt;builtins&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;listToAttrs &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;r&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; r&lt;span class="o"&gt;.&lt;/span&gt;values&lt;span class="o"&gt;.&lt;/span&gt;name&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="ss"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; mkLoadBalancer r&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; loadbalancers&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is quite a bit beefier than what we started with in the first article,
so let's go over the functionality step-by-step:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;(1.)&lt;/strong&gt; We import &lt;code&gt;parsetf.nix&lt;/code&gt; and use the &lt;code&gt;resourcesByType&lt;/code&gt; function it defines
to get a list of droplets in the Terraform state.
We split it into two lists: one for the backends and another for the load balancers.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;(2.)&lt;/strong&gt; Then, we predefine two functions: &lt;code&gt;mkBackend&lt;/code&gt; and &lt;code&gt;mkLoadBalancer&lt;/code&gt;.
They both take a single argument - the terraform resource object -
and return yet another function, which generates the NixOS
configuration for a concrete machine.&lt;/p&gt;
&lt;p&gt;This way, we can generate similar configurations for all of the droplets
that share the same role (&lt;code&gt;backend&lt;/code&gt; or &lt;code&gt;loadbalancer&lt;/code&gt;),
while pulling the specifics, like IP address and hostname,
from the &lt;code&gt;resource&lt;/code&gt; parameter in the outer function.&lt;/p&gt;
&lt;p&gt;So far, these two configurations are identical,
but we will soon introduce configuration specific to backends and load balancers.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;(3.)&lt;/strong&gt; We introduce an attribute set that defines our network.
Just like in part 1, we use the special &lt;code&gt;network&lt;/code&gt; attribute
to pin the version of nixpkgs that will be used across our machines.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;(4.)&lt;/strong&gt; Then, we use the lists of our resources - &lt;code&gt;backends&lt;/code&gt; and &lt;code&gt;loadbalancers&lt;/code&gt;.
We iterate over the lists using &lt;code&gt;map&lt;/code&gt;, and for each resource produce
an attribute set of two attributes in the following form:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="ss"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;balancer1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="ss"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; modulesPath&lt;span class="p"&gt;,&lt;/span&gt; lib&lt;span class="p"&gt;,&lt;/span&gt; name&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* configuration options */&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That is, &lt;code&gt;name&lt;/code&gt; points to the hostname of the machine,
while &lt;code&gt;value&lt;/code&gt; points to the function that will generate the config
for this specific machine.&lt;/p&gt;
&lt;p&gt;We also use &lt;code&gt;builtins.listToAttrs&lt;/code&gt;.
This function will take this list of attrsets with name-value pairs:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="ss"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;balancer1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="ss"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; modulesPath&lt;span class="p"&gt;,&lt;/span&gt; lib&lt;span class="p"&gt;,&lt;/span&gt; name&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* configuration options */&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="ss"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;balancer2&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="ss"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; modulesPath&lt;span class="p"&gt;,&lt;/span&gt; lib&lt;span class="p"&gt;,&lt;/span&gt; name&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* configuration options */&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;and turn it into a single attrset like&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="ss"&gt;balancer1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; modulesPath&lt;span class="p"&gt;,&lt;/span&gt; lib&lt;span class="p"&gt;,&lt;/span&gt; name&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* configuration options */&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="ss"&gt;balancer2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; modulesPath&lt;span class="p"&gt;,&lt;/span&gt; lib&lt;span class="p"&gt;,&lt;/span&gt; name&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* configuration options */&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That's exactly the format that Morph expects!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;(5.)&lt;/strong&gt; By this point, we have several attrsets - one with the &lt;code&gt;network&lt;/code&gt; key,
another with a key for each of our backends and their respective configuration functions,
and a similar attrset for load balancers.
Using the &lt;code&gt;//&lt;/code&gt; operator, we merge these attrsets together.&lt;/p&gt;
&lt;p&gt;If we could inspect the final value this expression produces,
it would look something like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="ss"&gt;network&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="ss"&gt;pkgs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;builtins&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;fetchGit &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="ss"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;nixos-21.11-2021-12-19&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="ss"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;https://github.com/NixOS/nixpkgs&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="ss"&gt;ref&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;refs/heads/nixos-21.11&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="ss"&gt;rev&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;e6377ff35544226392b49fa2cf05590f9f0c4b43&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="ss"&gt;backend1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; modulesPath&lt;span class="p"&gt;,&lt;/span&gt; lib&lt;span class="p"&gt;,&lt;/span&gt; name&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* configuration options */&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="ss"&gt;backend2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; modulesPath&lt;span class="p"&gt;,&lt;/span&gt; lib&lt;span class="p"&gt;,&lt;/span&gt; name&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* configuration options */&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="ss"&gt;loadbalancer1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; modulesPath&lt;span class="p"&gt;,&lt;/span&gt; lib&lt;span class="p"&gt;,&lt;/span&gt; name&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* configuration options */&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="ss"&gt;loadbalancer2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; modulesPath&lt;span class="p"&gt;,&lt;/span&gt; lib&lt;span class="p"&gt;,&lt;/span&gt; name&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* configuration options */&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="ss"&gt;loadbalancer3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; modulesPath&lt;span class="p"&gt;,&lt;/span&gt; lib&lt;span class="p"&gt;,&lt;/span&gt; name&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* configuration options */&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, let's try to deploy the network using Morph:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;morph&lt;span class="w"&gt; &lt;/span&gt;deploy&lt;span class="w"&gt; &lt;/span&gt;network.nix&lt;span class="w"&gt; &lt;/span&gt;switch
&lt;span class="go"&gt;Selected 5/5 hosts (name filter:-0, limits:-0):&lt;/span&gt;
&lt;span class="go"&gt;          0: backend1 (secrets: 0, health checks: 0)&lt;/span&gt;
&lt;span class="go"&gt;          1: backend2 (secrets: 0, health checks: 0)&lt;/span&gt;
&lt;span class="go"&gt;          2: backend3 (secrets: 0, health checks: 0)&lt;/span&gt;
&lt;span class="go"&gt;          3: loadbalancer1 (secrets: 0, health checks: 0)&lt;/span&gt;
&lt;span class="go"&gt;          4: loadbalancer2 (secrets: 0, health checks: 0)&lt;/span&gt;

&lt;span class="go"&gt;&amp;lt;...snip...&amp;gt;&lt;/span&gt;

&lt;span class="go"&gt;** backend1&lt;/span&gt;
&lt;span class="go"&gt;updating GRUB 2 menu...&lt;/span&gt;
&lt;span class="go"&gt;activating the configuration...&lt;/span&gt;
&lt;span class="go"&gt;setting up /etc...&lt;/span&gt;
&lt;span class="go"&gt;reloading user units for root...&lt;/span&gt;
&lt;span class="go"&gt;setting up tmpfiles&lt;/span&gt;

&lt;span class="go"&gt;Running healthchecks on backend1 (198.51.100.41):&lt;/span&gt;
&lt;span class="go"&gt;Health checks OK&lt;/span&gt;
&lt;span class="go"&gt;Done: backend1&lt;/span&gt;

&lt;span class="go"&gt;&amp;lt;...snip...&amp;gt;&lt;/span&gt;

&lt;span class="go"&gt;Executing &amp;#39;switch&amp;#39; on matched hosts:&lt;/span&gt;

&lt;span class="go"&gt;** loadbalancer2&lt;/span&gt;
&lt;span class="go"&gt;updating GRUB 2 menu...&lt;/span&gt;
&lt;span class="go"&gt;activating the configuration...&lt;/span&gt;
&lt;span class="go"&gt;setting up /etc...&lt;/span&gt;
&lt;span class="go"&gt;reloading user units for root...&lt;/span&gt;
&lt;span class="go"&gt;setting up tmpfiles&lt;/span&gt;

&lt;span class="go"&gt;Running healthchecks on loadbalancer2 (203.0.113.122):&lt;/span&gt;
&lt;span class="go"&gt;Health checks OK&lt;/span&gt;
&lt;span class="go"&gt;Done: loadbalancer2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Morph deploys to all five hosts, one by one.&lt;/p&gt;
&lt;h1 id="deploying-services-to-the-network"&gt;Deploying services to the network&lt;/h1&gt;
&lt;p&gt;Now that we're done with the Terraform &amp;lt;-&amp;gt; Nix boilerplate,
we can start deploying nginx on our droplets. Let's configure nginx on the backends:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gh"&gt;diff --git a/part2/network.nix b/part2/network.nix&lt;/span&gt;
&lt;span class="gh"&gt;index 6198eb1..9694bfb 100644&lt;/span&gt;
&lt;span class="gd"&gt;--- a/part2/network.nix&lt;/span&gt;
&lt;span class="gi"&gt;+++ b/part2/network.nix&lt;/span&gt;
&lt;span class="gu"&gt;@@ -13,6 +13,15 @@ let&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;    deployment.targetUser = &amp;quot;root&amp;quot;;
&lt;span class="w"&gt; &lt;/span&gt;    networking.hostName = resource.values.name;
&lt;span class="w"&gt; &lt;/span&gt;    system.stateVersion = &amp;quot;21.11&amp;quot;;
&lt;span class="gi"&gt;+&lt;/span&gt;
&lt;span class="gi"&gt;+    networking.firewall.allowedTCPPorts = [ 80 ];&lt;/span&gt;
&lt;span class="gi"&gt;+    services.nginx = {&lt;/span&gt;
&lt;span class="gi"&gt;+      enable = true;&lt;/span&gt;
&lt;span class="gi"&gt;+      virtualHosts.default = {&lt;/span&gt;
&lt;span class="gi"&gt;+        default = true;&lt;/span&gt;
&lt;span class="gi"&gt;+        locations.&amp;quot;/&amp;quot;.return = &amp;quot;200 \&amp;quot;Hello from ${name} at ${resource.values.ipv4_address}\&amp;quot;&amp;quot;;&lt;/span&gt;
&lt;span class="gi"&gt;+      };&lt;/span&gt;
&lt;span class="gi"&gt;+    };&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;  };

&lt;span class="w"&gt; &lt;/span&gt;  mkLoadBalancer = resource: { modulesPath, lib, name, ... }: {
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Follow this up with a deployment, and check that nginx is working
on all of the backends:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;morph&lt;span class="w"&gt; &lt;/span&gt;deploy&lt;span class="w"&gt; &lt;/span&gt;network.nix&lt;span class="w"&gt; &lt;/span&gt;switch
&lt;span class="go"&gt;&amp;lt;...snip...&amp;gt;&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;curl&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;198&lt;/span&gt;.51.100.41
&lt;span class="go"&gt;Hello from backend1 at 198.51.100.41&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;curl&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;198&lt;/span&gt;.51.100.36
&lt;span class="go"&gt;Hello from backend2 at 198.51.100.36&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;curl&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;203&lt;/span&gt;.0.113.74
&lt;span class="go"&gt;Hello from backend3 at 203.0.113.74&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, let's configure the load balancer machines:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;diff --git a/part2/network.nix b/part2/network.nix
index 9694bfb..5fa3925 100644
--- a/part2/network.nix
+++ b/part2/network.nix
@@ -32,8 +32,19 @@ let
     deployment.targetUser = &amp;quot;root&amp;quot;;
     networking.hostName = resource.values.name;
     system.stateVersion = &amp;quot;21.11&amp;quot;;
-  };

+    networking.firewall.allowedTCPPorts = [ 80 ];
+    services.nginx = {
+      enable = true;
+      upstreams.backend.servers = builtins.listToAttrs
+        (map (r: { name = r.values.ipv4_address_private; value = { }; })
+          backends);
+      virtualHosts.default = {
+        default = true;
+        locations.&amp;quot;/&amp;quot;.proxyPass = &amp;quot;http://backend&amp;quot;;
+      };
+    };
+  };
 in
 {
   network = {
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here, we also configure nginx.
However, instead of returning a static message,
we define an upstream called &lt;code&gt;backend&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;a href="https://search.nixos.org/options?channel=21.11&amp;amp;show=services.nginx.upstreams.%3Cname%3E.servers&amp;amp;from=0&amp;amp;size=30&amp;amp;sort=relevance&amp;amp;query=services.nginx.upstreams"&gt;&lt;code&gt;upstreams.&amp;lt;name&amp;gt;.servers&lt;/code&gt; option&lt;/a&gt;
expects an attribute set where names are the server addresses,
and values are options for the specific server (empty in our case).
We use the &lt;code&gt;ipv4_address_private&lt;/code&gt; attribute from the Terraform resources:
by default, DigitalOcean puts all of the droplets created in a single region
on their own internal network.&lt;/p&gt;
&lt;p&gt;We once again use &lt;code&gt;map&lt;/code&gt; to traverse the list of &lt;code&gt;backend&lt;/code&gt; resources
and then turn it into an attribute set using &lt;code&gt;listToAttrs&lt;/code&gt;.
At the end, it results in this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;upstreams&lt;span class="o"&gt;.&lt;/span&gt;backend&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;servers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;&amp;quot;198.51.100.41&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
  &lt;span class="s2"&gt;&amp;quot;198.51.100.36&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
  &lt;span class="s2"&gt;&amp;quot;203.0.113.74&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We then also define the default virtual host, which proxies all requests to the upstream.
The address of &lt;code&gt;http://backend&lt;/code&gt; indicates that nginx will pass the requests
to one of the servers defined in the upstream called &lt;code&gt;backend&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Let's deploy and try querying one of the load balancers:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;morph&lt;span class="w"&gt; &lt;/span&gt;deploy&lt;span class="w"&gt; &lt;/span&gt;network.nix&lt;span class="w"&gt; &lt;/span&gt;switch
&lt;span class="go"&gt;&amp;lt;...snip...&amp;gt;&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;curl&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;198&lt;/span&gt;.51.100.42
&lt;span class="go"&gt;Hello from backend3 at 203.0.113.74&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;curl&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;198&lt;/span&gt;.51.100.42
&lt;span class="go"&gt;Hello from backend2 at 198.51.100.36&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;curl&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;198&lt;/span&gt;.51.100.42
&lt;span class="go"&gt;Hello from backend1 at 198.51.100.41&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;curl&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;198&lt;/span&gt;.51.100.42
&lt;span class="go"&gt;Hello from backend3 at 203.0.113.74&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Our backends take turns serving the requests. Just what we wanted.&lt;/p&gt;
&lt;p&gt;Now that the load balancers proxy the requests to backends,
there is no need to keep the port 80 on the backends open to the entire world.
We can easily change the configuration to only allow connections to this port
on the internal network.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;diff --git a/part2/network.nix b/part2/network.nix
index 5fa3925..d3f5cca 100644
--- a/part2/network.nix
+++ b/part2/network.nix
@@ -12,11 +12,11 @@ let
     deployment.targetHost = resource.values.ipv4_address;
     deployment.targetUser = &amp;quot;root&amp;quot;;
     networking.hostName = resource.values.name;
     system.stateVersion = &amp;quot;21.11&amp;quot;;

-    networking.firewall.allowedTCPPorts = [ 80 ];
+    networking.firewall.interfaces.ens4.allowedTCPPorts = [ 80 ];
     services.nginx = {
       enable = true;
       virtualHosts.default = {
         default = true;
         locations.&amp;quot;/&amp;quot;.return = &amp;quot;200 \&amp;quot;Hello from ${name} at ${resource.values.ipv4_address}\&amp;quot;&amp;quot;;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;DigitalOcean seems to always have the external network on interface &lt;code&gt;ens3&lt;/code&gt;,
meanwhile the internal interface is named &lt;code&gt;ens4&lt;/code&gt;, but do check on your own just to be sure!&lt;/p&gt;
&lt;p&gt;Once again, let's redeploy and see that our cluster still works after the changes:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;morph&lt;span class="w"&gt; &lt;/span&gt;deploy&lt;span class="w"&gt; &lt;/span&gt;network.nix&lt;span class="w"&gt; &lt;/span&gt;switch
&lt;span class="go"&gt;&amp;lt;...snip...&amp;gt;&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;curl&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;198&lt;/span&gt;.51.100.42
&lt;span class="go"&gt;Hello from backend2 at 198.51.100.36&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;By this point, we have a network of NixOS machines, managed by Terraform,
with Morph using the Terraform state to
deploy the relevant configuration to each machine according to its role.&lt;/p&gt;
&lt;h1 id="finishing-touches"&gt;Finishing touches&lt;/h1&gt;
&lt;p&gt;To cut down on the noise, we can also move the common properties
into a separate &lt;a href="https://nixos.wiki/wiki/Module"&gt;NixOS module&lt;/a&gt;.
Create a file named &lt;code&gt;common.nix&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt; modulesPath&lt;span class="p"&gt;,&lt;/span&gt; lib&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="ss"&gt;imports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; lib&lt;span class="o"&gt;.&lt;/span&gt;optional &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;builtins&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;pathExists &lt;span class="l"&gt;./do-userdata.nix&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="l"&gt;./do-userdata.nix&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;modulesPath &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/virtualisation/digital-ocean-config.nix&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;];&lt;/span&gt;

  deployment&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;targetUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;root&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  system&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;stateVersion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;21.11&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then, remove these properties from your individual machine definitions,
instead, importing the newly created module:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gh"&gt;diff --git a/part2/network.nix b/part2/network.nix&lt;/span&gt;
&lt;span class="gh"&gt;index d3f5cca..1dc7801 100644&lt;/span&gt;
&lt;span class="gd"&gt;--- a/part2/network.nix&lt;/span&gt;
&lt;span class="gi"&gt;+++ b/part2/network.nix&lt;/span&gt;
&lt;span class="gu"&gt;@@ -5,14 +5,11 @@ let&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;  backends = builtins.filter (d: d.name == &amp;quot;backend&amp;quot;) droplets;
&lt;span class="w"&gt; &lt;/span&gt;  loadbalancers = builtins.filter (d: d.name == &amp;quot;loadbalancer&amp;quot;) droplets;

&lt;span class="gd"&gt;-  mkBackend = resource: { modulesPath, lib, name, ... }: {&lt;/span&gt;
&lt;span class="gd"&gt;-    imports = lib.optional (builtins.pathExists ./do-userdata.nix) ./do-userdata.nix ++ [&lt;/span&gt;
&lt;span class="gd"&gt;-      (modulesPath + &amp;quot;/virtualisation/digital-ocean-config.nix&amp;quot;)&lt;/span&gt;
&lt;span class="gd"&gt;-    ];&lt;/span&gt;
&lt;span class="gi"&gt;+  mkBackend = resource: { name, ... }: {&lt;/span&gt;
&lt;span class="gi"&gt;+    imports = [ ./common.nix ];&lt;/span&gt;
&lt;span class="gi"&gt;+&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;    deployment.targetHost = resource.values.ipv4_address;
&lt;span class="gd"&gt;-    deployment.targetUser = &amp;quot;root&amp;quot;;&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;    networking.hostName = resource.values.name;
&lt;span class="gd"&gt;-    system.stateVersion = &amp;quot;21.11&amp;quot;;&lt;/span&gt;

&lt;span class="w"&gt; &lt;/span&gt;    networking.firewall.interfaces.ens4.allowedTCPPorts = [ 80 ];
&lt;span class="w"&gt; &lt;/span&gt;    services.nginx = {
&lt;span class="gu"&gt;@@ -24,14 +21,11 @@ let&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;    };
&lt;span class="w"&gt; &lt;/span&gt;  };

&lt;span class="gd"&gt;-  mkLoadBalancer = resource: { modulesPath, lib, name, ... }: {&lt;/span&gt;
&lt;span class="gd"&gt;-    imports = lib.optional (builtins.pathExists ./do-userdata.nix) ./do-userdata.nix ++ [&lt;/span&gt;
&lt;span class="gd"&gt;-      (modulesPath + &amp;quot;/virtualisation/digital-ocean-config.nix&amp;quot;)&lt;/span&gt;
&lt;span class="gd"&gt;-    ];&lt;/span&gt;
&lt;span class="gi"&gt;+  mkLoadBalancer = resource: { name, ... }: {&lt;/span&gt;
&lt;span class="gi"&gt;+    imports = [ ./common.nix ];&lt;/span&gt;
&lt;span class="gi"&gt;+&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;    deployment.targetHost = resource.values.ipv4_address;
&lt;span class="gd"&gt;-    deployment.targetUser = &amp;quot;root&amp;quot;;&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;    networking.hostName = resource.values.name;
&lt;span class="gd"&gt;-    system.stateVersion = &amp;quot;21.11&amp;quot;;&lt;/span&gt;

&lt;span class="w"&gt; &lt;/span&gt;    networking.firewall.allowedTCPPorts = [ 80 ];
&lt;span class="w"&gt; &lt;/span&gt;    services.nginx = {
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Again, you can find the full code in a
&lt;a href="https://github.com/justinas/nixos-cloud"&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;
&lt;h1 id="thats-all-for-now-folks"&gt;That's all (for now), folks&lt;/h1&gt;
&lt;p&gt;Having done all that, we have a network of cloud servers on DigitalOcean,
which we can both bootstrap and deploy services on according to the configuration
written in Terraform and Nix.&lt;/p&gt;
&lt;p&gt;These two posts cover most of the tools and workflows
I use to manage my personal infrastructure.
While there are individual nuggets of Nix knowledge I have not shared yet,
I do not think these warrant a full blog article right now.&lt;/p&gt;
&lt;p&gt;One area that would be interesting to see explored
is writing Terraform definitions using Nix.
As Terraform &lt;a href="https://www.terraform.io/docs/configuration/syntax-json.html"&gt;supports pure JSON&lt;/a&gt;
as an alternative to its own configuration language,
and Nix can both parse and generate JSON,
this does not seem impossible.
However, I do not immediately see any inherent value or ergonomic improvements in this.
Perhaps that shall remain a challenge for another time (or person).&lt;/p&gt;
&lt;p&gt;With that said, I hope you learned something. Good luck on your NixOS adventures!&lt;/p&gt;
&lt;h1 id="alternative-approaches"&gt;Alternative approaches&lt;/h1&gt;
&lt;p&gt;There exist alternative approaches of managing your infrastructure
and deployments using Nix.&lt;/p&gt;
&lt;p&gt;For one, NixOps 1.7 is
&lt;a href="https://releases.nixos.org/nixops/nixops-1.7/manual/manual.html#sec-deploying-to-digital-ocean"&gt;able to spawn DigitalOcean machines directly&lt;/a&gt;.
However, as mentioned in the first part, NixOps is a moving target.
For version 2.0, the external providers are being moved to their own repositories.
There are also significant limitations, e.g.:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Note that we rely on a ssh key resource with the hard-coded name &lt;code&gt;ssh-key&lt;/code&gt;. Providing your own key is not supported yet.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Using the DigitalOcean provider with Terraform will give you far more flexibility,
allowing you to manage not only your machines, but domain records,
attached storage, and other sorts of resources as well.&lt;/p&gt;
&lt;p&gt;There is also a dedicated Terraform module for deploying NixOS machines,
as described by &lt;a href="https://nix.dev/tutorials/deploying-nixos-using-terraform.html"&gt;a tutorial on nix.dev&lt;/a&gt;.
To be completely honest, I was not aware of this until I had mostly written part 1,
and have not tried it for myself.
For my needs, a setup where each tool has its own set of responsibilities -
Terraform for infrastructure management and Morph or NixOps for configuration management -
works well.&lt;/p&gt;</content><category term="Linux"/></entry><entry><title>NixOS in the Cloud, step-by-step: part 1</title><link href="https://justinas.org/nixos-in-the-cloud-step-by-step-part-1" rel="alternate"/><published>2020-12-28T16:30:00+00:00</published><updated>2020-12-28T16:30:00+00:00</updated><author><name>Justinas Stankevičius</name></author><id>tag:justinas.org,2020-12-28:/nixos-in-the-cloud-step-by-step-part-1</id><summary type="html">&lt;p&gt;In the last few months, I migrated both my workstation
and my servers (a DigitalOcean VPS and a Raspberry Pi 3) to NixOS.
To best summarize the benefits, let's just say that it's like
having a "dotfiles" repo, but for your entire system (or multiple!),
including custom software, service configuration …&lt;/p&gt;</summary><content type="html">&lt;p&gt;In the last few months, I migrated both my workstation
and my servers (a DigitalOcean VPS and a Raspberry Pi 3) to NixOS.
To best summarize the benefits, let's just say that it's like
having a "dotfiles" repo, but for your entire system (or multiple!),
including custom software, service configuration, drivers, kernel tweaks, etc.&lt;/p&gt;
&lt;p&gt;While a similar result could be achieved by more mainstream configuration management tools,
such as Puppet or Ansible, they do not integrate deeply into your OS.
As such, over a longer period it's likely for your system to accumulate
all sorts of manual tweaks done outside of your configuration management framework.
The system's configuration is not fully described by your declarative configuration anymore
and you will likely not reproduce the system exactly if you have to recreate it from scratch.&lt;/p&gt;
&lt;p&gt;NixOS treats the system as mostly immutable
and makes it &lt;em&gt;way&lt;/em&gt; harder to mess something up:
you can't just edit the files under &lt;code&gt;/etc&lt;/code&gt; 
or upgrade globally installed packages by hand.
Most meaningful changes you'll only be able to do via edits to &lt;code&gt;configuration.nix&lt;/code&gt;
and &lt;code&gt;nixos-rebuild switch&lt;/code&gt;,
which replaces the entire system with a new &lt;em&gt;generation&lt;/em&gt;.
This also provides an ability to rollback everything easily and effectively,
which conventional tools often lack or implement incompletely.&lt;/p&gt;
&lt;h1 id="why-this-article-was-made"&gt;Why this article was made&lt;/h1&gt;
&lt;p&gt;Despite the situation getting progressively better,
while learning Nix and NixOS I still felt like some parts of the stack are under-documented.
While there are extensive resources such as the
&lt;a href="https://nixos.org/manual/nixos/stable/"&gt;NixOS manual&lt;/a&gt;,
&lt;a href="https://nixos.org/guides/nix-pills/"&gt;Nix pills&lt;/a&gt;, or
&lt;a href="https://nix.dev/"&gt;nix.dev&lt;/a&gt;;
what I lacked the most was &lt;em&gt;how-tos&lt;/em&gt; or &lt;em&gt;recipes&lt;/em&gt;
which would show how to connect the tools
to achieve your desired goal.
Time and time again, I had to resort to reading others'
configurations and the source code
in the &lt;a href="https://github.com/nixos/nixpkgs"&gt;nixpkgs&lt;/a&gt; repository.&lt;/p&gt;
&lt;p&gt;This series of articles intends to fill this niche somewhat.
Most of these methods are the same ones I use to run my own
"private cloud". My own infrastructure is quite pedestrian -
I only run a few services, including hosting my websites and email -
so it's not exactly a guide for "enterprise battle-tested infrastructure".
However, once I nailed the process down, I have definitely had a pleasant experience,
and my current setup is definitely satisfactory for my needs.&lt;/p&gt;
&lt;h1 id="who-this-is-for"&gt;Who this is for&lt;/h1&gt;
&lt;p&gt;If you - like me a while ago - are getting into Nix / NixOS,
but still struggling to put your newly-acquired knowledge to use,
you've come to the right place.&lt;/p&gt;
&lt;p&gt;I do not intend to teach the core concepts of Nix or the basics of the expression language.
The aforementioned resources should get you up and running if you are a complete newbie.
Instead, I'll focus on one specific use case - deploying a cloud server
running NixOS and managing its configuration from your own workstation.&lt;/p&gt;
&lt;p&gt;In this article, we will learn how to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Generate a custom NixOS image for DigitalOcean&lt;/li&gt;
&lt;li&gt;Create a virtual NixOS server on the cloud&lt;/li&gt;
&lt;li&gt;Deploy nginx on the server using &lt;a href="https://github.com/DBCDK/morph"&gt;Morph&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Before we begin, let's go over the tools we'll need one by one.&lt;/p&gt;
&lt;h2 id="nix"&gt;Nix&lt;/h2&gt;
&lt;p&gt;You should either be running &lt;a href="https://nixos.org/"&gt;NixOS&lt;/a&gt;,
or have &lt;a href="https://nixos.org/download.html#nix-quick-install"&gt;Nix&lt;/a&gt;
installed under your preferred Linux distribution.&lt;/p&gt;
&lt;p&gt;Again, I assume you have the basic gist of the Nix language.
Basically, if you've written at least one Nix derivation,
or played around with your &lt;code&gt;configuration.nix&lt;/code&gt;,
you should be fine.&lt;/p&gt;
&lt;h2 id="digitalocean"&gt;DigitalOcean&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.digitalocean.com/"&gt;DigitalOcean&lt;/a&gt; is a cloud hosting provider.
I chose it simply because it is the provider I have been using for the past several years.
It works well for me and allows custom images, which is gonna be really important soon.&lt;/p&gt;
&lt;p&gt;If you'd like to, you can sign up on DigitalOcean through my
&lt;a href="https://m.do.co/c/048e6d3c0501"&gt;referral&amp;nbsp;link&lt;/a&gt;
and get $100 credit to use freely for 60 days.&lt;/p&gt;
&lt;h2 id="morph"&gt;Morph&lt;/h2&gt;
&lt;p&gt;Morph is a tool that allows deploying NixOS machines remotely
as easily as you could update your own machine's configuration.&lt;/p&gt;
&lt;p&gt;There are multiple competing NixOS deployment tools,
including the &lt;em&gt;official&lt;/em&gt; &lt;a href="https://github.com/NixOS/nixops"&gt;NixOps&lt;/a&gt;,
rival &lt;a href="https://github.com/DBCDK/morph"&gt;Morph&lt;/a&gt;,
and a new contender called &lt;a href="https://github.com/zhaofengli/colmena"&gt;Colmena&lt;/a&gt;.
So, why choose Morph specifically?&lt;/p&gt;
&lt;p&gt;As Morph's README states, it and similar tools are:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;basically fancy wrapper[s] around &lt;code&gt;nix-build&lt;/code&gt;, &lt;code&gt;nix copy&lt;/code&gt;, &lt;code&gt;nix-env&lt;/code&gt;, &lt;code&gt;switch-to-configuration&lt;/code&gt;, &lt;code&gt;scp&lt;/code&gt; and more&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Thus it does not matter that much which tool we use, as all of these tools:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use the Nix language itself to define your configuration&lt;/li&gt;
&lt;li&gt;Use similar Nix-native methods for the deployment process itself&lt;/li&gt;
&lt;li&gt;Have a similar layout for the network expressions&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Most things you'll learn from this series will be applicable
to any of these tools.&lt;/p&gt;
&lt;p&gt;As NixOps is currently in the flux somewhere between version 1.7 and 2.0,
where 2.0 adds important features, but does not have a stable release yet,
it is hard to recommend (although I do use its &lt;code&gt;master&lt;/code&gt; branch personally).
Colmena might get there soon, as it gains features and polish, but for now,
Morph seems like the best alternative.&lt;/p&gt;
&lt;p&gt;In particular, Morph has a couple of features I really like.
The first is allowing to easily pin a specific version of nixpkgs for your machines. 
The second is being completely stateless:
unlike NixOps, it does not manage a set of deployments in a hidden file
somewhere in your home directory.
Instead, it does only what you explicitly tell it to do -
deploy to machines specified in your &lt;code&gt;.nix&lt;/code&gt; file.&lt;/p&gt;
&lt;h1 id="preparation"&gt;Preparation&lt;/h1&gt;
&lt;p&gt;Enough bikeshedding, let's get down to business.
We will need a few things before we are ready.&lt;/p&gt;
&lt;h2 id="nix-shell"&gt;nix-shell&lt;/h2&gt;
&lt;p&gt;Let's make a new folder to fit all of our stuff in:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;mkdir&lt;span class="w"&gt; &lt;/span&gt;part1&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;part1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then, let's define a new shell that will provide the &lt;code&gt;morph&lt;/code&gt; package,
as well as &lt;code&gt;curl&lt;/code&gt; which we will use to query our newly deployed web server.
Put this in a new file called &lt;code&gt;shell.nix&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt; pkgs &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="l"&gt;&amp;lt;nixpkgs&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt;
pkgs&lt;span class="o"&gt;.&lt;/span&gt;mkShell &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="ss"&gt;buildInputs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; pkgs&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; curl morph &lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then enter the shell and you should be able to launch both tools:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;nix-shell
&lt;span class="gp"&gt;$ &lt;/span&gt;curl&lt;span class="w"&gt; &lt;/span&gt;--version&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;head&lt;span class="w"&gt; &lt;/span&gt;-n&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;
&lt;span class="go"&gt;curl 7.72.0 (x86_64-pc-linux-gnu) libcurl/7.72.0 OpenSSL/1.1.1i zlib/1.2.11 libssh2/1.9.0 nghttp2/1.41.0&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;morph&lt;span class="w"&gt; &lt;/span&gt;--version
&lt;span class="go"&gt;1.5.0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Great success!&lt;/p&gt;
&lt;h2 id="preparing-your-digitalocean-project"&gt;Preparing your DigitalOcean project&lt;/h2&gt;
&lt;h3 id="custom-image"&gt;Custom image&lt;/h3&gt;
&lt;p&gt;Besides supporting major distributions out-of-the-box,
DigitalOcean also supports custom disk images,
which means you can run basically any OS.
We will use the &lt;a href="https://github.com/NixOS/nixpkgs/pull/66978"&gt;DO image generation functionality&lt;/a&gt;
in nixpkgs to generate one of our own.&lt;/p&gt;
&lt;p&gt;Put this in a new file called &lt;code&gt;image.nix&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt; pkgs &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="l"&gt;&amp;lt;nixpkgs&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="ss"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="ss"&gt;imports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="l"&gt;&amp;lt;nixpkgs/nixos/modules/virtualisation/digital-ocean-image.nix&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;in&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;pkgs&lt;span class="o"&gt;.&lt;/span&gt;nixos config&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;digitalOceanImage
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then execute:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;nix-build&lt;span class="w"&gt; &lt;/span&gt;image.nix
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This may take several minutes. Do not worry, we'll only need to do this once.
Once the build has finished,
you should have a new file under the newly created &lt;code&gt;result/&lt;/code&gt; directory:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;ls&lt;span class="w"&gt; &lt;/span&gt;-sh&lt;span class="w"&gt; &lt;/span&gt;result/*
&lt;span class="go"&gt;390M result/nixos.qcow2.gz&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;A custom image has been built! You can now &lt;a href="https://www.digitalocean.com/docs/images/custom-images/quickstart/"&gt;upload this image to your DigitalOcean account&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="ssh-key"&gt;SSH key&lt;/h3&gt;
&lt;p&gt;You should also &lt;a href="https://www.digitalocean.com/docs/droplets/how-to/add-ssh-keys/to-account/"&gt;upload your SSH public key&lt;/a&gt;.
The custom image we just generated has a hidden superpower:
it automatically pulls in the public SSH keys from your DigitalOcean account at creation time.
This will let us login via SSH without needing to create a root password.&lt;/p&gt;
&lt;h3 id="create-your-nixos-droplet"&gt;Create your NixOS droplet!&lt;/h3&gt;
&lt;p&gt;Finally, &lt;a href="https://www.digitalocean.com/docs/droplets/how-to/create/"&gt;we can create a droplet&lt;/a&gt;
(that's what Digital Ocean calls virtual servers).&lt;/p&gt;
&lt;p&gt;A few things to note:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Remember to choose your custom image, called &lt;code&gt;nixos.qcow2.gz&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Remember to enable your SSH key under the "Authentication" section.
  For me, the checkbox was checked by default&lt;/li&gt;
&lt;li&gt;I named my droplet &lt;code&gt;nixie&lt;/code&gt;.  Doing the same will make it easier to follow along&lt;/li&gt;
&lt;li&gt;Feel free to choose the smallest ($5/month) flavor. We will not need anything too powerful&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You are charged for all of your droplets hourly, even if they are turned off,
so remember to destroy anything you do not need anymore in order to not rack up a huge bill.&lt;/p&gt;
&lt;h3 id="verify"&gt;Verify&lt;/h3&gt;
&lt;p&gt;Once the droplet has been created, you will see its IP address on the dashboard.
Let's try to connect.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;ssh&lt;span class="w"&gt; &lt;/span&gt;root@198.51.100.207
&lt;span class="go"&gt;The authenticity of host &amp;#39;198.51.100.207 (198.51.100.207)&amp;#39; can&amp;#39;t be established.&lt;/span&gt;
&lt;span class="go"&gt;ED25519 key fingerprint is SHA256:MtP743nmdmL59nJYYeGrvJVw8sNkqpQGvl2yyD5PMOA.&lt;/span&gt;
&lt;span class="go"&gt;Are you sure you want to continue connecting (yes/no/[fingerprint])? yes&lt;/span&gt;
&lt;span class="go"&gt;Warning: Permanently added &amp;#39;198.51.100.207&amp;#39; (ED25519) to the list of known hosts.&lt;/span&gt;

&lt;span class="gp"&gt;[root@nixie:~]# &lt;/span&gt;nixos-version
&lt;span class="go"&gt;20.09.2290.647cc06986c (Nightingale)&lt;/span&gt;
&lt;span class="gp"&gt;[root@nixie:~]# &lt;/span&gt;&lt;span class="nb"&gt;exit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Works fine!&lt;/p&gt;
&lt;p&gt;Note: this initial NixOS version will depend on your workstation's version of nixpkgs.
This is not an ideal situation, but it works fine for provisioning.
We will solve this later on.&lt;/p&gt;
&lt;p&gt;The custom image we built the droplet from has some important
directives in its initial &lt;code&gt;configuration.nix&lt;/code&gt;.
Let's retrieve this file for later use:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;scp&lt;span class="w"&gt; &lt;/span&gt;root@198.51.100.207:/etc/nixos/configuration.nix&lt;span class="w"&gt; &lt;/span&gt;.
&lt;span class="gp"&gt;$ &lt;/span&gt;chmod&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;644&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;configuration.nix&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;# scp keeps the original 444 permissions, but we will need to edit this file&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h1 id="managing-the-droplet-with-morph"&gt;Managing the droplet with Morph&lt;/h1&gt;
&lt;p&gt;When using NixOS on your machine, you edit your configuration in &lt;code&gt;/etc/nixos/configuration.nix&lt;/code&gt;
and activate it via &lt;code&gt;sudo nixos-rebuild switch&lt;/code&gt;.
However, this "every machine governs itself" model will not scale gracefully
as you add remote hosts, especially if the amount of them grows large.
Instead, we would like to have all the configuration in one place
(a Git repo works well) and be able to push out configuration changes
from our workstation to all of these machines using a tool like Morph.&lt;/p&gt;
&lt;p&gt;However, this approach leaves &lt;code&gt;/etc/nixos/configuration.nix&lt;/code&gt; behind.
Your system is now running whatever Morph has built the system from, and only that.&lt;/p&gt;
&lt;p&gt;As the custom image we generated contains important stuff to run the system
on a DigitalOcean droplets, such as bootloader and hard disk configuration,
we will need to keep that when moving to Morph.&lt;/p&gt;
&lt;p&gt;Let's check what's inside of the current configuration we've downloaded:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;configuration.nix
&lt;span class="go"&gt;{ modulesPath, lib, ... }:&lt;/span&gt;
&lt;span class="go"&gt;{&lt;/span&gt;
&lt;span class="go"&gt;  imports = lib.optional (builtins.pathExists ./do-userdata.nix) ./do-userdata.nix ++ [&lt;/span&gt;
&lt;span class="go"&gt;    (modulesPath + &amp;quot;/virtualisation/digital-ocean-config.nix&amp;quot;)&lt;/span&gt;
&lt;span class="go"&gt;  ];&lt;/span&gt;
&lt;span class="go"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Seems a bit short? That's because everything important is
hidden away in the &lt;code&gt;digital-ocean-config.nix&lt;/code&gt; import.
If you are interested what it looks like under the hood, feel free to
&lt;a href="https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/virtualisation/digital-ocean-config.nix"&gt;read the source code in nixpkgs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For now though, we will rename it to use as a basis for our deployment specification.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;mv&lt;span class="w"&gt; &lt;/span&gt;configuration.nix&lt;span class="w"&gt; &lt;/span&gt;network.nix
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Open this file, now called &lt;code&gt;network.nix&lt;/code&gt; in your favorite editor.
We will do a few small edits to make it look like this instead:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="ss"&gt;nixie&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; modulesPath&lt;span class="p"&gt;,&lt;/span&gt; lib&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="ss"&gt;imports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; lib&lt;span class="o"&gt;.&lt;/span&gt;optional &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;builtins&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;pathExists &lt;span class="l"&gt;./do-userdata.nix&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="l"&gt;./do-userdata.nix&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;modulesPath &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/virtualisation/digital-ocean-config.nix&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;];&lt;/span&gt;

    deployment&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;targetHost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;198.51.100.207&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    deployment&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;targetUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;root&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Whereas previously we've had the function as the only thing in a file,
now the top level value is a set with one key &lt;code&gt;nixie&lt;/code&gt; pointing to this function.
This is how Morph and similar tools define your servers:
one key means one machine to deploy to,
and the corresponding value is a function that generates that machine's system configuration,
just like the one that might exist in your NixOS workstation's &lt;code&gt;configuration.nix&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Besides that, we added important Morph-specific options:
the address of the host to deploy to and the user to connect as.&lt;/p&gt;
&lt;p&gt;Let's try to deploy now:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;morph&lt;span class="w"&gt; &lt;/span&gt;deploy&lt;span class="w"&gt; &lt;/span&gt;network.nix&lt;span class="w"&gt; &lt;/span&gt;switch
&lt;span class="go"&gt;Selected 1/1 hosts (name filter:-0, limits:-0):&lt;/span&gt;
&lt;span class="go"&gt;          0: nixie (secrets: 0, health checks: 0)&lt;/span&gt;

&lt;span class="go"&gt;error: The option `networking.hostName&amp;#39; has conflicting definitions, in `/nix/store/p3bjy5vfknzn1dxq72gb8wwa33bs7hfr-nixos/nixos/modules/virtualisation/digital-ocean-config.nix&amp;#39; and `&amp;lt;unknown-file&amp;gt;&amp;#39;.&lt;/span&gt;
&lt;span class="go"&gt;&amp;lt;...snip...&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Oops! It seems that the hostname Morph tries to configure automatically
conflicts with what is defined in &lt;code&gt;digital-ocean-config.nix&lt;/code&gt;.
We can fix that by defining it manually in &lt;code&gt;network.nix&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gh"&gt;diff --git a/part1/network.nix b/part1/network.nix&lt;/span&gt;
&lt;span class="gh"&gt;index 52e8932..02db4f2 100755&lt;/span&gt;
&lt;span class="gd"&gt;--- a/part1/network.nix&lt;/span&gt;
&lt;span class="gi"&gt;+++ b/part1/network.nix&lt;/span&gt;
&lt;span class="gu"&gt;@@ -1,10 +1,12 @@&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;{
&lt;span class="gd"&gt;-  nixie = { modulesPath, lib, ... }: {&lt;/span&gt;
&lt;span class="gi"&gt;+  nixie = { modulesPath, lib, name, ... }: {&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;    imports = lib.optional (builtins.pathExists ./do-userdata.nix) ./do-userdata.nix ++ [
&lt;span class="w"&gt; &lt;/span&gt;      (modulesPath + &amp;quot;/virtualisation/digital-ocean-config.nix&amp;quot;)
&lt;span class="w"&gt; &lt;/span&gt;    ];

&lt;span class="w"&gt; &lt;/span&gt;    deployment.targetHost = &amp;quot;198.51.100.207&amp;quot;;
&lt;span class="w"&gt; &lt;/span&gt;    deployment.targetUser = &amp;quot;root&amp;quot;;
&lt;span class="gi"&gt;+&lt;/span&gt;
&lt;span class="gi"&gt;+    networking.hostName = name;&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;  };
&lt;span class="w"&gt; &lt;/span&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;For those not fluent in patches, this is what our &lt;code&gt;network.nix&lt;/code&gt; looks like so far:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="ss"&gt;nixie&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; modulesPath&lt;span class="p"&gt;,&lt;/span&gt; lib&lt;span class="p"&gt;,&lt;/span&gt; name&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="ss"&gt;imports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; lib&lt;span class="o"&gt;.&lt;/span&gt;optional &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;builtins&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;pathExists &lt;span class="l"&gt;./do-userdata.nix&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="l"&gt;./do-userdata.nix&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;modulesPath &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/virtualisation/digital-ocean-config.nix&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;];&lt;/span&gt;

    deployment&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;targetHost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;198.51.100.207&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    deployment&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;targetUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;root&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    networking&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;hostName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; name&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The new parameter &lt;code&gt;name&lt;/code&gt; that we added to the function definition
will be filled out with the same value as the key, in this case, &lt;code&gt;"nixie"&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Let's try deploying again:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;morph&lt;span class="w"&gt; &lt;/span&gt;deploy&lt;span class="w"&gt; &lt;/span&gt;network.nix&lt;span class="w"&gt; &lt;/span&gt;switch
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The first deployment will likely take a while.
However, on the following deployments, only the parts that changed,
e.g. newly added or updated packages, or daemon configuration files, will be rebuilt.&lt;/p&gt;
&lt;p&gt;The output of Morph will look like something this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;Selected 1/1 hosts (name filter:-0, limits:-0):
          0: nixie (secrets: 0, health checks: 0)

&amp;lt;...snip...&amp;gt;

Executing &amp;#39;switch&amp;#39; on matched hosts:

** nixie

&amp;lt;...snip...&amp;gt;

Running healthchecks on nixie (198.51.100.207):
Health checks OK
Done: nixie
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Finally some payoff!&lt;/p&gt;
&lt;h2 id="deploying-nginx"&gt;Deploying nginx&lt;/h2&gt;
&lt;p&gt;At last, it's time to deploy something more than just an empty system.
We will now make these changes to our configuration:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Enable the nginx HTTP server&lt;/li&gt;
&lt;li&gt;Add a default virtual host and a simple "OK" response to HTTP requests&lt;/li&gt;
&lt;li&gt;Add a &lt;a href="https://github.com/DBCDK/morph#health-checks"&gt;health check&lt;/a&gt; that Morph will use to ensure nginx is working properly&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gh"&gt;diff --git a/part1/network.nix b/part1/network.nix&lt;/span&gt;
&lt;span class="gh"&gt;index 02db4f2..8ab724a 100755&lt;/span&gt;
&lt;span class="gd"&gt;--- a/part1/network.nix&lt;/span&gt;
&lt;span class="gi"&gt;+++ b/part1/network.nix&lt;/span&gt;
&lt;span class="gu"&gt;@@ -8,5 +8,24 @@&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;    deployment.targetUser = &amp;quot;root&amp;quot;;

&lt;span class="w"&gt; &lt;/span&gt;    networking.hostName = name;
&lt;span class="gi"&gt;+&lt;/span&gt;
&lt;span class="gi"&gt;+    deployment.healthChecks = {&lt;/span&gt;
&lt;span class="gi"&gt;+      http = [&lt;/span&gt;
&lt;span class="gi"&gt;+        {&lt;/span&gt;
&lt;span class="gi"&gt;+          scheme = &amp;quot;http&amp;quot;;&lt;/span&gt;
&lt;span class="gi"&gt;+          port = 80;&lt;/span&gt;
&lt;span class="gi"&gt;+          path = &amp;quot;/&amp;quot;;&lt;/span&gt;
&lt;span class="gi"&gt;+          description = &amp;quot;check that nginx is running&amp;quot;;&lt;/span&gt;
&lt;span class="gi"&gt;+        }&lt;/span&gt;
&lt;span class="gi"&gt;+      ];&lt;/span&gt;
&lt;span class="gi"&gt;+    };&lt;/span&gt;
&lt;span class="gi"&gt;+&lt;/span&gt;
&lt;span class="gi"&gt;+    services.nginx = {&lt;/span&gt;
&lt;span class="gi"&gt;+      enable = true;&lt;/span&gt;
&lt;span class="gi"&gt;+      virtualHosts.default = {&lt;/span&gt;
&lt;span class="gi"&gt;+        default = true;&lt;/span&gt;
&lt;span class="gi"&gt;+        locations.&amp;quot;/&amp;quot;.return = &amp;quot;200 \&amp;quot;Hello from Nixie!\&amp;quot;&amp;quot;;&lt;/span&gt;
&lt;span class="gi"&gt;+      };&lt;/span&gt;
&lt;span class="gi"&gt;+    };&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;  };
&lt;span class="w"&gt; &lt;/span&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Time to deploy again!&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;morph&lt;span class="w"&gt; &lt;/span&gt;deploy&lt;span class="w"&gt; &lt;/span&gt;network.nix&lt;span class="w"&gt; &lt;/span&gt;switch
&lt;span class="go"&gt;Selected 1/1 hosts (name filter:-0, limits:-0):&lt;/span&gt;
&lt;span class="go"&gt;          0: nixie (secrets: 0, health checks: 1)&lt;/span&gt;
&lt;span class="go"&gt;&amp;lt;...snip...&amp;gt;&lt;/span&gt;
&lt;span class="go"&gt;Running healthchecks on nixie (198.51.100.207):&lt;/span&gt;
&lt;span class="go"&gt;        * check that nginx is running: Failed (Get &amp;quot;http://198.51.100.207:80/&amp;quot;: context deadline exceeded (Client.Timeout exceeded while awaiting headers))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Uh oh. Our health check is failing. Can you spot the issue?
An experienced NixOS-er will immediately tell what's wrong:
by default, NixOS has firewall enabled and we have not specified that we want
to open the port 80. Let's fix that:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gh"&gt;diff --git a/part1/network.nix b/part1/network.nix&lt;/span&gt;
&lt;span class="gh"&gt;index 8ab724a..ff078d3 100755&lt;/span&gt;
&lt;span class="gd"&gt;--- a/part1/network.nix&lt;/span&gt;
&lt;span class="gi"&gt;+++ b/part1/network.nix&lt;/span&gt;
&lt;span class="gu"&gt;@@ -20,6 +20,8 @@&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;      ];
&lt;span class="w"&gt; &lt;/span&gt;    };

&lt;span class="gi"&gt;+    networking.firewall.allowedTCPPorts = [ 80 ];&lt;/span&gt;
&lt;span class="gi"&gt;+&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;    services.nginx = {
&lt;span class="w"&gt; &lt;/span&gt;      enable = true;
&lt;span class="w"&gt; &lt;/span&gt;      virtualHosts.default = {
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And try our deployment one more time:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;morph&lt;span class="w"&gt; &lt;/span&gt;deploy&lt;span class="w"&gt; &lt;/span&gt;network.nix&lt;span class="w"&gt; &lt;/span&gt;switch
&lt;span class="go"&gt;Selected 1/1 hosts (name filter:-0, limits:-0):&lt;/span&gt;
&lt;span class="go"&gt;          0: nixie (secrets: 0, health checks: 1)&lt;/span&gt;

&lt;span class="go"&gt;&amp;lt;...snip...&amp;gt;&lt;/span&gt;

&lt;span class="go"&gt;Running healthchecks on nixie (198.51.100.207):&lt;/span&gt;
&lt;span class="go"&gt;        * check that nginx is running: OK&lt;/span&gt;
&lt;span class="go"&gt;Health checks OK&lt;/span&gt;
&lt;span class="go"&gt;Done: nixie&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Seems to pass now. Might as well check it via curl, just to be sure:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;curl&lt;span class="w"&gt; &lt;/span&gt;http://198.51.100.207
&lt;span class="go"&gt;Hello from Nixie!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Yay! We have an nginx instance running on our NixOS server.&lt;/p&gt;
&lt;h2 id="pinning-nixpkgs"&gt;Pinning nixpkgs&lt;/h2&gt;
&lt;p&gt;As mentioned before, currently the server's NixOS version
depends on the version of Nixpkgs in your local workstation.
That is not always the best idea: for example, you might want to run your workstation
on the bleeding edge by using &lt;code&gt;nixpkgs-unstable&lt;/code&gt;,
but keep your servers on a more stable channel.&lt;/p&gt;
&lt;p&gt;Luckily, Morph allows us to change what version of nixpkgs is used
to deploy our network:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gh"&gt;diff --git a/part1/network.nix b/part1/network.nix&lt;/span&gt;
&lt;span class="gh"&gt;index e89b9b1..3643f5f 100755&lt;/span&gt;
&lt;span class="gd"&gt;--- a/part1/network.nix&lt;/span&gt;
&lt;span class="gi"&gt;+++ b/part1/network.nix&lt;/span&gt;
&lt;span class="gu"&gt;@@ -1,4 +1,15 @@&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;{
&lt;span class="gi"&gt;+  network = {&lt;/span&gt;
&lt;span class="gi"&gt;+    pkgs = import&lt;/span&gt;
&lt;span class="gi"&gt;+      (builtins.fetchGit {&lt;/span&gt;
&lt;span class="gi"&gt;+       name = &amp;quot;nixos-21.11-2021-12-19&amp;quot;;&lt;/span&gt;
&lt;span class="gi"&gt;+       url = &amp;quot;https://github.com/NixOS/nixpkgs&amp;quot;;&lt;/span&gt;
&lt;span class="gi"&gt;+       ref = &amp;quot;refs/heads/nixos-21.11&amp;quot;;&lt;/span&gt;
&lt;span class="gi"&gt;+       rev = &amp;quot;e6377ff35544226392b49fa2cf05590f9f0c4b43&amp;quot;;&lt;/span&gt;
&lt;span class="gi"&gt;+      })&lt;/span&gt;
&lt;span class="gi"&gt;+      { };&lt;/span&gt;
&lt;span class="gi"&gt;+  };&lt;/span&gt;
&lt;span class="gi"&gt;+&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;  nixie = { modulesPath, lib, name, ... }: {
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The following expression will check out the commit &lt;code&gt;e6377ff3&lt;/code&gt; from the &lt;code&gt;nixos-21.11&lt;/code&gt;
branch and use it as the basis for all of the machines in the network.
The &lt;code&gt;name&lt;/code&gt; is allowed to be an arbitrary string.
I use it to mark the date of the last update of the packages.&lt;/p&gt;
&lt;p&gt;Now, let's redeploy and check out what version we are running.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;morph&lt;span class="w"&gt; &lt;/span&gt;deploy&lt;span class="w"&gt; &lt;/span&gt;network.nix&lt;span class="w"&gt; &lt;/span&gt;switch
&lt;span class="go"&gt;&amp;lt;...snip...&amp;gt;&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;morph&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;network.nix&lt;span class="w"&gt; &lt;/span&gt;nixos-version
&lt;span class="go"&gt;Selected 1/1 hosts (name filter:-0, limits:-0):&lt;/span&gt;
&lt;span class="go"&gt;          0: nixie (secrets: 0, health checks: 1)&lt;/span&gt;

&lt;span class="go"&gt;** nixie&lt;/span&gt;
&lt;span class="go"&gt;21.11pre-git (Nightingale)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;While the default &lt;code&gt;nixos-version&lt;/code&gt; utility is not willing to return a commit hash,
we do see that we are running from a git checkout, rather than the version we observed before.
For more information on various nixpkgs channels, check out
&lt;a href="https://nixos.wiki/wiki/Nix_channels#The_official_channels"&gt;this page on the unofficial wiki&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="state-version"&gt;State version&lt;/h2&gt;
&lt;p&gt;It is also a good idea to explicitly set your &lt;code&gt;system.stateVersion&lt;/code&gt;.
I will refrain from explaining this option in depth,
as &lt;a href="https://nixos.wiki/wiki/FAQ/When_do_I_update_stateVersion"&gt;an explanation can be found&lt;/a&gt;
in the wiki.
Basically, some stateful services (e.g. &lt;a href="https://github.com/NixOS/nixpkgs/blob/2df221ec8a95566ba771f102fd421c12b41d875c/nixos/modules/services/databases/postgresql.nix#L281-L288"&gt;Postgres&lt;/a&gt;)
need manual intervention, such as data migration, when upgrading to a new major version.
&lt;code&gt;system.stateVersion&lt;/code&gt; prevents breakage that could result from
upgrading these packages without the necessary precautions:
the affected services will keep using compatible versions,
even if we upgrade our NixOS version to a new one.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gh"&gt;diff --git a/part1/network.nix b/part1/network.nix&lt;/span&gt;
&lt;span class="gh"&gt;index 3643f5f..04eedaf 100755&lt;/span&gt;
&lt;span class="gd"&gt;--- a/part1/network.nix&lt;/span&gt;
&lt;span class="gi"&gt;+++ b/part1/network.nix&lt;/span&gt;
&lt;span class="gu"&gt;@@ -20,6 +20,8 @@&lt;/span&gt;

&lt;span class="w"&gt; &lt;/span&gt;    networking.hostName = name;

&lt;span class="gi"&gt;+    system.stateVersion = &amp;quot;21.11&amp;quot;; # Do not change lightly!&lt;/span&gt;
&lt;span class="gi"&gt;+&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;    deployment.healthChecks = {
&lt;span class="w"&gt; &lt;/span&gt;      http = [
&lt;span class="w"&gt; &lt;/span&gt;        {
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h1 id="thats-it"&gt;That's it&lt;/h1&gt;
&lt;p&gt;Here's the finished &lt;code&gt;network.nix&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="ss"&gt;network&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="ss"&gt;pkgs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;builtins&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;fetchGit &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="ss"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;nixos-21.11-2021-12-19&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="ss"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;https://github.com/NixOS/nixpkgs&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="ss"&gt;ref&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;refs/heads/nixos-21.11&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="ss"&gt;rev&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;e6377ff35544226392b49fa2cf05590f9f0c4b43&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="ss"&gt;nixie&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; modulesPath&lt;span class="p"&gt;,&lt;/span&gt; lib&lt;span class="p"&gt;,&lt;/span&gt; name&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="ss"&gt;imports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; lib&lt;span class="o"&gt;.&lt;/span&gt;optional &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;builtins&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;pathExists &lt;span class="l"&gt;./do-userdata.nix&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="l"&gt;./do-userdata.nix&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;modulesPath &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/virtualisation/digital-ocean-config.nix&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;];&lt;/span&gt;

    deployment&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;targetHost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;198.51.100.207&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    deployment&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;targetUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;root&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    networking&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;hostName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; name&lt;span class="p"&gt;;&lt;/span&gt;

    system&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;stateVersion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;21.11&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;# Do not change lightly!&lt;/span&gt;

    deployment&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;healthChecks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="ss"&gt;http&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="ss"&gt;scheme&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;http&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="ss"&gt;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="ss"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="ss"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;check that nginx is running&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    networking&lt;span class="o"&gt;.&lt;/span&gt;firewall&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;allowedTCPPorts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt; &lt;span class="p"&gt;];&lt;/span&gt;

    services&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;nginx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="ss"&gt;enable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      virtualHosts&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;default&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="ss"&gt;default&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        locations&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;return&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;200 &lt;/span&gt;&lt;span class="se"&gt;\&amp;quot;&lt;/span&gt;&lt;span class="s2"&gt;Hello from Nixie!&lt;/span&gt;&lt;span class="se"&gt;\&amp;quot;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Let's recap. Using this process, we:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Created an image that allows us to bootstrap NixOS servers on DigitalOcean,
  complete with our SSH public key for easy management&lt;/li&gt;
&lt;li&gt;Created a NixOS configuration that we can push to remote machines via Morph&lt;/li&gt;
&lt;li&gt;Deployed an nginx server and added a health check to ensure it still works
  after changes to configuration&lt;/li&gt;
&lt;li&gt;Pinned this server's packages to a specific commit to ensure stability&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The entire source code can be found in a
&lt;a href="https://github.com/justinas/nixos-cloud"&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;
&lt;h1 id="whats-next"&gt;What's next?&lt;/h1&gt;
&lt;p&gt;In the second part of the series, we will learn how to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Launch several DigitalOcean servers using Terraform&lt;/li&gt;
&lt;li&gt;Make Nix aware of Terraform state and the servers it manages&lt;/li&gt;
&lt;li&gt;Use that information in our Morph network definition
  and deploy a setup of several backend servers
  behind several load balancers.&lt;/li&gt;
&lt;/ul&gt;</content><category term="Linux"/></entry><entry><title>Producing a podcast the geeky way: Audio</title><link href="https://justinas.org/producing-a-podcast-the-geeky-way-audio" rel="alternate"/><published>2018-11-11T16:30:00+00:00</published><updated>2018-11-11T16:30:00+00:00</updated><author><name>Justinas Stankevičius</name></author><id>tag:justinas.org,2018-11-11:/producing-a-podcast-the-geeky-way-audio</id><summary type="html">&lt;p&gt;A few months ago I started my podcast &lt;a href="https://corded.lt"&gt;Corded&lt;/a&gt;
where I talk to people whose jobs or creations I find interesting.
Corded is an ongoing learning experience
not only in the sense of producing interesting material,
but also the technical intricacies that come with producing
an audio/video product.&lt;/p&gt;
&lt;p&gt;This …&lt;/p&gt;</summary><content type="html">&lt;p&gt;A few months ago I started my podcast &lt;a href="https://corded.lt"&gt;Corded&lt;/a&gt;
where I talk to people whose jobs or creations I find interesting.
Corded is an ongoing learning experience
not only in the sense of producing interesting material,
but also the technical intricacies that come with producing
an audio/video product.&lt;/p&gt;
&lt;p&gt;This article, the first of a three-part series,
aims to shed some light on the &lt;em&gt;geeky&lt;/em&gt; way I produce my podcast.&lt;/p&gt;
&lt;p&gt;Note that I could not emphasize &lt;em&gt;geeky&lt;/em&gt; enough:
as it often is, when I take up a creative activity,
I find the technical side of it just as interesting
as the creative side, if not more so.
Perhaps this is why when I dabbled in streaming on Twitch,
I found that I enjoyed spending hours in OBS
trying to make the scene just perfect
at least as much as I enjoyed the actual streaming.
I will often choose the long route instead of the easy one,
just to learn more about the inner workings,
rather than make my process as easy as possible.
My process will not be the optimal one for everyone
or possibly even anyone other than me.&lt;/p&gt;
&lt;p&gt;The topic of this first article is audio,
the most instrumental part of any podcast.&lt;/p&gt;
&lt;h2 id="hardware"&gt;Hardware&lt;/h2&gt;
&lt;p&gt;Way before I actually started recording episodes,
I became a fan of Bandrew Scott's YouTube channel called
&lt;a href="https://www.youtube.com/channel/UCvOU-zTlankT-JjN3ZzvuKA"&gt;Podcastage&lt;/a&gt;.
Bandrew is constantly putting out in-depth reviews
of microphones, audio interfaces and other audio hardware.&lt;/p&gt;
&lt;p&gt;It was in part Podcastage that helped me decide on
what is so far the only piece of "audio hardware" I use:
the &lt;a href="https://www.amazon.com/Samson-Handheld-Microphone-Recording-Podcasting/dp/B001R747SG"&gt;Samson Q2U&lt;/a&gt;
dynamic microphone.
Nothing in its price range can beat Q2U's versatility:
it can be connected via USB for that no-frills plug-and-play experience,
however, an XLR port is also included which makes for a clear upgrade path
if one ever decides to upgrade to a standalone audio interface
or finds themselves in need of a mixer for live production.&lt;/p&gt;
&lt;p&gt;Other than that, I also got a cheapo
&lt;a href="https://www.amazon.com/Neewer-Microphone-Suspension-Mounting-Windscreen/dp/B01GRMF5ZE/"&gt;Neewer boom arm&lt;/a&gt;
with an included pop filter.
It is worthy to note that I had to go to a local store to get a suitable mic clip
for the Q2U, as the shock mount with the arm was too large:
likely manufactured to accomodate larger condenser microphones.&lt;/p&gt;
&lt;h2 id="remote-recording-woes"&gt;Remote recording woes&lt;/h2&gt;
&lt;p&gt;Once I got my gear sorted out,
it was time to figure out how best to record both me and the guests.
For now, I have opted for remote interviews.
This means that I do not have to get more microphones for my guests or even
invite them over (possibly meaning a trip from another city just to record for 30 minutes).
However, it slightly complicates the process on my side:
not only do I need a VoIP solution to communicate,
I also need a way to record both my own end
and the other end.&lt;/p&gt;
&lt;p&gt;For the first issue, I have used both
&lt;a href="https://discordapp.com/"&gt;Discord&lt;/a&gt;
and &lt;a href="https://zencastr.com/"&gt;Zencastr&lt;/a&gt; so far.
Considering most of my guests do not own a studio-quality microphone in the first place,
these applications provide a good-enough quality.
I found Zencastr to be less of a hassle as the guests would not need to create a Discord account
and configure its audio settings for optimal recording.&lt;/p&gt;
&lt;p&gt;Both Zencastr and Discord (using &lt;a href="https://craig.chat/"&gt;Craig&lt;/a&gt;)
can record each participant's track separately.
However, upon testing Zencastr, I noticed it would often suffer
from audio drift issues.
For one reason or another, I decided not to try Craig
and instead searched for software I could run solely on my own machine
and which would let me record both my microphone in
and the loopback interface (i.e. 'what you hear') simultaneously.
This way, Discord or Zencastr would be used purely as a way to communicate,
without using their recording capabilities.&lt;/p&gt;
&lt;p&gt;This was not a trivial task, as most digital audio workstations (DAWs)
will expect you to use a single audio interface when in my case there were two:
the on-board sound card which I would plug my headphones into
and the Samson Q2U which acts as a sound card of its own when used via USB.&lt;/p&gt;
&lt;p&gt;Finally, I decided on a solution: OBS.
Yes, that OBS, mostly used by streamers on Twitch or YouTube.
Usually streamers will want the audio on their stream to contain
both the loopback interface (e.g. game sounds)
and their own microphone.
OBS allows to record a setup like that out-of-the-box,
and if you tune the settings just right,
it will put your audio sources
into separate audio tracks in the resulting video file.
I would then use Avidemux to extract these separate tracks from the video file.
It was the perfect hack, which I gladly used for recording the first three episodes.&lt;/p&gt;
&lt;h2 id="post-production-and-perfectionism"&gt;Post-production and perfectionism&lt;/h2&gt;
&lt;p&gt;Of course, just because you have the recording
does not mean it is ready for your listeners' ears.
Any podcast warrants at least basic post-production:
background noise removal, cutting out any mess-ups or awkward silence.
Most podcasters will also use an equalizer at least minimally
(cutting off anything below 80 or 100 Hz is a usual practice)
and apply compression to not have startling changes in audio levels.&lt;/p&gt;
&lt;p&gt;Initially I went for the trusty &lt;a href="https://www.audacityteam.org/"&gt;Audacity&lt;/a&gt;
which I had been using for years whenever I needed to do basic audio edits.
For beginner podcasters, using Audacity is a no-brainer.
It's free, its noise reduction works like magic,
and, once I learned the keybindings,
making cuts in the episode felt like
swinging a sharp samurai sword at the tracks.&lt;/p&gt;
&lt;p&gt;Post-production was (and still is) the most time-consuming part of my process.
Even after making the initial cut I would listen to the entire episode
5 to 10 more times, finding something worth fixing every time,
be it a sharp breath of the guest,
or me going on a tangent that I would find not worthy keeping in.&lt;/p&gt;
&lt;p&gt;After all this was done, the episode would be exported to an MP3 file.
Many podcasters will tell you that a 64 or 96 kbps mono export is enough.
I went a bit overboard and chose 128 kbps as my baseline,
with the one exception being episode 2,
which included a preview of a track from Kuoga.:
that one, I felt, warranted a 256 kbps stereo export.&lt;/p&gt;
&lt;h2 id="the-move-to-linux-and-a-daw"&gt;The move to Linux and a DAW&lt;/h2&gt;
&lt;p&gt;I have been using Linux as my main OS for about 10 years now
(with a 2 year period of being an OS X guy).
Windows exists on my hard drive mostly
to run a few games that do not perform as well on Linux.
So naturally, I wanted to move my podcast production to my preferred OS as well.&lt;/p&gt;
&lt;p&gt;As an additional step towards greatness,
I decided to look for a &lt;em&gt;proper&lt;/em&gt; DAW.
Not only is Audacity's multi-track recording limited,
it is also a &lt;em&gt;destructive&lt;/em&gt; editor.
That means that whatever FX or edits you apply to a track in Audacity,
it is like painting over something in MS Paint.
Sure, you can click "Undo" a few times,
but what if you save the project and reopen it?
Or if you want to undo an earlier change without affecting the later ones?
Want to bypass one of the 10 effects you applied? Tough luck.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Non-destructive&lt;/em&gt; editors treat changes more like Adobe Photoshop treats layers.
You are free to turn effects on or off or
make cuts and then bring the removed parts back
without affecting anything else.
Besides, everything is applied in real-time
as opposed to Audacity that will present you with a progress bar
while the waveform changes before your eyes.&lt;/p&gt;
&lt;p&gt;In search of a more professional piece of software,
I first tried using Ardour, probably the most significant open source DAW.
And while I liked its vast recording and routing capabilities,
I quickly found that
&lt;a href="http://manual.ardour.org/mixing/plugin-and-hardware-inserts/plugins-bundled-with-ardour/"&gt;the set of plugins&lt;/a&gt;
Ardour comes with is very spartan (perhaps on purpose).
Scavenging the interwebs for a decent noise removal plugin
felt like a backwards step from Audacity,
so I quickly turned my attention elsewhere
in pursuit of an all-in-one solution.&lt;/p&gt;
&lt;p&gt;In the end, I decided on REAPER, a DAW often recommended
in the &lt;a href="https://reddit.com/r/podcasting"&gt;r/podcasting&lt;/a&gt; community.
The team behind REAPER had just recently started publishing native Linux builds
at the time. Despite not being as prevalent as FL Studio or Ableton Live,
REAPER is by all means a professional DAW.
Just like Ardour, it comes with flexible audio routing,
but surpasses it in plugins in terms of both quality and quantity.
The bigger userbase also helps:
YouTube is full of tutorials for doing all sorts of things using REAPER.&lt;/p&gt;
&lt;p&gt;The caveat? REAPER is non-free.
However, the WinRAR-like
&lt;a href="https://en.wikipedia.org/wiki/Shareware#Nagware"&gt;nagware&lt;/a&gt; model
is a welcome practice.
REAPER does not limit functionality even if you use it past the 60-day trial period.
Hell, they even offer &lt;a href="https://www.reaper.fm/reaplugs/"&gt;a set of plugins&lt;/a&gt;
which you are free to use in any other DAW of your liking.
Even if I find the $60 personal/small-business license steep,
that is only because I record about one episode per month.
Compared to prices of other DAWs of similar level, it is essentially pennies.
Pennies that I will pay some time in the future, I promise.&lt;/p&gt;
&lt;p&gt;Apart from editing &lt;em&gt;non-destructively&lt;/em&gt;, my post-production barely changed with the move from Audacity to REAPER:
I still use the same functionality (noise removal, equalization, compression),
I still make similar cuts in the episode,
and I still export in the same quality.&lt;/p&gt;
&lt;h2 id="jack-the-daemon-of-my-nightmares-dreams"&gt;JACK: the daemon of my &lt;s&gt;nightmares&lt;/s&gt; dreams&lt;/h2&gt;
&lt;p&gt;Another key component to working with audio on Linux is JACK:
the &lt;a href="https://en.wikipedia.org/wiki/JACK_Audio_Connection_Kit"&gt;"professional sound server daemon"&lt;/a&gt;.
I have been aware of JACK for a while now,
perhaps back from all the times
I tried to make my PC into a guitar amp
using &lt;a href="http://rakarrack.sourceforge.net/"&gt;Rakkarack&lt;/a&gt;
(which, of course, used JACK).&lt;/p&gt;
&lt;p&gt;I might have lacked patience back then,
because I struggled with just getting JACK up and running a lot.
Now, however, I found the experience involved, yet relatively painless.
I did need to spend some time learning how to use the audio routing
and get JACK to play along nicely with
PulseAudio (which is in turn another daemon that most
"consumer" Linux software like Firefox or Discord use for audio).&lt;/p&gt;
&lt;p&gt;A few evenings learning the ins and outs of JACK yielded this recording setup:&lt;/p&gt;
&lt;p&gt;&lt;img alt="My JACK audio routing setup" src="https://justinas.org/static/jack.png"&gt;&lt;/p&gt;
&lt;p&gt;While this may seem convoluted to an untrained eye,
it is actually a quite elegant setup:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;samson&lt;/code&gt;, my microphone
  (attached via &lt;a href="https://www.systutorials.com/docs/linux/man/1-alsa_in/"&gt;alsa_in&lt;/a&gt;),
  feeds into both &lt;code&gt;REAPER&lt;/code&gt; to record
  and &lt;code&gt;PulseAudio JACK Source&lt;/code&gt; for my VoIP solution to transmit.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PulseAudio JACK Sink&lt;/code&gt;, i.e. 'what I hear' from the guest via Zencastr via Firefox
  goes to two destinations as well: &lt;code&gt;REAPER&lt;/code&gt; and my headphones.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;REAPER&lt;/code&gt; outputs to &lt;code&gt;system&lt;/code&gt; by default.
  I do not use monitoring from the DAW when recording.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;While this setup is pretty simple,
JACK, in conjunction with a DAW like REAPER,
provides almost infinite audio routing possibilities.
For example, if I ever wanted to do live podcast production,
it should be possible to do a &lt;a href="https://en.wikipedia.org/wiki/Mix-minus"&gt;mix-minus&lt;/a&gt;
solely by making the right connections in the software,
without any need to shell out money for a hardware mixer.&lt;/p&gt;
&lt;p&gt;For more info about using JACK for podcasting
&lt;a href="https://www.youtube.com/watch?v=BX35MdZT9LI"&gt;check out this video&lt;/a&gt;
by Dustin Williams,
who uses an even geekier JACK setup
using jack_mixer, jack_capture, and some helper shell scripts.&lt;/p&gt;
&lt;h2 id="the-future"&gt;The future&lt;/h2&gt;
&lt;p&gt;As it stands now, I am happy with my Q2U/JACK/REAPER
setup for recording and post-production.
Aside from getting better at actually using REAPER,
the best improvement to make would probably be
moving to an in-person recording setup,
including a standalone audio interface,
a couple more microphones
and a dedicated sound-treated space in my home or elsewhere.&lt;/p&gt;
&lt;p&gt;However, like I've mentioned before,
that change would come with its own set of drawbacks
and my low episode output makes it hard to justify
the time and money investment it would require.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;The next part of the series will focus on the video part of my podcast:
the &lt;em&gt;why&lt;/em&gt; and the &lt;em&gt;how&lt;/em&gt;.
If you're able to decipher Lithuanian and like podcasts,
consider subscribing to &lt;a href="https://corded.lt"&gt;Corded&lt;/a&gt;. :)&lt;/p&gt;</content><category term="Podcasting"/></entry><entry><title>My reason to be excited for Go 1.4</title><link href="https://justinas.org/my-reason-to-be-excited-for-go-14" rel="alternate"/><published>2014-12-22T09:50:00+00:00</published><updated>2014-12-22T09:50:00+00:00</updated><author><name>Justinas Stankevičius</name></author><id>tag:justinas.org,2014-12-22:/my-reason-to-be-excited-for-go-14</id><summary type="html">&lt;p&gt;More than a week ago,
&lt;a href="http://blog.golang.org/go1.4"&gt;Go 1.4 was released&lt;/a&gt;,
bringing new features and bug fixes to the programming language.&lt;/p&gt;
&lt;p&gt;Many people consider the support for building
shared libraries for Android the most important
addition in this version.
Others are excited about the new &lt;code&gt;go generate&lt;/code&gt; tool.
Some are happy …&lt;/p&gt;</summary><content type="html">&lt;p&gt;More than a week ago,
&lt;a href="http://blog.golang.org/go1.4"&gt;Go 1.4 was released&lt;/a&gt;,
bringing new features and bug fixes to the programming language.&lt;/p&gt;
&lt;p&gt;Many people consider the support for building
shared libraries for Android the most important
addition in this version.
Others are excited about the new &lt;code&gt;go generate&lt;/code&gt; tool.
Some are happy that internal packages have landed,
as they should help reduce duplication of code.&lt;/p&gt;
&lt;p&gt;However, my favorite new feature of Go 1.4
is hidden deep in a section called "Minor changes to the [standard] library"
in the &lt;a href="https://golang.org/doc/go1.4"&gt;release notes&lt;/a&gt;.
A list item there states:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The testing package has a new facility to provide more control
over running a set of tests. If the test code contains a function  &lt;/p&gt;
&lt;p&gt;&lt;code&gt;func TestMain(m *testing.M)&lt;/code&gt;   &lt;/p&gt;
&lt;p&gt;that function will be called instead of running the tests directly.
The M struct contains methods to access and run the tests.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;To sum up the benefits of this feature in one sentence,
it lets you do global set-up/tear-down for tests.&lt;/p&gt;
&lt;h2 id="why-that-excites-me"&gt;Why that excites me&lt;/h2&gt;
&lt;p&gt;Recently, I have been developing a
full-blown MVC web application in Go.
Having come from Python, where Django
wraps you tightly with all sorts of helpers,
I initially struggled with several areas
of architecture of a web application.&lt;/p&gt;
&lt;p&gt;One of those was database testing.
Django provides a test runner
that creates a fresh database
every time the tests are run.
This way, you can do away with mocking
and run your tests on real data,
thus improving their accuracy.&lt;/p&gt;
&lt;p&gt;In Go, I don't use any framework
for my projects, and even if I did,
none seem to have their own
sophisticated testing tools.
Thus, I had to invent my own way
to swap out the database while testing .
After thinking the design over for weeks,
the final result looked like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;TestSomeFeature&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;testing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TestDBManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Enter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TestDBManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Exit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Do the tests&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Where &lt;code&gt;Enter()&lt;/code&gt; is responsible
for creating a new Postgres database,
running the migrations, 
swapping out the usual database connection,
while &lt;code&gt;Exit()&lt;/code&gt; drops the database
and restores the original one.&lt;/p&gt;
&lt;p&gt;This worked, but was less than ideal.
Every single test which utilized the DB
had to go through this process
and thus as the testing suite grow,
the time it took to run tests followed linearly.
Even if I wanted to only do this once,
there was no single point of entry or exit
I could hook on when &lt;code&gt;go test&lt;/code&gt; ran.&lt;/p&gt;
&lt;p&gt;The introduction of &lt;code&gt;TestMain()&lt;/code&gt; made it possible
to run these migrations only once.
The code now looks like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;TestSomeFeature&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;testing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TestDBManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Reset&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Do the tests&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;TestMain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;testing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;M&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TestDBManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Enter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// os.Exit() does not respect defer statements&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;ret&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TestDBManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Exit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ret&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;While each test must still clean up after itself,
that only involves restoring the initial data,
which is way faster than doing the schema migrations.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style="text-align: center;"&gt;Package&lt;/th&gt;
&lt;th style="text-align: center;"&gt;Without TestMain&lt;/th&gt;
&lt;th style="text-align: center;"&gt;With TestMain&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;models&lt;/td&gt;
&lt;td style="text-align: center;"&gt;3.017s&lt;/td&gt;
&lt;td style="text-align: center;"&gt;0.548s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;handlers&lt;/td&gt;
&lt;td style="text-align: center;"&gt;9.329s&lt;/td&gt;
&lt;td style="text-align: center;"&gt;2.971s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;settings&lt;/td&gt;
&lt;td style="text-align: center;"&gt;0.008s&lt;/td&gt;
&lt;td style="text-align: center;"&gt;0.008s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;cli&lt;/td&gt;
&lt;td style="text-align: center;"&gt;1.230s&lt;/td&gt;
&lt;td style="text-align: center;"&gt;0.528s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The table above illustrates the performance improvements.
The time it takes to run tests has reduced significantly,
considering the database-heavy parts.&lt;/p&gt;
&lt;p&gt;This approach also reduces code duplication by 50%:
we now only have one line for database management
in each test instead of two.&lt;/p&gt;
&lt;h1 id="less-is-more"&gt;Less is more&lt;/h1&gt;
&lt;p&gt;The addition of the &lt;code&gt;TestMain&lt;/code&gt; function,
as simple change as it is,
improved my development process in important ways.
This is why Go makes me happy:
every 6 months, with a new version of the language,
new features come along.
Some are big, but most are little.
Despite that, they all play
an important part in making Go better,
without sacrificing core values of the language.
I am sure many others will benefit from
the improvements brought by Go 1.4.&lt;/p&gt;</content><category term="Programming"/></entry><entry><title>Alice – Painless Middleware Chaining for Go</title><link href="https://justinas.org/alice-painless-middleware-chaining-for-go" rel="alternate"/><published>2014-05-25T17:00:00+00:00</published><updated>2014-05-25T17:00:00+00:00</updated><author><name>Justinas Stankevičius</name></author><id>tag:justinas.org,2014-05-25:/alice-painless-middleware-chaining-for-go</id><summary type="html">&lt;p&gt;According to a recent 
&lt;a href="http://www.reddit.com/r/golang/comments/252wjh/are_you_using_golang_for_webapi_development_what/"&gt;thread&lt;/a&gt;
on Reddit, 
many people like it simple 
when doing web development in Go
and use &lt;code&gt;net/http&lt;/code&gt; with useful addons
(like the Gorilla toolkit)
instead of a full-fledged framework.&lt;/p&gt;
&lt;p&gt;Such applications often make use of middleware,
but wrapping lots of layers of handlers
can become …&lt;/p&gt;</summary><content type="html">&lt;p&gt;According to a recent 
&lt;a href="http://www.reddit.com/r/golang/comments/252wjh/are_you_using_golang_for_webapi_development_what/"&gt;thread&lt;/a&gt;
on Reddit, 
many people like it simple 
when doing web development in Go
and use &lt;code&gt;net/http&lt;/code&gt; with useful addons
(like the Gorilla toolkit)
instead of a full-fledged framework.&lt;/p&gt;
&lt;p&gt;Such applications often make use of middleware,
but wrapping lots of layers of handlers
can become messy in the long run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;final&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;gzipHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rateLimitHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;securityHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;authHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;myApp&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Sure, that works. But then you want to remove a handler,
add one or reorder them. Suddenly, you're drowning in parentheses.&lt;/p&gt;
&lt;p&gt;Alice &lt;a href="https://github.com/justinas/alice"&gt;(available on GitHub)&lt;/a&gt;
was created as a solution to simplify chaining
while remaining flexible 
and playing nice with the existing &lt;code&gt;net/http&lt;/code&gt; middleware.&lt;/p&gt;
&lt;p&gt;It's not a framework, a mux or a toolkit.
Its sole functionality is 
to let you create the same middleware chain like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;final&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;alice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;gzipHandler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ratelimitHandler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;securityHandler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;authHandler&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;Then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;myApp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h1 id="flaws-of-other-approaches"&gt;Flaws of other approaches&lt;/h1&gt;
&lt;p&gt;Many might point out that there are existing solutions
for chaining middleware.
That's true, but any of the solutions I had looked into 
had at least one thing that I thought should be done in a differently.&lt;/p&gt;
&lt;p&gt;The recent &lt;a href="https://github.com/codegangsta/negroni"&gt;Negroni&lt;/a&gt; package 
allows handlers to be added as middleware like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;negroni&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Classic&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="c1"&gt;// func (n *Negroni) UseHandler(handler http.Handler)&lt;/span&gt;
&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;UseHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;myMiddleware&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;See the fault here? &lt;em&gt;Traditional&lt;/em&gt; &lt;code&gt;net/http&lt;/code&gt; middleware
wrap the next handler so the wrapper can have a total control.
Here, there's simply no handler to pass in.
You can't pass in the Negroni instance as it would result in
infinite recursion (Negroni calls middleware calls Negroni).&lt;/p&gt;
&lt;p&gt;Negroni has its own mechanism for control flow
(&lt;code&gt;next()&lt;/code&gt; to call the following handlers),
but you have to modify your middleware to fully utilize it,
which is not ideal.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/technoweenie/go-httppipe"&gt;go-httppipe&lt;/a&gt;
has the same problem: it's suited for successive handlers,
but not wrapper-type middleware.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/mattn/go-stackbuilder"&gt;go-stackbuilder&lt;/a&gt;
forcibly uses &lt;code&gt;http.ServeMux&lt;/code&gt; as the main handler,
instead of &lt;code&gt;http.Handler&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mux&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ServeMux&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Builder&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Builder&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;mux&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Handler&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DefaultServeMux&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hs&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That is not ideal as one might like to bypass the default mux completely,
especially when using an alternative one.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/stephens2424/muxchain"&gt;Muxchain&lt;/a&gt;,
like Negroni, doesn't provide a reference to the next handler.&lt;/p&gt;
&lt;p&gt;Matt Silverlock's
&lt;a href="https://gist.github.com/elithrar/21cb76b8e29398722532"&gt;use.go snippet&lt;/a&gt;
came closest to what I wanted.
My only complaint is that 
the ordering of handlers here is counter-intuitive.
Reading the chaining code makes it obvious that&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;myApp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;csrf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;recovery&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;is equivalent to this code:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;recovery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;csrf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;myApp&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;and this request cycle:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;recovery -&amp;gt; logging -&amp;gt; csrf -&amp;gt; myApp
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;So, a reversed order from what you've written in your code.&lt;/p&gt;
&lt;h1 id="how-alice-is-better"&gt;How Alice is better&lt;/h1&gt;
&lt;p&gt;Alice adopts Matt's model and fixes the small imperfections.
It still requires middleware constructors of form &lt;code&gt;func (http.Handler) http.Handler&lt;/code&gt;,
but requests now flow exactly the way you order your handlers.&lt;/p&gt;
&lt;p&gt;This code:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;alice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Chain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;recovery&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;csrf&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;Then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;myApp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;will result in this request cycle:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;recovery -&amp;gt; logging -&amp;gt; csrf -&amp;gt; myApp
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here, &lt;code&gt;recovery&lt;/code&gt; receives the request and has a reference to &lt;code&gt;logging&lt;/code&gt;.
It may or may not call &lt;code&gt;logging&lt;/code&gt;:
it's completely up to &lt;code&gt;recovery&lt;/code&gt;,
just as without Alice.&lt;/p&gt;
&lt;h1 id="one-more-thing"&gt;One more thing&lt;/h1&gt;
&lt;p&gt;Deciding on a unified constructor for middleware is the main reason
why creating such a convenient API for chaining is even possible.&lt;/p&gt;
&lt;p&gt;However, limiting ourselves to one function signature has a drawback.
Many middleware have settings one might want (or have) to set.
Not only does that not fit into our chosen signature,
there is no standard way adopted by developers.&lt;/p&gt;
&lt;p&gt;Middleware found in the standard library take the options
as additional arguments to the same function:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StripPrefix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/old/&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://github.com/PuerkitoBio/throttled"&gt;Throttled&lt;/a&gt;
constructs a rate limiting strategy 
which has a method to wrap our handler:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;th&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;throttled&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RateLimit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;throttled&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PerMin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;throttled&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;VaryBy&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;RemoteAddr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NewMemStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;th&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Throttle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And &lt;a href="https://github.com/justinas/nosurf"&gt;nosurf&lt;/a&gt;
has additional methods on the handler:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;nosurf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ExemptPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SetFailureHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NotFoundHandler&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It's nearly impossible for Alice to solve this
without resorting to ugly reflection tricks, so it doesn't try to.
Instead, when in need of customization, one should create their own constructor.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;myStripPrefix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;h&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Handler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Handler&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StripPrefix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/old/&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;h&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This now complies to the constructor interface, so we can plug it into Alice.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;alice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;myStripPrefix&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;Then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;myApp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h1 id="prove-me-wrong-though"&gt;Prove me wrong, though&lt;/h1&gt;
&lt;p&gt;Alice was born in a matter of minutes 
and based on my own perception of what's right and what's not.
Just like I've found other solutions non-ideal,
some might find inherent flaws in how Alice works.
Although it's unlikely that the very essence of how Alice functions
will change, any feedback is welcome.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/justinas/alice"&gt;Check out Alice on GitHub.&lt;/a&gt;&lt;/p&gt;</content><category term="Programming"/></entry><entry><title>Best Practices for Errors in Go</title><link href="https://justinas.org/best-practices-for-errors-in-go" rel="alternate"/><published>2014-04-26T18:00:00+00:00</published><updated>2014-04-26T18:00:00+00:00</updated><author><name>Justinas Stankevičius</name></author><id>tag:justinas.org,2014-04-26:/best-practices-for-errors-in-go</id><summary type="html">&lt;p&gt;Error handling seems to be 
one of the more controversial areas of Go.
Some are pleased with it,
while others hate it with passion.
Nevertheless, there is a handful of best practices
that will make dealing with errors 
less painful if you're a sceptic
and even better if you like …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Error handling seems to be 
one of the more controversial areas of Go.
Some are pleased with it,
while others hate it with passion.
Nevertheless, there is a handful of best practices
that will make dealing with errors 
less painful if you're a sceptic
and even better if you like it as it is.&lt;/p&gt;
&lt;h1 id="know-when-to-panic"&gt;Know when to panic&lt;/h1&gt;
&lt;p&gt;The idiomatic way of reporting errors in Go
is having the error as the last return value of a funtion.
However, Go also offers 
an alternative error mechanism called &lt;code&gt;panic&lt;/code&gt;
that is similar to what is known as exceptions
in other programming languages.&lt;/p&gt;
&lt;p&gt;Despite not being suitable everywhere,
panics are useful in several specific scenarios.&lt;/p&gt;
&lt;h3 id="when-the-user-explicitly-asks-okay"&gt;When the user explicitly asks: &lt;span style="color: #0a0"&gt;Okay&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;In certain cases, the user might want to panic
and thus abort the whole application
if an important part of it can not be initialized.
Go's standard library is ripe with examples of variants 
of functions that panic instead of returning an error,
e.g. &lt;a href="http://golang.org/pkg/regexp/#MustCompile"&gt;regexp.MustCompile&lt;/a&gt;.
As long as there remains a function
that does this in an idiomatic way (&lt;code&gt;regexp.Compile&lt;/code&gt;),
providing the user with a nifty shortcut is okay.&lt;/p&gt;
&lt;h3 id="when-setting-up-maybe"&gt;When setting up: &lt;span style="color: #f5c500"&gt;Maybe&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;A scenario that, in a way, intersects with the previous one,
is the setting up phase of an application.
In most cases, if preparations fail, there is no point
in continuing.
One case of this might be a web application
failing to bind the required port
or being unable to connect to the database server.
In that case, there's not much left to do,
so panicking is acceptable,
even if not explicitly requested by the user.&lt;/p&gt;
&lt;p&gt;This behavior can also be observed in the standard library:
the &lt;code&gt;net/http&lt;/code&gt; muxer will panic if a pattern is invalid in any way.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mux&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;ServeMux&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pattern&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Handler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;mux&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;mux&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pattern&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http: invalid pattern &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http: nil handler&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;mux&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;explicit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http: multiple registrations for &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="otherwise-not-really"&gt;Otherwise: &lt;span style="color:#c00"&gt;Not really&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;Although there might be other cases where panic is useful,
returned errors remain preferable in most scenarios.&lt;/p&gt;
&lt;h1 id="predefine-errors"&gt;Predefine errors&lt;/h1&gt;
&lt;p&gt;It's not unusual to see code returning errors like this&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;doStuff&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;someCondition&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;no space left on the device&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;permission denied&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The wrongdoing here is that it's not convenient
to check which error has been returned.
Comparing strings is error prone: 
misspelling a string in comparison will result in
an error that cannot be caught at compile time,
while a cosmetic change of the returned error
will break the checking just as much.&lt;/p&gt;
&lt;p&gt;Given a small set of errors, the best way to handle this
is to predefine each error publicly at the package level.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ErrNoSpaceLeft&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;no space left on the device&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ErrPermissionDenied&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;permission denied&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;doStuff&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;someCondition&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ErrNoSpaceLeft&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ErrPermissionDenied&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now the previous problems aren't anymore. &lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ErrNoSpaceLeft&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// handle this particular error&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h1 id="provide-information"&gt;Provide information&lt;/h1&gt;
&lt;p&gt;Sometimes, an error can happen because of 
a whole lot of different reasons. 
Wikipedia lists 
&lt;a href="https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#4xx_Client_Error"&gt;41 different HTTP client errors&lt;/a&gt;.
Let's say we want to treat them as errors in Go
(&lt;code&gt;net/http&lt;/code&gt; does not).
What's more, we'd like to be able to look into the specifics of
the error we received and find out whether the error was
404, 410 or 418.&lt;/p&gt;
&lt;p&gt;In the last paragraph we developed a pattern 
for discerning errors from one another,
but here it gets a bit messy.
Predefining 41 separate errors like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ErrBadRequest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;HTTP 400: Bad Request&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ErrUnauthorized&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;HTTP 401: Unauthorized&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;will make our code and documentation messy and our fingers sore.&lt;/p&gt;
&lt;p&gt;A custom error type is the best solution to this problem.
Go's implicit interfaces make creating one easy:
to conform to the &lt;code&gt;error&lt;/code&gt; interface,
we only need to have an &lt;code&gt;Error()&lt;/code&gt; method
that returns a string.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;HTTPError&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Code&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Description&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;h&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;HTTPError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;HTTP %d: %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Not only does this act like a regular error,
it also contains the status code as an integer.
We can then use it as follows:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;HTTPError&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Not Found&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// an error occured&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.(&lt;/span&gt;&lt;span class="nx"&gt;HTTPError&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;Code&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// handle a &amp;quot;not found&amp;quot; error&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// handle a different error&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;p&gt;The only minor annoyance left here is 
the need to do a type assertion to a concrete error type.
But it's a small price to pay compared to 
the fragility of parsing the error code from a string.&lt;/p&gt;
&lt;h1 id="provide-stack-traces"&gt;Provide stack traces&lt;/h1&gt;
&lt;p&gt;Errors as they exist in Go remain inferior 
to panics in one important way: they do not provide important information 
about where in the call stack the error happened.&lt;/p&gt;
&lt;p&gt;A solution to this problem has recently been created
by the Juju team at Canonical.
Their package &lt;a href="https://github.com/juju/errgo"&gt;errgo&lt;/a&gt;
provides the functionality of wrapping an error
into another one that records where the error happened.&lt;/p&gt;
&lt;p&gt;Building up on the HTTP error handling example,
we'll now put this to use.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;fmt&amp;quot;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;github.com/juju/errgo&amp;quot;&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;HTTPError&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Code&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Description&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;h&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;HTTPError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;HTTP %d: %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;errgo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Mask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;HTTPError&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Not Found&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.(&lt;/span&gt;&lt;span class="nx"&gt;errgo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Locationer&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;Location&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;realErr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.(&lt;/span&gt;&lt;span class="nx"&gt;errgo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Wrapper&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;Underlying&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;realErr&lt;/span&gt;&lt;span class="p"&gt;.(&lt;/span&gt;&lt;span class="nx"&gt;HTTPError&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;Code&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// handle a &amp;quot;not found&amp;quot; error&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// handle a different error&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Our code has changed in several ways.
Firstly, we wrap an error into an &lt;code&gt;errgo&lt;/code&gt;-provided type.
This code now prints the information on where the error happened.
On my machine it outputs&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;/private/tmp/example.go:19
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;referencing a line in &lt;code&gt;request()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;However, our code has become somewhat messier.
To get to the real &lt;code&gt;HTTPError&lt;/code&gt; we need to do more unwrapping.
Sadly, I'm not aware of a real way to make this nicer, so
 it's all about tradeoffs.
If your codebase is small
and you can always tell where the error came from,
you might not need to use &lt;code&gt;errgo&lt;/code&gt; at all.  &lt;/p&gt;
&lt;h1 id="what-about-concrete-types"&gt;What about concrete types?&lt;/h1&gt;
&lt;p&gt;Some might point out that a portion of 
the type assertions could have been avoided
if we returned a concrete type from a function
instead of an &lt;code&gt;error&lt;/code&gt; interface.&lt;/p&gt;
&lt;p&gt;However, doing that in conjunction with the &lt;code&gt;:=&lt;/code&gt; operator 
will bring trouble. As a result, the error variable will not be reusable.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;f1&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;HTTPError&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;f2&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;OSError&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// err automatically declared as HTTPError&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;f1&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// OSError is a completely different type&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// The compiler does not allow this&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;f2&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To avoid this, errors are best returned using the &lt;code&gt;error&lt;/code&gt; type.
Standard library avoids returning concrete types as well,
e.g. &lt;code&gt;os&lt;/code&gt; package states:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Often, more information is available within the error. 
For example, if a call that takes a file name fails, 
such as Open or Stat, the error will include 
the failing file name when printed 
and will be of type *PathError,
which may be unpacked for more information.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This concludes my list of 
best practices for errors in Go.
As in other areas, a different mindset has to be adopted
when coming into Go from elsewhere.
"Different" does not imply "worse" though
and deciding on a set of conventions
is vital to making Go development even better.&lt;/p&gt;</content><category term="Programming"/></entry><entry><title>Writing HTTP Middleware in Go</title><link href="https://justinas.org/writing-http-middleware-in-go" rel="alternate"/><published>2013-10-19T19:00:00+00:00</published><updated>2013-10-19T19:00:00+00:00</updated><author><name>Justinas Stankevičius</name></author><id>tag:justinas.org,2013-10-19:/writing-http-middleware-in-go</id><summary type="html">&lt;p&gt;In the context of web development, "middleware" usually stands for
"a part of an application that wraps 
the original application, adding additional functionality".
It's a concept that usually seems to be somewhat underappreciated,
but I think middleware is great.&lt;/p&gt;
&lt;p&gt;For one, a good middleware has a single responsibility,
is pluggable …&lt;/p&gt;</summary><content type="html">&lt;p&gt;In the context of web development, "middleware" usually stands for
"a part of an application that wraps 
the original application, adding additional functionality".
It's a concept that usually seems to be somewhat underappreciated,
but I think middleware is great.&lt;/p&gt;
&lt;p&gt;For one, a good middleware has a single responsibility,
is pluggable and self-contained.
That means you can plug it in your app
at the interface level and have it just work.
It doesn't affect your coding style,
it isn't a framework, but merely another layer in your request handling cycle.
There's no need to rewrite your code:
if you decide that you want the middleware, you add it into the equation,
if you change your mind, you remove it. That's it.&lt;/p&gt;
&lt;p&gt;Looking at Go, HTTP middleware is quite prevalent,
even in the standard library.
Although it might not be obvious at first,
functions in the &lt;code&gt;net/http&lt;/code&gt; package, like 
&lt;a href="http://golang.org/pkg/net/http/#StripPrefix"&gt;StripPrefix&lt;/a&gt;
or &lt;a href="http://golang.org/pkg/net/http/#TimeoutHandler"&gt;TimeoutHandler&lt;/a&gt;
are exactly what we defined middleware to be: they wrap your handler 
and take additional steps when dealing with requests or responses.&lt;/p&gt;
&lt;p&gt;My recent Go package &lt;a href="https://github.com/justinas/nosurf"&gt;nosurf&lt;/a&gt;
is middleware too. 
I intentionally designed it as one from the very beginning.
In most cases you don't need to be aware of things happening at the application layer
to do a CSRF check: &lt;code&gt;nosurf&lt;/code&gt;, like any proper middleware, stands completely on its own
and works with any tools that use the standard &lt;code&gt;net/http&lt;/code&gt; interface.&lt;/p&gt;
&lt;p&gt;&lt;a id="usecases"&gt;&lt;/a&gt;You can also use middleware for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mitigating BREACH attack by length hiding&lt;/li&gt;
&lt;li&gt;Rate-limiting&lt;/li&gt;
&lt;li&gt;Blocking &lt;em&gt;evil&lt;/em&gt; bots&lt;/li&gt;
&lt;li&gt;Providing debugging information&lt;/li&gt;
&lt;li&gt;Adding &lt;a href="https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security"&gt;HSTS&lt;/a&gt;,
  &lt;a href="https://developer.mozilla.org/en-US/docs/HTTP/X-Frame-Options"&gt;X-Frame-Options&lt;/a&gt; headers&lt;/li&gt;
&lt;li&gt;Recovering gracefully from panics&lt;/li&gt;
&lt;li&gt;...and probably many others&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id="writing-a-simple-middleware"&gt;Writing a simple middleware&lt;/h1&gt;
&lt;p&gt;For the first example, we'll write middleware
that only allows users visit our website
through a single domain
(specified by HTTP in the &lt;code&gt;Host&lt;/code&gt; header).
A middleware like that could serve to protect the web application
from &lt;a href="http://www.skeletonscribe.net/2013/05/practical-http-host-header-attacks.html"&gt;host spoofing attacks&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="constructing-the-type"&gt;Constructing the type&lt;/h2&gt;
&lt;p&gt;For starters, let's define a type for the middleware. We'll call it &lt;code&gt;SingleHost&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;SingleHost&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Handler&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;allowedHost&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It consists of only two fields:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the wrapped &lt;code&gt;Handler&lt;/code&gt; we'll call if the request comes with a valid &lt;code&gt;Host&lt;/code&gt;. &lt;/li&gt;
&lt;li&gt;the allowed host value itself.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As we made the field names lowercase, making them private to our package,
we should also make a constructor for our type.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;NewSingleHost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Handler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;allowedHost&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;SingleHost&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;SingleHost&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;allowedHost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;allowedHost&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="request-handling"&gt;Request handling&lt;/h2&gt;
&lt;p&gt;Now, for the actual logic. To implement &lt;code&gt;http.Handler&lt;/code&gt;,
our type only needs to have one method:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Handler&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;ServeHTTP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And here it is:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;SingleHost&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ServeHTTP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Host&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;allowedHost&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ServeHTTP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;WriteHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;403&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;ServeHTTP&lt;/code&gt; method simply checks the Host header on the request:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;if it matches the &lt;code&gt;allowedHost&lt;/code&gt; set by the constructor, 
it calls the wrapped handler's &lt;code&gt;ServeHTTP&lt;/code&gt; method, thus passing the 
responsibility for handling the request.&lt;/li&gt;
&lt;li&gt;if it doesn't match, it returns the 403 (Forbidden) status code
and the request is dealt with. &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The original handler's &lt;code&gt;ServeHTTP&lt;/code&gt; is never called in the latter case,
so not only does it not get a say in this, 
it won't even know such a request arrived at all.&lt;/p&gt;
&lt;p&gt;Now that we're done coding our middleware,
we just need to plug it in.
Instead of passing our original &lt;code&gt;Handler&lt;/code&gt; 
directly into the &lt;code&gt;net/http&lt;/code&gt; server, 
we wrap it in the middleware.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;singleHosted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;NewSingleHost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;myHandler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;example.com&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;:8080&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;singleHosted&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="an-alternative-approach"&gt;An alternative approach&lt;/h2&gt;
&lt;p&gt;The middleware we just wrote is really simple: 
it literally consists of 15 lines of code.
For writing such middleware,
there exists a method with less boilerplate.
Thanks to Go's support of first class functions and closures,
and having the neat &lt;code&gt;http.HandlerFunc&lt;/code&gt; wrapper,
we'll be able to implement this as a simple function,
rather than a separate struct type. 
Here is the function-based version of our middleware in its entirety.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;SingleHost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Handler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;allowedHost&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Handler&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;ourFunc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Host&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;allowedHost&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ServeHTTP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;WriteHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;403&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;HandlerFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ourFunc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here we declare a simple function called &lt;code&gt;SingleHost&lt;/code&gt;
that takes in a &lt;code&gt;Handler&lt;/code&gt; to wrap and the allowed hostname.
Inside it, we construct a function analogous to &lt;code&gt;ServeHTTP&lt;/code&gt;
from the previous version of our middleware.
Our inner function is actually a closure, 
so it can access the variables from the outer function.
Finally, &lt;a href="http://golang.org/pkg/net/http/#HandlerFunc"&gt;HandlerFunc&lt;/a&gt;
lets us use this function as a &lt;code&gt;http.Handler&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Deciding whether to use a &lt;code&gt;HandlerFunc&lt;/code&gt;
or to roll out your own &lt;code&gt;http.Handler&lt;/code&gt; type is ultimately up to you.
While for basic cases a function might be enough,
if you find your middleware growing, you might want to consider
making your own struct type and separate the logic into several methods. &lt;/p&gt;
&lt;p&gt;Meanwhile, the standard library actually uses both ways of building middleware.
&lt;a href="http://golang.org/pkg/net/http/#StripPrefix"&gt;StripPrefix&lt;/a&gt;
is a function that returns a &lt;code&gt;HandlerFunc&lt;/code&gt;,
while &lt;a href="http://golang.org/pkg/net/http/#TimeoutHandler"&gt;TimeoutHandler&lt;/a&gt;,
although a function too, returns a custom struct type that handles the requests.&lt;/p&gt;
&lt;h1 id="a-more-complex-case"&gt;A more complex case&lt;/h1&gt;
&lt;p&gt;Our &lt;code&gt;SingleHost&lt;/code&gt; middleware was trivial:
we checked one attribute of the request and
either passed the request to the original handler,
not caring about it anymore,
or returned a response ourselves
and didn't let the original handler
touch it at all.
Nevertheless, there are cases where, 
rather than acting based on what the request is,
our middleware has to post-process the response
after the original handler has written it, modifying it in some way.&lt;/p&gt;
&lt;h2 id="appending-data-is-easy"&gt;Appending data is easy&lt;/h2&gt;
&lt;p&gt;If we just want to append some data
after the body written by the wrapped handler,
all we have to do is call Write()
after it finishes:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;AppendMiddleware&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Handler&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;AppendMiddleware&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ServeHTTP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ServeHTTP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Middleware says hello.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The response body will now consist of whatever the original handler
outputted, followed by &lt;code&gt;Middleware says hello.&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="the-problem"&gt;The problem&lt;/h2&gt;
&lt;p&gt;Doing other types of response manipulations is a bit harder though.
Say, we'd like to prepend data to the response instead of appending it.&lt;/p&gt;
&lt;!--
We can't just call `Write()` before our original handler does.
If we did that, it would cause 
the default status code and headers to be written immediately. 
That way, the original handler wouldn't have 
any control over what those will be anymore.
--&gt;
&lt;p&gt;If we call &lt;code&gt;Write()&lt;/code&gt; before the original handler does,
it will lose control over the status code and headers,
since the first &lt;code&gt;Write()&lt;/code&gt; writes them out immediately.&lt;/p&gt;
&lt;p&gt;Modifying the original output in any other way (say, replacing strings in it),
changing certain response headers or setting a different status code won't work
because of a similar reason: when the wrapped handler returns,
those will have already be sent to the client.&lt;/p&gt;
&lt;p&gt;To counter this we need a particular kind of &lt;code&gt;ResponseWriter&lt;/code&gt;
that would work as a buffer, 
gathering the response and storing it for later use (and modifications).
We would then pass this buffering &lt;code&gt;ResponseWriter&lt;/code&gt; 
to the original handler instead of giving it the real RW,
thus preventing it from actually sending the response to the user just yet.&lt;/p&gt;
&lt;p&gt;Luckily, there's a tool just like that in the Go standard library.
&lt;a href="http://golang.org/pkg/net/http/httptest/#ResponseRecorder"&gt;ResponseRecorder&lt;/a&gt;
in the &lt;code&gt;net/http/httptest&lt;/code&gt; package does all we need:
it saves the response status code, a map of response headers
and accumulates the body into a buffer of bytes.
Although (like the package name implies) it's intended to be used in tests,
it fits our use case as well.&lt;/p&gt;
&lt;p&gt;Let's look at an example of middleware
that uses &lt;code&gt;ResponseRecorder&lt;/code&gt; and modifies &lt;strong&gt;everything&lt;/strong&gt; in a response, 
just for the sake of completeness.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ModifierMiddleware&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Handler&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;ModifierMiddleware&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ServeHTTP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;rec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;httptest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NewRecorder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// passing a ResponseRecorder instead of the original RW&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ServeHTTP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rec&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// after this finishes, we have the response recorded&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// and can modify it before copying it to the original RW&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// we copy the original headers first&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;rec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// and set an additional one&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;X-We-Modified-This&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Yup&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// only then the status code, as this call writes out the headers &lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;WriteHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;418&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// The body hasn&amp;#39;t been written (to the real RW) yet,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// so we can prepend some data.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Middleware says hello again. &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// But the Content-Length might have been set already,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// we should modify it by adding the length&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// of our own data.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Ignoring the error is fine here:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// if Content-Length is empty or otherwise invalid,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Atoi() will return zero,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// which is just what we&amp;#39;d want in that case.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;clen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;strconv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Atoi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Content-Length&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;clen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Content-Length&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;strconv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Itoa&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;clen&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// finally, write out our data&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// then write out the original body&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Bytes&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And here's the response we get by wrapping a handler 
that would otherwise simply return "Success!"
with our middleware.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kr"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt; &lt;span class="m"&gt;418&lt;/span&gt; &lt;span class="ne"&gt;I&amp;#39;m a teapot&lt;/span&gt;
&lt;span class="na"&gt;X-We-Modified-This&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="l"&gt;Yup&lt;/span&gt;
&lt;span class="na"&gt;Content-Type&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="l"&gt;text/plain; charset=utf-8&lt;/span&gt;
&lt;span class="na"&gt;Content-Length&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="l"&gt;37&lt;/span&gt;
&lt;span class="na"&gt;Date&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="l"&gt;Tue, 03 Sep 2013 18:41:39 GMT&lt;/span&gt;

Middleware says hello again. Success!
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This opens up a whole lot of new possibilities.
The wrapped handler is now completely in or control:
even after it handling the request,
we can manipulate the response in any way we want.&lt;/p&gt;
&lt;h1 id="sharing-data-with-other-handlers"&gt;Sharing data with other handlers&lt;/h1&gt;
&lt;p&gt;In various cases, your middleware might need to expose
certain information to other middleware or your app itself.
For example, &lt;code&gt;nosurf&lt;/code&gt; needs to give the user
a way to access the CSRF token
and the reason of failure (if any).&lt;/p&gt;
&lt;p&gt;A nice pattern for this is to use a map,
usually an unexported one, that maps &lt;code&gt;http.Request&lt;/code&gt; pointers
to pieces of the data needed,
and then expose package (or handler) level functions 
to access the data.&lt;/p&gt;
&lt;p&gt;I used this pattern for &lt;code&gt;nosurf&lt;/code&gt; too.
Here, I created a global context map.
Note that a mutex is also needed, since Go's maps 
&lt;a href="http://blog.golang.org/go-maps-in-action#TOC_6."&gt;aren't safe for concurrent access&lt;/a&gt;
by default.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;csrfContext&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;reason&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;contextMap&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;csrfContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;cmMutex&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RWMutex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The data is set by the handler and exposed via exported functions like &lt;code&gt;Token()&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;cmMutex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RLock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;cmMutex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RUnlock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;contextMap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can find the whole implementation in the 
&lt;a href="https://github.com/justinas/nosurf/blob/master/context.go"&gt;context.go&lt;/a&gt;
file in &lt;code&gt;nosurf&lt;/code&gt;'s repository.&lt;/p&gt;
&lt;p&gt;While I chose to implement this on my own for &lt;code&gt;nosurf&lt;/code&gt;,
there exists a handy &lt;a href="http://www.gorillatoolkit.org/pkg/context"&gt;gorilla/context&lt;/a&gt;
package that implements a generic map for saving request information.
In most cases, it should suffice and protect you from pitfalls 
of implementing a shared storage on your own.
It even has &lt;a href="http://www.gorillatoolkit.org/pkg/context#ClearHandler"&gt;middleware of its own&lt;/a&gt;
that clears the request data after it's been served.&lt;/p&gt;
&lt;h1 id="all-in-all"&gt;All in all&lt;/h1&gt;
&lt;p&gt;The intention of this article was both 
to draw fellow gophers' attention to middleware as a concept
and to demonstrate some of the basic building blocks for writing middleware in Go.
Despite being a relatively young language, Go has 
&lt;a href="https://justinas.org/embrace-gos-http-tools"&gt;an amazing standard HTTP interface&lt;/a&gt;.
It's one of the factors that make coding middleware for Go
a painless and even fun process.&lt;/p&gt;
&lt;p&gt;Nevertheless, there is still a lack of quality HTTP tools for Go.
Most, if not all, of the &lt;a href="#usecases"&gt;middleware ideas for Go&lt;/a&gt; 
I mentioned earlier are yet to come to life.
Now that you know how to build middleware for Go,
why not do it yourself? ;)&lt;/p&gt;
&lt;p&gt;P.S. You can find samples for all the middleware written for this post
in a &lt;a href="https://gist.github.com/justinas/7059324"&gt;GitHub gist&lt;/a&gt;.&lt;/p&gt;</content><category term="Programming"/></entry><entry><title>Embrace Go's HTTP Tools</title><link href="https://justinas.org/embrace-gos-http-tools" rel="alternate"/><published>2013-10-14T20:00:00+00:00</published><updated>2013-10-14T20:00:00+00:00</updated><author><name>Justinas Stankevičius</name></author><id>tag:justinas.org,2013-10-14:/embrace-gos-http-tools</id><summary type="html">&lt;p&gt;Some time ago I released 
&lt;a href="http://github.com/justinas/nosurf"&gt;nosurf&lt;/a&gt;,
a Go middleware for mitigating 
Cross-Site Request Forgery attacks.
Writing a seemingly simple and small package
was enough to fall in love 
with how Go handles HTTP.
Yet, it's up to us to either 
embrace the standard HTTP facilities
or fragmentate, sacrificing composability and …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Some time ago I released 
&lt;a href="http://github.com/justinas/nosurf"&gt;nosurf&lt;/a&gt;,
a Go middleware for mitigating 
Cross-Site Request Forgery attacks.
Writing a seemingly simple and small package
was enough to fall in love 
with how Go handles HTTP.
Yet, it's up to us to either 
embrace the standard HTTP facilities
or fragmentate, sacrificing composability and modularity.&lt;/p&gt;
&lt;h1 id="httphandler-is-the-interface"&gt;http.Handler is THE interface&lt;/h1&gt;
&lt;p&gt;Unified HTTP interfaces for 
web apps written in certain programming languages, like 
&lt;a href="http://www.python.org/dev/peps/pep-0333/"&gt;WSGI&lt;/a&gt; for Python
and &lt;a href="http://rack.github.io/"&gt;Rack&lt;/a&gt; for Ruby 
are a great idea, but they weren't always there. 
For instance, Rack only emerged in 2007,
when Rails had already been 
&lt;a href="http://www.google.com/trends/explore?q=ruby%20on%20rails"&gt;going strong&lt;/a&gt; 
for a while.&lt;/p&gt;
&lt;p&gt;Meanwhile in Go, the only interface needed
has been in development since 2009,
and although it's been through some serious
changes since that, by the end of 2011, 
months before Go 1.0 was released,
it had already stabilized.&lt;/p&gt;
&lt;p&gt;Of course, I'm talking about the mighty &lt;code&gt;http.Handler&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Handler&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;ServeHTTP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To be able to handle HTTP requests,
your type only needs to implement this one method.
The method reads the request info from the given *Request
and writes a response into the given ResponseWriter.
Seems simple enough, right?&lt;/p&gt;
&lt;h1 id="complement-dont-replace"&gt;Complement, don't replace&lt;/h1&gt;
&lt;p&gt;Yet, when building abstractions on top of that, some get it wrong.
Take for example
&lt;a href="https://github.com/paulbellamy/mango"&gt;Mango&lt;/a&gt;,
described by its author as
"a modular web-application framework for Go,
 inspired by Rack and PEP333".&lt;/p&gt;
&lt;p&gt;This is what a Mango application looks like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;mango&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mango&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;mango&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;mango&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;mango&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Headers&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;mango&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Hello World!&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Looks simple, concise and very similar to WSGI or Rack, right?
Except for one thing. While with dynamic/duck typing,
you could have any iterable for a body, 
here &lt;code&gt;mango.Body&lt;/code&gt; is simply a string.
Essentially, that takes away the ability to do 
any sort of streaming responses with Mango.
Even if it were to expose a &lt;code&gt;ResponseWriter&lt;/code&gt;,
anything written to it would clash with the returned values,
since they're only returned at the end of the function,
after the calls to ResponseWriter have already been made.&lt;/p&gt;
&lt;p&gt;That's bad. Whether you need another interface 
on top of existing &lt;code&gt;net/http&lt;/code&gt; is a matter of taste,
but even if you do, it should not take functionality away.
An interface that is nicer to code with, 
but takes away important functions is clearly inferior.&lt;/p&gt;
&lt;h1 id="the-right-way"&gt;The right way&lt;/h1&gt;
&lt;p&gt;A popular "micro" web framework &lt;a href="http://webgo.io/"&gt;web.go&lt;/a&gt;
deals with this in a simple, yet much better way.
Its handlers take a pointer to &lt;code&gt;web.Context&lt;/code&gt; 
as an optional first argument.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Context&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Request&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Params&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kd"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Server&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Server&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ResponseWriter&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;web&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;hello &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;web.Context&lt;/code&gt; does not take the standard HTTP handler structures away.
Instead, the &lt;code&gt;*Request&lt;/code&gt; argument is available as a struct member
and &lt;code&gt;Context&lt;/code&gt; &lt;del&gt;implements the required &lt;code&gt;ResponseWriter&lt;/code&gt; methods itself&lt;/del&gt;
embeds the original ResponseWriter.
The string you return from the function (if any) is simply appended
to the response.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;That&lt;/em&gt; is a good design choice and I think it goes well with Go's philosophy. 
Even though you get a nice higher-level API,
you don't have to sacrifice the low-level control over the request handling.&lt;/p&gt;
&lt;h1 id="start-now"&gt;Start now&lt;/h1&gt;
&lt;p&gt;Go's HTTP library infrastructure, despite growing rapidly,
still has some gaps left to fill.
But the last thing we need is fragmentation and 
annoying incompatibilities due to poor design
and abstractions that actually take important functionality away.
Embracing and supporting the standard Go HTTP facilities 
is, in my humble opinion, the straightest way to 
having functional and modular 3rd-party HTTP tools.&lt;/p&gt;</content><category term="Programming"/></entry></feed>