<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Sam J Drew]]></title><description><![CDATA[Sam J Drew]]></description><link>https://blog.samjdrew.com</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1722736896452/5994c1c1-69fd-4a38-8b7e-ad0f65e65958.png</url><title>Sam J Drew</title><link>https://blog.samjdrew.com</link></image><generator>RSS for Node</generator><lastBuildDate>Thu, 16 Apr 2026 08:24:08 GMT</lastBuildDate><atom:link href="https://blog.samjdrew.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Python developer learns C++]]></title><description><![CDATA[Brain-space is a limited resource. I hadn’t touched C/C++ since uni (excluding some tinkering with Arduino C) until a couple months ago when I was inspired by Mitchell Hashimoto, Co-founder and Former CEO of Hashicorp. In an interview, Hashimoto said...]]></description><link>https://blog.samjdrew.com/python-developer-learns-cpp-for-the-first-time</link><guid isPermaLink="true">https://blog.samjdrew.com/python-developer-learns-cpp-for-the-first-time</guid><category><![CDATA[software development]]></category><category><![CDATA[Software Engineering]]></category><category><![CDATA[cplusplus]]></category><dc:creator><![CDATA[Samuel Drew]]></dc:creator><pubDate>Thu, 13 Mar 2025 10:16:50 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1742700623162/f32dee7d-10fc-4ef7-9600-002461d8b8a3.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Brain-space is a limited resource. I hadn’t touched C/C++ since uni (excluding some tinkering with Arduino C) until a couple months ago when I was inspired by Mitchell Hashimoto, Co-founder and Former CEO of Hashicorp. <a target="_blank" href="https://youtu.be/YQnz7L6x068?si=HzWWgqf2LNS1dSp0">In an interview</a>, Hashimoto said he read the entire documentation of the Zig programming language to write his Ghostty terminal emulator. The whole thing. Top to bottom. What a concept! I’m very used to skimming the docs or reading bits that are relevant to a particular challenge. But I always assumed I didn’t have the brain-space to realistically store every page of the documentation.</p>
<p>And the reality is, I probably don’t. I can’t just go read the whole of cpprefference.com[1]. I also definitely wont go and read all of every C++ Standards Committee paper. Because that would be insane. But what I did do what you also can and should do is read learncpp.com.</p>
<p>Learncpp.com is a well written, concise rendering of the foundational knowledge required to write C++. But many of the concepts can be transferred to programming languages in general. I can confidently say I’m a far better software engineer than I was before I started reading it.</p>
<p>I’m not going to summarise learncpp.com in this article. Instead, I’ll share a list of things that, as an experienced DevOps engineer who’s mostly only ever used Python, were either a brand new concept to me or were a correction to a misunderstanding I had based on some false assumptions I’d made long ago. My hope for this article? I want the inquisitive reader to be the informed reader. To see that there’s so many things readers may not have known about C++ that the authors cover in expertly succinct detail with examples, quizzes and zero condescending tones.</p>
<p>A disclaimer: learncpp is still a working site and the writers are updating it constantly, not only when new cpp standards are released but also just depending on how readers respond to each article, feedback is listened to and new articles are written all the time. So this article may become outdated very quickly but with that in mind, lets treat this like a snapshot in time.</p>
<h3 id="heading-compile-time-optimisations-and-the-constexpr-keyword">Compile time optimisations and the <code>constexpr</code> keyword</h3>
<p>The compiler will try (when configured as such) to optimise as much as it can. There are a lot of optimisation techniques the compiler uses. One such technique is called constant propagation. It’s when the compiler replaces occurrences of a variable that is known to be constant with its value, saving the user time that would otherwise be spent fetching the variable from memory.</p>
<p>Another one of the techniques compilers use is called compile-time evaluation. That is, the compiler will look for any expressions that are evaluatable at compile-time (such as, variables that do not change after their initialisation, const variable declarations and statements that use only constant variables). It will then evaluate those expressions at compile time, replacing anywhere in the code that they appear with their evaluated expression.</p>
<p>Programmers can use the <code>constexpr</code> keyword in a few different ways to tell the compiler that the expression is evaluatable at compile-time (though the compiler has the final say on whether or not it does actually perform the evaluation at compile-time.)</p>
<p>Programmers can force the compiler to evaluate a statement at compile-time. A statement in an initialiser for a constexpr object will force the compiler to evaluate the statement at compile time. This means the statement must also be a constexpr. If it isn’t, the compiler will error.</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>{ 
    <span class="hljs-keyword">constexpr</span> <span class="hljs-keyword">int</span> expr { <span class="hljs-number">7</span> }; <span class="hljs-comment">// expr **may** be evaluated at compile time</span>
}
</code></pre>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>{ 
    <span class="hljs-keyword">constexpr</span> <span class="hljs-keyword">int</span> expr { <span class="hljs-number">7</span> }; <span class="hljs-comment">// Because variable x is constexpr, expr must</span>
    <span class="hljs-keyword">constexpr</span> <span class="hljs-keyword">int</span> x { expr }; <span class="hljs-comment">// be evaluted at compile-time</span>
}
</code></pre>
<p>Of course coming from an interpreted language, I’ve never considered how optimisations work or what degree of control the user might have over them. The authors of learncpp.com go into more details and cover a few more optimisation techniques used in compilers.</p>
<h3 id="heading-the-static-keyword-does-completely-different-things-depending-on-where-it-is-used">The <code>static</code> keyword does COMPLETELY different things depending on where it is used</h3>
<p>Static means a few different things in C++. Static-scope refers to objects that remain in-scope throughout the life of the program when it is run (as opposed to automatic-scope variables which go out of scope as soon as the execution gets past the braced section (block statement) of code inside which the variable was declared.)</p>
<pre><code class="lang-cpp"><span class="hljs-keyword">int</span> x { <span class="hljs-number">80</span> };    <span class="hljs-comment">// x is a global variable. global variables have static-scope </span>

<span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">main</span> <span class="hljs-params">()</span> </span>{
    <span class="hljs-keyword">int</span> y { <span class="hljs-number">100</span> };    <span class="hljs-comment">// y has automatic scope</span>
    {
        <span class="hljs-keyword">int</span> z { <span class="hljs-number">120</span> };    <span class="hljs-comment">// z also has automatic scope</span>
    }    <span class="hljs-comment">// z goes out of scope here</span>
}    <span class="hljs-comment">// y goes out of scope here</span>
<span class="hljs-comment">// x remains in scope until the program exits</span>
</code></pre>
<p>The <code>static</code> keyword can be used to declare a statically scoped variable within a block of code. Doing so will create a static local variable. This variable will exist in memory throughout the life of the program, just like a global variable. The difference is that the static local variable is only accessible from within the block statement. This is useful in functions that are called multiple times where we want an object used in the function to persist between function calls (eg. a unique id number that is incremented every time a function is called.)</p>
<p>The static keyword can also be used in the global namespace (not within any block statements). This will make objects and functions internally linked (as non-const global expressions and functions default to external linkeage). This means the internally linked global variable is only accessible within the translation unit (file) that they are declared in. Externally linked globals on the other hand can be accessed from any translation unit.<br />There’s so much more under this topic including namespaces, using directives, and inline functions. <a target="_blank" href="https://www.learncpp.com/cpp-tutorial/compound-statements-blocks/">Chapter 7</a> is a brilliant read for anyone who finds C++ semantics daunting at first glance.</p>
<h3 id="heading-templating-classes-functions-aliases-oh-my">Templating classes, functions, Aliases - Oh my!</h3>
<p>Seeing an unfamiliar symbol in a language can be a bit spooky. You might spend some time ignoring it, hoping it’ll go away. After all, surely those angled brackets are more afraid of you than you are of them. right? Let’s hope so. Angled brackets are used in C++ in templating, both declaring and invoking. lets see my beautiful examples.</p>
<p>In Python, everything is <em>sort of</em> pass by reference and <em>completely</em> untyped. That is, any object can become any type at any time with not so much as a judgmental side-eye from the interpreter. It will happily create a single array of <code>[int, int, char, string, double, whateveryoulike]</code> and allow users to change any of those array items into anything else. I knew going into C++ that this wasn’t the case as I had messed around with statically typed languages like Java and Arduino C before. So if a user were to try to define a function (or class) in C++, the compiler would need to know exactly what types it can expect as function parameters (or class members).</p>
<pre><code class="lang-cpp"><span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;iostream&gt;</span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;string&gt;</span></span>
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">myprintfunc</span><span class="hljs-params">(<span class="hljs-built_in">std</span>::<span class="hljs-built_in">string</span> x)</span> </span>{
    <span class="hljs-built_in">std</span>::<span class="hljs-built_in">cout</span> &lt;&lt; <span class="hljs-string">"my parameter: "</span> &lt;&lt; x &lt;&lt; <span class="hljs-string">"\n"</span>;
}

<span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">main</span> <span class="hljs-params">()</span> </span>{
    myprintfunc(<span class="hljs-string">"spaghetti"</span>); <span class="hljs-comment">// outputs: "my parameter: spaghetti"</span>
    myprintfunc(<span class="hljs-number">8.5</span>); <span class="hljs-comment">// compile time error: no matching function for parameter of type "float"</span>
}
</code></pre>
<p>In the above example, we have a function that can take a string. But what if we wanted to pass it a float? One way to solve this would be to write overloaded functions for each parameter type that users are expected to need. This would quickly become a long and tiresome task. Codebases might have hundreds of functions like this. Each would need overloaded versions for each parameter type. It would also rely on the programmer to know exactly what types are expected and to not mistakenly forget any types.</p>
<p>The neat C++ alternative is to use templating (the spooky, scary angled brackets <code>&lt;&gt;</code>). By using a templated function here, the compiler can be instructed to generate its own overloaded functions as required by the code that calls it.</p>
<pre><code class="lang-cpp"><span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;iostream&gt;</span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;string&gt;</span></span>

<span class="hljs-keyword">template</span> &lt;<span class="hljs-keyword">typename</span> T&gt;
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">myprintfunc</span><span class="hljs-params">(T x)</span> </span>{
    <span class="hljs-built_in">std</span>::<span class="hljs-built_in">cout</span> &lt;&lt; <span class="hljs-string">"my parameter: "</span> &lt;&lt; x &lt;&lt; <span class="hljs-string">"\n"</span>;
}

<span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">main</span> <span class="hljs-params">()</span> </span>{
    myprintfunc&lt;<span class="hljs-keyword">int</span>&gt;(<span class="hljs-number">8</span>);         <span class="hljs-comment">// outputs: "my parameter: 8"</span>
    myprintfunc&lt;<span class="hljs-keyword">double</span>&gt;(<span class="hljs-number">8.5</span>);    <span class="hljs-comment">// outputs: "my parameter: 8.5"</span>
    myprintfunc&lt;<span class="hljs-built_in">std</span>::<span class="hljs-built_in">string</span>&gt;(<span class="hljs-built_in">std</span>::<span class="hljs-built_in">string</span>(<span class="hljs-string">"hello world"</span>));    <span class="hljs-comment">// outputs: "my parameter: hello world"</span>
}
</code></pre>
<p>Behind the scenes, the compiler generates overloaded functions every time the function is called with a new type in <code>&lt;&gt;</code> angled brackets.<br />In C++20 and newer, the angled brackets can be omitted sometimes if the type can be inferred.</p>
<p>Templating can also be used to create class templates in much the same way. It just allows the user to create objects of that class with any type substituted for T. Templating is used a lot in the standard library (eg. in std::array and std::vector for example). I use templating in all my classes in my Cpp data structures and algorithms library.</p>
<h3 id="heading-overloading-operators-and-functions">Overloading operators (and functions)</h3>
<p>Operators in C++ are implemented as functions. The arguments to the operator are the operands that appear on either side of it. Operators can be unary, binary or ternary where they have 1, 2 or 3 arguments (eg. <code>-19</code> uses the unary <code>-</code> operator to flip the sign of the value, <code>2+2</code> uses the binary <code>+</code> operator to add the arguments on either side of it.)[2]</p>
<p>Just like functions, operators can be overloaded to extend their functionality. Lets say for example, we create a new class. If we try to send an instance of that class to the output stream via the <code>&lt;&lt;</code> operator, we will get a compilation error because <code>&lt;&lt;</code> doesn’t know what to do with our new class. We can overload it to “teach” it how to print to console.</p>
<pre><code class="lang-cpp"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Myint</span> {</span>
<span class="hljs-keyword">public</span>:
    <span class="hljs-keyword">int</span> m_int {<span class="hljs-number">30</span>};
};

<span class="hljs-built_in">std</span>::ostream&amp; <span class="hljs-keyword">operator</span>&lt;&lt; (<span class="hljs-built_in">std</span>::ostream&amp; out, <span class="hljs-keyword">const</span> Myint&amp; myint)
{
    out &lt;&lt; myint.m_int;
    <span class="hljs-keyword">return</span> out;    <span class="hljs-comment">// we have to return std::cout here so we can chain &lt;&lt; operators together.</span>
}
}

<span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>{
    Myint newint {};
    <span class="hljs-built_in">std</span>::<span class="hljs-built_in">cout</span> &lt;&lt; newint;    <span class="hljs-comment">// prints myint.m_int to console</span>
}
</code></pre>
<p>When overloading a binary operator, the 1st parameter is the left operand (what appears on the left side of the operator in normal use) and the 2nd parameter is the right operand. We can overload operators outside any class body (as above) or we would overload operators using member functions (also known as methods). Because member functions 1st argument is always the implicit object (<code>this</code> in C++, <code>self</code> in python, Java and others) we can omit the 1st argument in the definition as we would a member function definition.</p>
<p>I’ve never stopped to consider how operators are implemented in a language before. Since learning about operator overloading in C++, I will always be thinking about this whenever I learn a new language.</p>
<h3 id="heading-the-delete-specifier">the <code>= delete</code> specifier</h3>
<p>For a language known for being strict and explicit, there’s actually a lot of ways that C++ allows implicit conversions, promotions, and type inference.</p>
<p>For example, chars can be implicitly converted to integral types. If we have a function that accepts an <code>int</code> parameter, but it is called with a parameter of type char, the char will be implicitly converted into an int so that the function may be used.</p>
<p>If we need to prevent this behavior, we can tell the compiler not to use specific overloads of the function.</p>
<pre><code class="lang-cpp"><span class="hljs-comment">// code example from learncpp.com (https://www.learncpp.com/cpp-tutorial/deleting-functions/)</span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;iostream&gt;</span></span>

<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">printInt</span><span class="hljs-params">(<span class="hljs-keyword">int</span> x)</span>
</span>{
    <span class="hljs-built_in">std</span>::<span class="hljs-built_in">cout</span> &lt;&lt; x &lt;&lt; <span class="hljs-string">'\n'</span>;
}

<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">printInt</span><span class="hljs-params">(<span class="hljs-keyword">char</span>)</span> </span>= <span class="hljs-keyword">delete</span>; <span class="hljs-comment">// calls to this function will halt compilation</span>
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">printInt</span><span class="hljs-params">(<span class="hljs-keyword">bool</span>)</span> </span>= <span class="hljs-keyword">delete</span>; <span class="hljs-comment">// calls to this function will halt compilation</span>

<span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span>
</span>{
    printInt(<span class="hljs-number">97</span>);   <span class="hljs-comment">// okay</span>
    printInt(<span class="hljs-string">'a'</span>);  <span class="hljs-comment">// compile error: function deleted</span>
    printInt(<span class="hljs-literal">true</span>); <span class="hljs-comment">// compile error: function deleted</span>

    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
}
</code></pre>
<p>This can be combined with a deleted function template to only allow a specific type to be used.</p>
<p>I like the fine-grained control this gives me as a programmer working in C++. Python type hints are nice, but things like this and constexpr make me feel empowered to write fast code while taking preventative measures against user error.</p>
<h3 id="heading-copy-constructors-and-deep-copy-vs-shallow-copy">Copy constructors and deep copy vs shallow copy</h3>
<p>Classes have a special kind of constructor called a copy constructor. Even if we don’t define it, the class will have an implicit (default) copy constructor. The copy constructor is invoked whenever an instance of the class is copied. This can be done explicitly when we initialise a new object with another object of the same class. The copy constructor is also called automatically[3] when we pass an object by value and when a function returns an object by value (as opposed to by reference or address).</p>
<p>The thing about the copy constructor is that it defaults to shallow copy. That is, unless we specify our own copy constructor, our class will be copied member-wise and if we have any dynamically allocated members (members that are actually pointers to an object in memory on the heap), the pointer will be copied, not the data that they point to. This saves time but will lead to the data having two copies of an object pointing to the same data. If one object’s destructor is called and it destroys the data it’s pointing to, the copy of the object will be pointing to unallocated memory and using it will lead to undefined behavior.</p>
<p>Deep vs Shallow copies was a concept I was familiar with in theory but had never had to implement in practice. Since reading this section, I implemented deep copy constructors in my data structures library.</p>
<h3 id="heading-l-values-r-values-and-temporaries">L-values, R-values, and temporaries</h3>
<p>The way I remember the difference in my head is that L-values are anything that would sit comfortably on the left side of an assignment operator. But the authors of learncpp.com have a better definition.</p>
<blockquote>
<p>An <strong>lvalue</strong> (pronounced “ell-value”, short for “left value” or “locator value”, and sometimes written as “l-value”) is an expression that evaluates to an identifiable object or function (or bit-field).</p>
</blockquote>
<p>The importance of l-value expressions may not be apparent until we know what r-values do. An r-value is the opposite of an l-value. An r-value evaluates to a value, not an object. This becomes tricky because some functions (and operators) expect certain arguments to be L-values and others to be r-values. L-values will be implicitly evaluated into the their value to get an r-value. However, r-values cannot be converted into an L-value. The assignment operator <code>=</code> expects an L-value on the left and an r-value on the right, if an L-value is placed on the right, it will be converted into an r-value. The distinction is important because r-values can behave differently in functions to L-values. Ref qualifiers can be used in function definitions to change how functions handle references to L-values and references to r-values.</p>
<p>The given example for this is when using an accessor that provides a reference to a member when the implicit object is an r-value. This is dangerous because when the statement in which the r-value is used is finished, the r-value is destroyed. If there are any remaining pointers or references to the now destroyed r-value object, accessing them will result in undefined behaviour.</p>
<pre><code class="lang-cpp"><span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;iostream&gt;</span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;string&gt;</span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;string_view&gt;</span></span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Thing</span>
{</span>
<span class="hljs-keyword">private</span>:
    <span class="hljs-built_in">std</span>::<span class="hljs-built_in">string</span> m_name{};
<span class="hljs-keyword">public</span>:
    Thing(<span class="hljs-built_in">std</span>::string_view name)
        : m_name {name} 
        {
        }

    <span class="hljs-function"><span class="hljs-keyword">const</span> <span class="hljs-built_in">std</span>::<span class="hljs-built_in">string</span>&amp; <span class="hljs-title">getName</span><span class="hljs-params">()</span> <span class="hljs-keyword">const</span> </span>{<span class="hljs-keyword">return</span> m_name;} <span class="hljs-comment">// accessor returns a reference</span>
};

<span class="hljs-comment">// createThing() returns a Thing by value (which means the returned value is an rvalue)</span>
<span class="hljs-function">Thing <span class="hljs-title">createThing</span><span class="hljs-params">()</span>
</span>{
    Thing newThing {name};
    <span class="hljs-keyword">return</span> newThing;
}

<span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span>
</span>{
    <span class="hljs-comment">// reference becomes dangling when return value of createThing() is destroyed</span>
    <span class="hljs-keyword">const</span> <span class="hljs-built_in">std</span>::<span class="hljs-built_in">string</span>&amp; thingName {createThing().getName()}; 
    <span class="hljs-built_in">std</span>::<span class="hljs-built_in">cout</span> &lt;&lt; thingName &lt;&lt; <span class="hljs-string">'\n'</span>; <span class="hljs-comment">// undefined behavior</span>
}
</code></pre>
<p>Temporary objects (also anonymous objects) are objects that are created in an expression just for the duration of the expression, after which they will be destroyed. When a function returns by value, that means the resulting value will be an r-value. Because the r-value in the above example is a temporary object, when the statement finishes, it is destroyed and <code>thingName</code> becomes dangling.</p>
<p>I know that section was a mouthful. I’m not great at explaining it. Check out <a target="_blank" href="https://www.learncpp.com/cpp-tutorial/value-categories-lvalues-and-rvalues/">chapter 12</a> for a better explanation and read the rest too because it’s really good.</p>
<h3 id="heading-array-decay-c-style-arrays-are-not-just-pointers">Array decay (C-style Arrays are not <em>just</em> pointers)</h3>
<p>This isn’t actually a C++ thing so much as a fun-fact about C that is brought up. I wrote it down because that’s something I (and many others) learned in uni. C-style arrays are just pointers, right? WRONG! But because doing just about anything to them will turn them into pointers (array decay). Seriously:</p>
<blockquote>
<p>In most cases, when a C-style array is used in an expression, the array will be implicitly converted into a pointer to the element type, initialized with the address of the first element (with index 0). Colloquially, this is called <strong>array decay</strong> (or just <strong>decay</strong> for short).</p>
</blockquote>
<p>Thus, many people have the incorrect belief that arrays and pointers are one and the same in C. And from that, the idea that arrays don’t know how long they are in C. They do. As long as we have a non-decayed array, we can find the length of it, for example, by passing it as an argument to the sizeof() function. In practice this doesn’t help because if we have an undecayed array, we likely defined its length.</p>
<p>Because of this is generally agreed that C-style arrays are totally whack, thus it’s recommended to use the standard library classes std::array and std::vector.<br />I thought it was a neat piece of information to take back into an C projects I do in the future.</p>
<h3 id="heading-further-reading">Further reading…</h3>
<p>There’s so much more on this website including smart pointers, copy elision, standard library algorithms, and more. These are just the things I took note of as particularly interesting or weird. I hope the inspired reader goes and reads the whole thing. I’d recommend it to any software engineer. C/C++ is the foundation that many other languages build on top of. I’ve been working in software for a few years now and never known that this delightful fountain of knowledge was here all along. Have I “learned” C++? No. I plan to build all my projects in C++ for a little while to get a handle on the language. After that I’ll try my hand at other systems-level languages like Odin or Zig (I think I’ll appreciate them more after I’ve worked in C++ for a while).</p>
<p>Brain-space is a funny thing. There always seems to be more of it hiding around every corner. I managed to fill a lot of knowledge gaps these past 2 months and when the time comes to learn another language, I will be so much better at it for having learned how C/C++ works. Thanks, me from 2 months ago.</p>
<hr />
<p>[1] Also Hashimoto says he wouldn’t do this in the interview. He explicitly says “I would not do this with C++” so take from that what you will.</p>
<p>[2] operator precedence is another interesting topic I hadn’t thought about before reading. And it’s not just BOMDAS order of operations. Have you ever considered the <code>=</code> assignment operator? It’s a binary operator too and can be overloaded.</p>
<p>[2] if the copy is not elided in compilation.</p>
]]></content:encoded></item><item><title><![CDATA[A Christmas Ramble]]></title><description><![CDATA[Let’s put a bow on this website-making project. We set out to create a website in Django and to host it in AWS. The primary goal was to learn the Django framework because that was what we did at my workplace at the time. These days, however, I no lon...]]></description><link>https://blog.samjdrew.com/a-christmas-ramble</link><guid isPermaLink="true">https://blog.samjdrew.com/a-christmas-ramble</guid><category><![CDATA[AWS]]></category><category><![CDATA[#AWSPricing #CloudCosts #AWSBudgeting #CostOptimization #PricingOptions #AWSBilling #SavingsPlans #ReservedInstances #SpotInstances #CloudFinance ]]></category><category><![CDATA[Cloud Computing]]></category><category><![CDATA[webhosting]]></category><dc:creator><![CDATA[Samuel Drew]]></dc:creator><pubDate>Sat, 21 Dec 2024 08:49:12 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1734736796290/17fcc22d-0272-4e15-8073-3e1b7b7cd623.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Let’s put a bow on this website-making project. We set out to create a website in Django and to host it in AWS. The primary goal was to learn the Django framework because that was what we did at my workplace at the time. These days, however, I no longer need to use Python/Django and my interests are focused generally in systems-level programming, and less-so in website development.<br />There’s a few outstanding items that I have to address in this post. So without further TODOs (I’m hilarious btw), lets take a look at what we did to bring down our aws billing to less than a quarter of our previous Elastic Beanstalk costs and how the website has handled the shift.</p>
<hr />
<h2 id="heading-measurable-indifference">Measurable Indifference</h2>
<p>Following on from <a target="_blank" href="https://blog.samjdrew.com/finops-is-a-conspiracy-by-big-ops-to-make-you-use-more-fin">my last post</a>, I mentioned that we would be looking to move from Elastic Beanstalk to EC2 spot requests. EB was useful. Initially, it was a great starting point. But after our foray into Elastic Beanstalk to get the website live, I've come to the following conclusion:<br />EB is for people with new projects that just want to get started and don't much care how anything works or how much it costs[^1].<br />I’m not pointing fingers because this was me <a target="_blank" href="https://blog.samjdrew.com/devlog-1-hosting-my-django-website">not too long ago</a>. Something I’ve learned since leaving full-time work is that it pays to know how to actually put it together yourself so that you can cut out the bits that you don't need and minimise the costs that you can.</p>
<p>Here’s what I did…</p>
<p>In my last post, we distilled the dizzying morass that was our AWS billing page into 3 distinct actions we can take to reduce our total spending on the website.</p>
<ul>
<li><p>Remove all static IPv4 addresses</p>
</li>
<li><p>Decommission the Network Load Balancer that was doing nothing but routing https to http and handling the SSL for us</p>
</li>
<li><p>Move from Elastic Beanstalk to a spot fleet to host the Django app</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1734741746214/abdba55e-6486-45e7-9fd3-87ca9b01f971.png" alt class="image--center mx-auto" /></p>
<p><em>The last three months of AWS bills has felt like a warm hug from my wallet</em></p>
<p>Now you might be thinking, “well, yeah of course it costs less, we now have to do all the server management and scaling ourselves!” To which I say the short answer is yes… and no… twice…</p>
<p><strong>Yes, it’s a bit more work:</strong> we will need to manage the server configuration now. But that’s good! we want to know exactly what’s running on our instance (instead of vaguely knowing that Django is being used to handle http requests <em>somehow</em>).</p>
<p><strong>And “no”</strong>: The whole server configuration can be defined in a single script that gets run every time the server starts. No ongoing management required, just set and forget.</p>
<p><strong>Yes, scaling is something to manage</strong>: If we were managing any kind of load on my website, we would have to set up scaling rules.</p>
<p><strong>But “no” because</strong>: Until we start seeing the thousands of readers and clients that my mum says I deserve, we can stick to the smallest morsel of compute power that AWS can charge for.</p>
<h3 id="heading-server-configuration-in-one-file">Server Configuration in one file:</h3>
<p>First, we switched off the EB which removed all the resources in commissioned including the expensive Load Balancer and the unnesesary static IP addresses.</p>
<p>We then needed to define our own basic VPC. This can be just a standard public VPC with an internet gateway and 3 public subnets, one in each ap-southeast-2 availability zone (we have no backend database so public subnets will do just fine for our purposes).</p>
<p>Next, we moved the server to a spot fleet request (‘fleets’ can be configured to be 1 instance). The request uses a configuration object called a ‘launch template’ containing all our capacity and compute preferences and configuration information.</p>
<p>The spot request will look for the cheapest of any t2.micro, t2.small, t3.micro, or t3.small available in any AZ in ap-southeast-2 and assign it to the appropriate subnet in our VPC. The instance is then automatically given a public IP address by our VPC.</p>
<p>The launch template also includes a "user data" section that is executed every time the server instance starts up. If you’re more familiar with Docker, you can think of the ‘launch template’ as AWS lingo for a dockerfile and the confusingly named "user data" section is an entrypoint script that gets called in your image's dockerfile. The point is, all the code in “user data” gets run. <strong>First thing.</strong> As soon as our instance is running.<br />This is very important because spot instances will get interrupted semi-regularly by aws (I've found mine are replaced at least once per day).</p>
<p>Every time our EC2 instance changes, our “user data” should perform the following actions:</p>
<ol>
<li><p>Find the instance’s public IP address (These first three steps are required because we now have no load balancer and therefore no static IP address to always route traffic to. So whenever a new server is started, we have to directly edit the A record in our DNS settings to tell the internet that the website's host server is now <em>here</em>).</p>
</li>
<li><p>Change our Route53 A record to set <a target="_blank" href="http://samjdrew.com">samjdrew.com</a> to go to this new instance’s public IP.</p>
</li>
<li><p>Search our code packages S3 bucket for the latest version of the website and unzip it.</p>
</li>
<li><p>Install Python 3.11 and NGINX.</p>
</li>
<li><p>In the unzipped source code, activate Django's python venv and install requirements.</p>
</li>
<li><p>Configure gunicorn daemon workers to run the Django app.</p>
</li>
<li><p>Start gunicorn and NGINX.</p>
</li>
<li><p>use certbot-nginx to assign a free SSL certificate and set up https on nginx [²].</p>
</li>
</ol>
<p>The interested reader can check out the actual code over on <a target="_blank" href="https://github.com/MountainBean/Online/blob/master/.ec2config/userdata.sh">my website repo</a>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1734757788955/9ad3b0a6-8874-434e-b3ec-b1adddd4ca81.png" alt class="image--center mx-auto" /></p>
<p><em>Do diagrams help? In my head, it’s simpler than this makes it look.</em></p>
<p>This is everything we need. And that’s how I’ve left it for the past 3 months. Of course, now and again, I check in on the website as often as my ego prompts me to but it’s been up every time I’ve checked. I half expected there to be some disarray somehow manifesting from my negligence but it looks like we’ve written a good system.</p>
<h3 id="heading-lets-briefly-consider-scalability">Let’s briefly consider scalability</h3>
<p>The magic word of cloud platform engineering - scalability - is a term thrown around so much, you’d think it’s a requirement for any cloud-hosted solution. There’s a section in chapter one of Martin Kleppmann’s <em>Designing Data-Intensive Applications:</em></p>
<blockquote>
<p>[Scalability] is not a one-dimensional label that we can attach to a system: it is meaningless to say “X is scalable” or “Y doesn’t scale.” Rather, discussing scalability means considering questions like “If the system grows in a particular way, what are our options for coping with that growth?” and “How can we add computing resources to handle the additional load?” -</p>
</blockquote>
<p>The rest of the section goes on to point out that <em>before</em> we discus scalability, we need to have a way to measure load on the system and the performance of the system. We also need to know what our performance goals for the system are. Do we want the 99.9th percentile to experience webpage load times of less than 1 second? Is that doable? How much work will that take? What about the 99.99th percentile?</p>
<p>In a commercial setting, this makes a lot of sense. Having a way to reduce your cloud spending when traffic is low and only increase when demand for your service goes up is the Great Cloud Dream™. Scaling up and/or out at peak volume periods and scaling back down/in when traffic usually dies down is a neat, effective way to minimise wasted resources and is one of the major selling points of Cloud resources over on-prem. Autoscaling is the sledgehammer approach and is only really appropriate when you’re dealing with unpredictable loads.</p>
<p>Scalability is a tool - or maybe a power-tool, to present a more visual analogy. It can and should be used but only AFTER:</p>
<ol>
<li><p>Defining <em>how</em> you’ll measure performance and load</p>
</li>
<li><p>Using those definitions to define your Service Level Objectives (SLO and SLA if you’re working with a client)</p>
</li>
<li><p>Setting up billing alerts (which should be done as soon as you set up any cloud hosting account that’s tied to your wallet)</p>
</li>
</ol>
<p>For this website, there’s no sense in implementing an autoscaling group with a maximum instance count greater than 1 because our 1 instance should be able to handle <a target="_blank" href="https://docs.gunicorn.org/en/latest/design.html#how-many-workers">hundreds of requests per second</a>.<br />As far as we’re concerned, we can be content in the knowledge that the small handful of clients or employers who bother to click on our website are getting our website.</p>
<h3 id="heading-the-left-overs">The left-overs</h3>
<p>There were some issues beneath the surface that I haven’t addressed:</p>
<ul>
<li><p><s>Github actions were broken since moving away from Elastic Beanstalk meant we had to come up with a way of getting my source code onto the server (this was particularly embarrassing for me to ignore for so long as someone who once had </s> <em><s>DevOps</s></em> <s>in his job title).</s></p>
<ul>
<li>This is fixed now. After merging to master, github actions sends a zipped package of the code to an S3 bucket, removes the “-latest” suffix from the old package and appends it to the new one, temporarily scales the spot fleet to 2 instances and then terminates the old instance after 3 minutes. The new instance handles all the server set up and domain redirection as described above and a new version of our website is live about 4 minutes after we merge to master.</li>
</ul>
</li>
<li><p>The pages on certifications and experience still haven’t been implemented, which is hilarious for a website that’s supposed to be a portfolio landing page</p>
</li>
<li><p>we don’t talk about the photography website.</p>
</li>
</ul>
<p>Jumping back into this project after three months, after not thinking about or working on anything Python/Django, I found it daunting trying to remember how Django organises itself. Python/Django has taken a sharp nose-dive in my list of priorities and unfortunately, the website has been in limbo because of that.</p>
<p>I’ll always be intrigued by cloud platforms and automating build systems. However, in my spare time, I’ve been trying to expand into a few new areas that I’m not familiar enough with.</p>
<p>In the past 3 months, I've:</p>
<ul>
<li><p>learned to use Cmake/ninja to build large C projects</p>
</li>
<li><p>been <em>re</em>-learning C/C++ and assembly</p>
</li>
<li><p>Learned to draw a triangle in OpenGL</p>
</li>
<li><p>reading:</p>
<ul>
<li><p>Martin Kleppmann's <em>Designing Data-Intensive systems</em> and</p>
</li>
<li><p>Thorsten Ball’s <em>Writing an Interpreter in Go</em></p>
</li>
</ul>
</li>
<li><p>Been working on my own indie game in Godot 4</p>
</li>
</ul>
<p>The point is, everything I learned about django/python and HTML/CSS while throwing this website together this year is buried under several dense layers of unrelated CS stuff that I had to sift through to write this. The Python/Django atrophy has begun and I don’t want to strain myself trying to strengthen those muscles again when it’s no longer a thing I need for my job and I have other priorities preceding it.</p>
<p>This isn’t the post for discussing learning goals and professional growth[³]. I just wanted to wrap up the last outstanding thing I said I’d write about with regards to creating and hosting a website.</p>
<p>Some day I may start measuring data from my nginx access logs and use that data to make a more informed decisions around scaling and traffic. But at the moment, I have other things I’m excited to learn about and the website is up so I’m not fussed.</p>
<p>Just one more thing, my old domain mountainbean.online expired this week and my domain registrar wanted me to pay $80 US to renew it which was never going to happen. Thus you may have noticed I’ve moved to samjdrew.com. If the savvy reader has any idea where I can get better domain registrars that don’t hold my domain to ransom every year, please write in and let me know. Feedback is also welcome.</p>
<hr />
<p>[^1]: I had a whole analogy here where you would ask your mate to by groceries and cook dinner for you but it turns out your mate got kickbacks from the grocery store so he buys you a bunch of stuff you don’t need to run up your grocery bill. It’s a bit cynical and the analogy was not exactly relatable so decided not to force my up-and-coming novella “Stretchy- Legume Steve” upon you.</p>
<p>[²]: It’s worth noting somewhere that I don’t have to ever worry about renewing my certificates. My servers are rebooted around every 2 days and a new certificate is generated each time. (Edit: turns out this is a problem because if I ever go over 5 certificates in a week, certbot stops giving me new certs that week. I’ll have to work in a way to store, access and renew my certs.</p>
<p>[³]: but if it were, it’d be inspirational af.</p>
]]></content:encoded></item><item><title><![CDATA[FinOps is a conspiracy by big Ops to make you use more Fin]]></title><description><![CDATA[There's an episode in season 2 of Community where Jeff, while doing his very best not to do anything, gets caught up in a comically layered conspiracy about the risks of trying to do nothing. Now I'm not trying to do nothing but right now I don't hav...]]></description><link>https://blog.samjdrew.com/finops-is-a-conspiracy-by-big-ops-to-make-you-use-more-fin</link><guid isPermaLink="true">https://blog.samjdrew.com/finops-is-a-conspiracy-by-big-ops-to-make-you-use-more-fin</guid><category><![CDATA[finops]]></category><category><![CDATA[AWS FinOps]]></category><category><![CDATA[AWS]]></category><category><![CDATA[ec2]]></category><category><![CDATA[Django]]></category><category><![CDATA[vpc]]></category><category><![CDATA[IPv4]]></category><category><![CDATA[ipv6]]></category><dc:creator><![CDATA[Samuel Drew]]></dc:creator><pubDate>Fri, 23 Aug 2024 13:06:48 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1724737380328/71320c54-3e01-43a1-a87b-21b559117d14.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>There's an episode in season 2 of Community where Jeff, while doing his very best not to do anything, gets caught up in a comically layered conspiracy about the risks of trying to do nothing. Now I'm not trying to do <em>nothing</em> but right now I don't have the time to do more than I need to. And the more I can do while <strong><em>not</em></strong> doing (and <strong><em>not paying</em></strong>), the better. This is where my website comes in.</p>
<p>In the act of procuring cloud infrastructure for my website, <a target="_blank" href="https://blog.mountainbean.online/devlog-1-hosting-my-django-website">I've taken some shortcuts</a> and I <em>thought</em> I'd carefully measured the price of those shortcuts and was willing to pay for them. Despite that, when my budget alerts went off a mere 10 days into the month, I was surprised and also kind of annoyed. How can this be?</p>
<p>So for this dev log, I've decided to have a look at my bills and see what we can do.</p>
<p>Oh boy. I don't know why I bothered spending so much time time tinkering my <a target="_blank" href="https://blog.mountainbean.online/devlog-2-getting-s3-connected-to-my-django-website">S3 media file hosting solution</a>. That and most of the other costs related to my website server are dwarfed by this huge, honking Load balancer bill!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724052986708/2fa9505d-5eb4-4579-ab02-abab19f45817.png" alt class="image--center mx-auto" /></p>
<p><em>Load balancer clearly costs more than any other service. However VPC is unusually High too...</em></p>
<p>So yeah what's all that for just a micro T3 EC2 box quietly running a Django app that no one but me uses? I see 3 chunky bars evoking my ire.</p>
<ul>
<li><p>Load Balancer</p>
</li>
<li><p>VPC</p>
</li>
<li><p>EC2 - Compute</p>
</li>
</ul>
<p>Let's address the Load balancer first.</p>
<h4 id="heading-balance-deez">Balance Deez</h4>
<p>I don't see myself as a conspiracy person, but there's a reason AWS tells you <a target="_blank" href="https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/configuring-https.html">"the simplest" way to enable https</a> on your server is by attaching a load balancer. You can see it here in their documentation on the <a target="_blank" href="https://aws.amazon.com/elasticloadbalancing/pricing/"><em>Load Balancer pricing</em></a> page.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724053939900/066da88e-a4ca-4cfa-a960-d9f0989e4e67.png" alt class="image--center mx-auto" /></p>
<p>Straight out of the gate, we're spending upwards of $18 per month just to keep the load balancer on 24/7. That's not even considering the LCUs (Capacity units) used. $18/month is already too much and I'll need to take action to fix this (the action is me ripping it out like a weed, in case you were wondering).</p>
<p>Next up is the VPC. What's that charge for?</p>
<p>Well, dear reader, much like a decently priced rental in Brisbane City, public addresses on the internet are in short supply (that is, IPv4 addresses). This makes them valuable. Valuable enough that <a target="_blank" href="https://repost.aws/articles/ARknH_OR0cTvqoTfJrVGaB8A/why-am-i-seeing-charges-for-public-ipv4-addresses-when-i-am-under-the-aws-free-tier">as of February 2024, Amazon has been charging 0.5 cents per hour</a> for the pleasure of using one. Fast-forward to last month, when I asked Elastic Beanstalk to put my website online. It assumed I was a man of vastly more means than I really am and decided that I must want 3 availability zones each with a public IP address.</p>
<p>I was just a poor developer, trying to find a cheap way to host my website. Now look at me, I have a leak in my bank account of exactly 1.5 cents/hour and I get to think to myself, "boy am I glad my website is highly available".</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724070644186/f31fda92-dc9a-4bd1-9a9e-d817372b5bfc.png" alt class="image--center mx-auto" /></p>
<p><em>1.5 cents per hour makes Sam a poor boy</em></p>
<p>Finally EC2 pricing. There's not much to say.</p>
<p>EC2 charges based on the type of EC2 and data transferred in a given time period. Data transfer is negligible at this stage and the EC2 type is T3-micro, the 2nd cheapest on-demand instance AWS offers. However, there are still some neat little FinOps tricks I can explore here.</p>
<h4 id="heading-yes-finops-is-a-real-word">Yes, FinOps is a real word</h4>
<p>First off, the ALB has to go. There's no sense in my using a Load balancer anyway because my website traffic is featherweight. If that ever changes, I'll scale it up myself. For now paying $18 per month for a fancy server to route https traffic to my single node website is farcical. It's doing nothing but serving the SSL certificate which I can get Nginx to do on the instance for free.</p>
<p>While reconfiguring things, we could reduce our VPC costs by switching to IPv6. This would remove all the IPv4 tolls and our only charges will come from traffic (if we ever break out of free tier). Unfortunately, IPv6 presents a lot of it's own challenges. Namely that neither my home broadband service provider nor my mobile service provider support IPv6. The funny part is that even AWS has spotty IPv6 support! The <em>AWS Instance Connect</em> tool that AWS provides to connect to instances through your browser ALSO doesn't actually support IPv6. Why is any of that relevant? Because practically, yes I can configure and populate an IPv6-only VPC and subnets regardless of whether my ISP or Instance Connect supports IPv6. However, I won't be able to reach them for configuring or debugging my instances because I can't SSH in from home. It seems no one can actually handle the protocol that has been getting "adopted" since 2012.</p>
<p>Well okay. I can at least remove the 2 IPv4 addresses that I'm not using. That'll reduce the VPC costs by 1 cent/hour saving me up to $7.44/month (USD btw so that's actually around 14 dollaroos 🦘).</p>
<p>Finally we need to reduce EC2 costs. Savings plans are an option. According to AWS documentation, this would bring the hourly price of my instance down by 22%. However, I've been wanting to try out creating a spot fleet. It's essentially an autoscaling group but the instances are only ever spot instances. I can configure a spot fleet with a desired capacity of only 1 instance. Spot instances can get reclaimed by AWS at any time as other users are willing to pay the on-demand price. However if you have a spot fleet set up, the instance will be replaced automatically (if possible). Looks like this should bring my EC2 instance costs down around by 35%. If my website goes down for a few minutes or hours between spot instances, I'll live.</p>
<blockquote>
<h4 id="heading-and-a-very-familiar-feeling-is-starting-to-come-over-me-i-feel-like-someone-is-trying-to-teach-me-something-jeff-winger-community-episode-conspiracy-theories-and-interior-design">"...And a very familiar feeling is starting to come over me. I feel like someone is trying to teach me something." - Jeff Winger, Community Episode: Conspiracy Theories and Interior Design</h4>
</blockquote>
<p>To a seasoned Platform Engineer, I'm sure this is some kindergarten-level course-correction. It's not tricky to point out where I've taken shortcuts. I've done the cloud certification exams, I've heard of these issues before and I've been working in AWS for a few years. That's why I know that these are common problems and where to find the solutions. But I've never actually had to foot the bill for my shortcuts. That's what this little project is for (among other things). Unlike Jeff Winger, I'm here to learn and it's all part of the experience.</p>
<p>Keep an eye out for my next post where I'll go through implementing my cost-saving changes and how much my AWS bill actually changes.</p>
]]></content:encoded></item><item><title><![CDATA[Getting S3 Connected to my Django Website]]></title><description><![CDATA[In my last Devlog, I got my Django website hosted on Elastic Beanstalk by uploading a packaged zip of all the application code and the static files including my sample photos. While it was a success and it got the website live, it's not... comfortabl...]]></description><link>https://blog.samjdrew.com/devlog-2-getting-s3-connected-to-my-django-website</link><guid isPermaLink="true">https://blog.samjdrew.com/devlog-2-getting-s3-connected-to-my-django-website</guid><category><![CDATA[Django]]></category><category><![CDATA[AWS]]></category><category><![CDATA[S3-bucket]]></category><dc:creator><![CDATA[Samuel Drew]]></dc:creator><pubDate>Sun, 04 Aug 2024 11:45:20 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1722838584920/3004ac30-5143-4d00-a757-c5b2b342e265.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In my last Devlog, I got my Django website hosted on Elastic Beanstalk by uploading a packaged zip of all the application code and the static files including my sample photos. While it was a success and it got the website live, it's not... comfortable.<br />My code has to be manually zipped up (along with a handful of huge jpegs which bloat out my repo). Then they get pushed manually to Elastic beanstalk via the AWS console.</p>
<p>Now look... no one's saying you must only ever use Terminal to get around, but the thought of clicking my mouse that many times just to push to production makes my little DevOps tummy hurt.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722770540099/d1c2a6be-f9b6-4d3e-8b62-17b19037fba0.png" alt /></p>
<p><em>The Django tech stack ✨idea✨</em></p>
<h6 id="heading-configuring-prod-data-in-dev">Configuring prod data in dev</h6>
<p>So this is just so I don't have to muck around setting up and spending money on a DB. Photo details are all stored in SQLite. That gets uploaded with my code to the repo. I then have Github Actions push that to Elastic Beanstalk, as my manager says, "auto-magically". No dev DB/prod DB disparity. It's just my website. For this moment, the data can be the same.<br />Now what about the photos and any other static files? I should move those to S3.</p>
<p>Firstly, I've set up a bucket with public read access, uploaded my photos there, set up Django to map the media URLs to the s3 bucket. Then I'll sit back and use all the spare time I now have googling ways I could've done it better.</p>
<pre><code class="lang-python">MEDIA_URL = <span class="hljs-string">"/photo_files/"</span>
<span class="hljs-keyword">if</span> DJANGO_WEBSITE_ENVIRONMENT == <span class="hljs-string">"PROD"</span> <span class="hljs-keyword">or</span> DJANGO_WEBSITE_ENVIRONMENT == <span class="hljs-string">"BUILD"</span>:
    AWS_STORAGE_BUCKET_NAME = <span class="hljs-string">"mountainbean-photos-bucket-shepherds-pie"</span>
    AWS_S3_REGION_NAME = <span class="hljs-string">"ap-southeast-2"</span>
    AWS_ACCESS_KEY_ID = getenv(<span class="hljs-string">"S3_WRITE_USER_ACCESS_KEY"</span>)
    AWS_SECRET_ACCESS_KEY = getenv(<span class="hljs-string">"S3_WRITE_SECRET_ACCESS_KEY"</span>)

    AWS_S3_CUSTOM_DOMAIN = <span class="hljs-string">f"<span class="hljs-subst">{AWS_STORAGE_BUCKET_NAME}</span>.s3.amazonaws.com"</span>

    STORAGES = {
        <span class="hljs-string">"default"</span>: {
            <span class="hljs-string">"BACKEND"</span>: <span class="hljs-string">"storages.backends.s3.S3Storage"</span>,
            <span class="hljs-string">"OPTIONS"</span>: {
                <span class="hljs-string">"location"</span>: <span class="hljs-string">"media"</span>
            },
        },
        <span class="hljs-string">"staticfiles"</span>: {
            <span class="hljs-string">"BACKEND"</span>: <span class="hljs-string">"storages.backends.s3.S3Storage"</span>,
            <span class="hljs-string">"OPTIONS"</span>: {
                <span class="hljs-string">"location"</span>: <span class="hljs-string">"static"</span>
            }
        }
    }
</code></pre>
<p>Using the django_storages library, I've configured the public S3 bucket as a backend with a service role that has write-access permission on the bucket. An admin with access to post a new photo on the website (me) now has permissions to upload to the bucket from the website and that photo can be viewed by any visitor via a url to the photo location in the public bucket.</p>
<h6 id="heading-so-whats-with-the-if-statement">So what's with the if() statement?</h6>
<p>When the website is being hosted by elastic beanstalk, I want Django to give out the correct urls to the photos in the S3 bucket. Likewise, when Github actions is deploying the code (there the environment variable will be <em>BUILD</em>) and running collectstatic, I want django to send the static files to S3, not just collect them into a local directory. However, when I'm just working on this on my machine, I don't want those files going anywhere.</p>
<p>So I set: <code>MEDIA_ROOT = BASE_DIR / "uploads"</code> in my <a target="_blank" href="http://Settings.py">Settings.py</a> and:</p>
<pre><code class="lang-python"><span class="hljs-keyword">if</span> settings.DJANGO_WEBSITE_ENVIRONMENT != <span class="hljs-string">"PROD"</span>:
    urlpatterns += static(settings.MEDIA_URL,
                          document_root=settings.MEDIA_ROOT)
</code></pre>
<p>Map that directory to MEDIA_URL in my root <a target="_blank" href="http://urls.py">urls.py</a> so Django will send all my uploaded images there when I'm just in <a target="_blank" href="http://localhost">localhost</a>.</p>
<h6 id="heading-the-catch">The catch</h6>
<p>I have one manual step left. When I make a commit or merge to master (triggering my Github workflow) I have to remember to copy my <em>uploads</em> folder to the public S3 bucket under the <em>media</em> key.<br />Lastly, I should address the issue of uploading my full-size images to the web. I've just shifted the problem from my repo to the S3 bucket. I still have very large JPEGs in my public S3 bucket that I (and any other visitor) will be requesting every time I visit my site.<br />AWS gives you a free 100GB of data transfer out of S3 per month. But if I'm not careful, my big fat JPEGs might use that up quickly. I'll look at resizing uploads next...</p>
]]></content:encoded></item><item><title><![CDATA[Hosting my Django Website]]></title><description><![CDATA[Setting
I've been working on a photography website as a project to force myself to actually learn Django. I enjoy coding and I love taking shitty photos but I've never deigned to host my own work anywhere other than Instagram. By setting a project fo...]]></description><link>https://blog.samjdrew.com/devlog-1-hosting-my-django-website</link><guid isPermaLink="true">https://blog.samjdrew.com/devlog-1-hosting-my-django-website</guid><category><![CDATA[Django]]></category><category><![CDATA[AWS]]></category><category><![CDATA[Elastic Beanstalk]]></category><dc:creator><![CDATA[Samuel Drew]]></dc:creator><pubDate>Sun, 28 Jul 2024 23:39:54 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1722209875937/7e3266f7-2f7a-4a8a-95aa-2e1b949b3970.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h6 id="heading-setting">Setting</h6>
<p>I've been working on a photography website as a project to force myself to actually learn Django. I enjoy coding and I love taking shitty photos but I've never deigned to host my own work anywhere other than Instagram. By setting a project for myself like this, not only do I hope I become less sucky at working with Django, a necessary skill in my particular role at my workplace, one ancillary outcome is that I get to host my photos somewhere more permanently.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722207261766/e0b2308b-ee31-4ad6-8729-451f7a75b54a.png" alt="The progenitor website starting page" /></p>
<p><em>The progenitor website starting page</em></p>
<p>It has three views.</p>
<ul>
<li><p>Starting page: Shows the three most recent photos</p>
</li>
<li><p>All photos: Shows all uploaded photos</p>
</li>
<li><p>Photo detail: Displays a single image with white margins</p>
</li>
</ul>
<p>That's all it does right now. The photos are currently placeholders, <strong>They are</strong> my photos and they will appear in the final product but these particular photos are jpegs that have undergone at least 2x rounds of edits (jpeg's lossy compression gets applied for every edit + save). To be honest, they look fine to me but I'll want make sure the final product looks as good as I can make it. All static files (like the photos) are hosted locally for now. The plan is to put them in an S3 and get Django or Nginx to fetch them.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722207354434/48691a1c-16fe-46fc-9275-6de27bdd4d5b.png" alt class="image--center mx-auto" /></p>
<p><em>Photo detail view</em></p>
<h6 id="heading-resourcing">Resourcing</h6>
<p>Deciding on hosting raises some conflicting feelings. I want to take advantage of my somewhat working knowledge of AWS systems... but I also don't want to over-engineer this site that will likely only be visited by myself, my wife and a handful of job recruiters that actually vet me. I've never actually done this before either. So I'm not taking any shortcuts, nor am I jumping into architectures I have absolutely no business using.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722208467302/7855f6ff-2ffb-4093-8707-e48194e028b6.png" alt="Resourcing initial ✨idea✨" class="image--center mx-auto" /></p>
<p><em>Resourcing initial ✨idea✨</em></p>
<p>This is the basic plan. Chuck it on a tiny EC2. SQLite database to hold all the photo details including the S3 key (so it knows where to reach for it in the S3 bucket). The S3 bucket is just a regular bucket with public access blocked. I'll need to allow the server to access the photos on it via API key. Lets flesh this out a bit.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722208549238/2efa9fa4-9ebf-4c1d-bdce-ef37694a17c2.png" alt="Resourcing ideal version 1" class="image--center mx-auto" /></p>
<p><em>Resourcing ideal version 1</em></p>
<p>So I'm just using SQLite. This is a file-base database system. No need for a dedicated server which simplifies deployment drastically. The drawback here is that it's not quite as fast as a dedicated DB server like Postgres or MySQL would be. So I might have some delays in fetch times as the website grows. However, at this scale I think this will be fine. Similarly, hosting my photos on an S3 bucket means no need to spin up an additional private server. S3 is by far the cheapest option for file storage (probably) and the drawbacks are outweighed at this stage by my chief desires to spend no money and do no work.</p>
<h6 id="heading-first-deployment">First Deployment</h6>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722208583028/da4acee0-6b6e-449c-ae54-45cd984df1a6.png" alt="My Django website's Elastic Beanstalk environment overview" /></p>
<p><em>My Django website's Elastic Beanstalk environment overview</em></p>
<p>Alright, I'm cheating. I'm using a barebone Elastic beanstalk application to spin up my EC2 in an "autoscaling group" of 1 instance, no DB, no VPC, no security groups. Just what is needed. In defence of my laziness, this is all I need at this stage. I wanted it live. It's now live (almost)</p>
<h6 id="heading-deployment-woes">Deployment Woes</h6>
<p>Right off the bat I ran into some problems getting a response from the EC2 instance deployed by elastic beanstalk. After re-deploying 4 times, re-checking my configuration each time, I was fed up. I've been working in AWS too long to get stuck at first deployment. Let's diagnose.</p>
<p>Elastic beanstalk is telling me it's deployed the EC2, added an EIP and added the EC2 to the environment. Good... So what's wrong? The problem is that AWS is getting no responses from the instance. Not just from the Nginx server, but from the whole instance. That tells me it's not connected to the internet. Lets check the instance settings.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722208642147/58037f25-2fc9-4d4b-824c-40fc562a2b69.png" alt /></p>
<p><em>Django website app EC2 instance Networking tab</em></p>
<p>Seeeeems fine... I didn't set any VPC settings so Elastic Beanstalk has taken care of all that for me. Let's look at the VPC and see if it has an Internet gateway.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722208658547/58dcdef9-f716-4cb5-af28-d6363f75a1e1.png" alt /></p>
<p><em>Internet gateway generated by Elastic Beanstalk</em></p>
<p>Okay... is it routed?</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722208674410/074865d6-1d07-4f2f-b911-f8ce74ed9bad.png" alt /></p>
<p><em>Route table generated by Elastic Beanstalk</em></p>
<p>So that's weird right? There should be a route there for outbound packages (anything not going to 172.31.0.0/16). But there's not. Elastic Beanstalk generated everything I asked and then some, but stopped short of actually connecting the VPC to the internet. Let's add it in manually.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722208681520/df2c95aa-1387-4a89-a482-cd44fb7cef53.png" alt /></p>
<p><em>Route table with added route out to the internet gateway</em></p>
<p>I'll cut to the chase. That solved the issue. With my instance now connected to the internet, Elastic Beanstalk is getting responses and I'm able to connect on the default domain it's given me.</p>
<h6 id="heading-ill-leave-it-there-for-today">I'll leave it there for today</h6>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722208727031/1380f952-5d2e-4a8a-89f8-974917cdb671.png" alt /></p>
<p><em>Literally best website you've ever seen</em></p>
<p>After adding the DNS entries for my domain and sorting out SSL, my site is officially on the web. I'm putting out my dirty html for the world to see. Instead of S3 hosting the images, the Nginx server on the EC2 is currently serving the sample images I loaded in with the code. I have many tasks left to do, but for today, this is enough.</p>
]]></content:encoded></item><item><title><![CDATA[Oh *THAT* Extension, it's called "Emmet"]]></title><description><![CDATA[How to fix html boilerplate extension in vs code after installing Django extension for the Django Templating Language: A very specific help article
I'm looking for why something in my code editor broke. It's late, I have work tomorrow, and this can w...]]></description><link>https://blog.samjdrew.com/oh-that-extension-its-called-emmet</link><guid isPermaLink="true">https://blog.samjdrew.com/oh-that-extension-its-called-emmet</guid><category><![CDATA[#emmet #html #htmlelemnts #boilerplate ]]></category><category><![CDATA[vscode extensions]]></category><category><![CDATA[coding]]></category><category><![CDATA[Django]]></category><category><![CDATA[django rest framework]]></category><dc:creator><![CDATA[Samuel Drew]]></dc:creator><pubDate>Sun, 12 May 2024 12:09:30 GMT</pubDate><content:encoded><![CDATA[<h3 id="heading-how-to-fix-html-boilerplate-extension-in-vs-code-after-installing-django-extension-for-the-django-templating-language-a-very-specific-help-article">How to fix html boilerplate extension in vs code after installing Django extension for the Django Templating Language: A very specific help article</h3>
<p>I'm looking for why something in my code editor broke. It's late, I have work tomorrow, and this can wait until after then. So naturally I will not rest until I find a satisfactory answer. Sometimes I try to give these things a solid go of my own before I turn my brain off and ask google.</p>
<p>After banging my head against the screen for far too long, I finally gave up. I'll sacrifice this golden nugget of a learning opportunity for a few more moments of sleep. So I ask google, What is it? Why have my html scaffolds stopped working because I installed the <a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=batisteo.vscode-django">Django extension</a> in VS Code?<br />This thing:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1715988088784/734efb0b-9e4d-40ed-aaf8-1167088f9106.png" alt class="image--center mx-auto" /></p>
<p>I used to be able to just type "html" into an empty file and vs code, putting on it's best mother hen impression, would help the poor baby who's clearly about to hurt himself (yes I'm the poor baby). Anyway, this is the boilerplate:</p>
<pre><code class="lang-xml"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Document<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>Turns out vs code by default has an extension that is where that html boilerplate was coming from. If you're looking closely, you might've already spotted where this extension announces itself.</p>
<p>The Django extension makes Django templating language the default "language" used when working in html files and that breaks it.</p>
<p>But is there a solution (other than just pick which extension you want more)? Well let's look back at the extension details page. "instructions for Emmet"? I had skimmed this. must be irrelevant. never heard of it. Don't use it. those instructions aren't for me...</p>
<p>Emmet. It's called Emmet. Not "html scaffolding". Not "html-boilerplate". Friggin "Emmet". bro.</p>
<p>All this to say learning people's names is already hard. Don't drag tech into this by giving it people names! Give us a hint at least! In the settings, in your extension descriptions, give the project subtitle or something. A hint whatever.</p>
<p>For those wondering I'll add some instructions here:</p>
<h3 id="heading-the-recipe">The Recipe:</h3>
<p>After installing Django extension and finding your html boilerplate is no longer being generated:</p>
<ol>
<li><p>Go into your user or workspace settings and search for 'Emmet: Include languages'</p>
</li>
<li><p>Add an Item 'django-html' with Value of 'html' to the table like this:</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1715990133448/9887d8f7-d9d4-4258-a46e-add492e56dc2.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>That's it. Try making a blank html again. Tell your friends.</p>
</li>
</ol>
<p>I get this is a niche issue that not many people will ever run into. No one is writing a html document from scratch. But just in case, there you go.</p>
<p>Anyway, many thanks to Baptiste Darthenay for the Django extension for vs code. Works great.</p>
]]></content:encoded></item><item><title><![CDATA[Its AWS Time Baby]]></title><description><![CDATA[I've been working in AWS for over 2 years now, and I've always put off acquiring my official AWS certification. I've known it's a worthwhile goal and ever since I started working with cloud applications, I've wanted to do it. Nevertheless, I fall bac...]]></description><link>https://blog.samjdrew.com/its-aws-time-baby</link><guid isPermaLink="true">https://blog.samjdrew.com/its-aws-time-baby</guid><category><![CDATA[AWS]]></category><category><![CDATA[AWS certification]]></category><category><![CDATA[Solutions architecture]]></category><dc:creator><![CDATA[Samuel Drew]]></dc:creator><pubDate>Sun, 17 Dec 2023 23:40:31 GMT</pubDate><content:encoded><![CDATA[<p>I've been working in AWS for over 2 years now, and I've always put off acquiring my official AWS certification. I've known it's a worthwhile goal and ever since I started working with cloud applications, I've <em>wanted</em> to do it. Nevertheless, I fall back to that famous sentiment, the well-worn axiom wielded by the slightly too busy: "I'll do it later".</p>
<p>Well, it's officially later, and I'm starting my AWS Solutions Architect exam prep today. I <em>was</em> going to schedule my AWS Cloud Practitioner exam but that's the foundational certification. It's aimed towards business/marketing majors and professionals from a "non-IT" background.</p>
<p>It's the base level of competency and I've already been operating in that capacity for the past 2+ years.</p>
<blockquote>
<p>Do you have 1-3 years of IT or STEM background? Start with: An Associate-level AWS Certification that aligns with your role or interests. Outcome: Validation of AWS Cloud knowledge and skills; confidence and credibility to build your cloud career.</p>
</blockquote>
<p>Looking at the <a target="_blank" href="https://d1.awsstatic.com/training-and-certification/docs/AWS_certification_paths.pdf">Certification Paths</a> recommended by AWS, It's recommended that individuals in my position skip the cloud practitioner certification and go straight to an associate-level cert like <a target="_blank" href="https://d1.awsstatic.com/training-and-certification/docs-dev-associate/AWS-Certified-Developer-Associate_Exam-Guide.pdf">Developer</a> or <a target="_blank" href="https://d1.awsstatic.com/training-and-certification/docs-sa-assoc/AWS-Certified-Solutions-Architect-Associate_Exam-Guide.pdf">Solutions Architect</a>. I'd like to get both and also go for the DevOps professional-level cert (What AWS calls the pathway of the "Application Architect") but I'm pretty sure associate-level and higher exams cost over 200AUD so we'll see. At the very least, I need to decide which one to go for right now.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702854691685/fb0999e7-1653-43a2-b1e4-c613ec8cdd1f.png" alt class="image--center mx-auto" /></p>
<p>The Solutions Architect role looks to be almost exactly what I've been doing for the past 2 years. Just better. The Developer role, however, seems almost fundamental to getting a tech job but is also not quite as familiar to me.</p>
<p>For now, I'll begin the Solutions Architect exam prep. Solutions Architect will be the fastest to achieve and I can always do the developer one afterwards (if I have the time and funding). I'll be updating this blog as I go with my learnings and thoughts.</p>
]]></content:encoded></item></channel></rss>