<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: UponTheSky</title>
    <description>The latest articles on DEV Community by UponTheSky (@uponthesky).</description>
    <link>https://dev.to/uponthesky</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F768827%2Fee919402-55f1-4933-bfac-9c3360885743.jpeg</url>
      <title>DEV Community: UponTheSky</title>
      <link>https://dev.to/uponthesky</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/uponthesky"/>
    <language>en</language>
    <item>
      <title>[Opinion]Today's frontend is easy to be messed up and we need to organize it</title>
      <dc:creator>UponTheSky</dc:creator>
      <pubDate>Sun, 01 Feb 2026 06:25:49 +0000</pubDate>
      <link>https://dev.to/uponthesky/opiniontodays-frontend-is-easy-to-be-messed-up-and-we-need-to-organize-it-17hl</link>
      <guid>https://dev.to/uponthesky/opiniontodays-frontend-is-easy-to-be-messed-up-and-we-need-to-organize-it-17hl</guid>
      <description>&lt;p&gt;&lt;strong&gt;Disclaimer&lt;/strong&gt;: This post is a mixture of ranting about the complexity of the contemporary frontend, and my thought on how to solve it. I have been away from the frontend/React world for a while, so this post might contain some out-of-date ideas. Please let me know if you find such ideas while reading this post. Also, although I only discuss React/Next.js here, I think the argument could be extended to the entire frontend system as of now, regardless of framework. Therefore I will use the words "frontend" and "React" interchangeably throughout the post.&lt;/p&gt;

&lt;h2&gt;
  
  
  React is dang complex
&lt;/h2&gt;

&lt;p&gt;Lately, I was involved in a task to develop an application where the frontend is to be developed in Next.js. Although I have done a bunch of tasks where I had to use React and Next.js, at those times I didn't have to deal with the design part, and all I was doing was tossing and turning the data from the backend and making React components to present it. However, this was my first time that I had to seriously consider the visual design part as well, from the layout to the font color of a small text under &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; tag. And man, it was super difficult! &lt;/p&gt;

&lt;p&gt;But why? Why was it that difficult? For sure the amount of CSS document pages from MDN was overwhelming, but that was a pretty minor issue. The harder part was that &lt;strong&gt;it was very very easy to write messy React components&lt;/strong&gt; (Here, what I mean by "messy code" is that it is difficult to recognize what the purpose or responsibility of this component is, and very hard to track the behavior and the state updates).&lt;/p&gt;

&lt;p&gt;But before you are about to blame me for my skill issue, calm down and think up of the last React/Next.js code that you encountered. If you can't, visit a few pages about advanced topics in the &lt;a href="https://react.dev/" rel="noopener noreferrer"&gt;official React documentation homepage&lt;/a&gt;. For example, the following is an excerpt of code from the page about &lt;a href="https://react.dev/learn/reacting-to-input-with-state" rel="noopener noreferrer"&gt;managing input and states&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Form&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setAnswer&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&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="nx"&gt;setStatus&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;typing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;success&lt;/span&gt;&lt;span class="dl"&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;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;That's right!&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleSubmit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nf"&gt;setStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;submitting&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;submitForm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nf"&gt;setStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;success&lt;/span&gt;&lt;span class="dl"&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;catch &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="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;typing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nf"&gt;setError&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="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleTextareaChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setAnswer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;City quiz&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        In which city is there a billboard that turns air into drinkable water?
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt; &lt;span class="na"&gt;onSubmit&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleSubmit&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;textarea&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;answer&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleTextareaChange&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;submitting&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;br&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
          &lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;submitting&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          Submit
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Error"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;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;Of course, this is a relatively simple and straightforward example, but there are still lots of things to consume. There are already three states, nested HTML elements, two event handlers, and even a conditionally rendered component, even in a fairly simple and decent example. Why is this so complex?&lt;/p&gt;

&lt;p&gt;Well, I believe that there is an innate issue which is hard to overcome in React (or frontend in general). That is, a React component needs to represent information from a managed state in the form of JSX, which is simply a "nicer" version of HTML. But doesn't this sound way too natural? How could it be an essential problem of React and frontend?&lt;/p&gt;

&lt;h2&gt;
  
  
  Frontend = State + hierarchical presentation
&lt;/h2&gt;

&lt;p&gt;I believe any frontend technologies including mobile ones are essentially about how to manage the current &lt;em&gt;state&lt;/em&gt; (either on the frontend or on the backend) and render it in &lt;em&gt;hierarchical&lt;/em&gt; views. Being hierarchical implies several issues, but to name a few:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How to make the layout: What is the relationship between potentially conflicting sibling HTML nodes? How many children would you put under the current &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt;? How to deal with responsive design?&lt;/li&gt;
&lt;li&gt;How to manage the states: For rendering this particular dataset, are we going to fetch all the resources in a single place and distribute them to several HTML elements, or would it be better to make several API calls from each of the small elements themselves? How about data update and re-rendering? Would it be better to make data fetching in a parent or in its children?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Because state management and layout are essentially coupled but the HTML elements must be hierarchical at the same time, things are very likely to become complex (or as I expressed in the title, &lt;em&gt;messed&lt;/em&gt;). Think about the above excerpt as an example. Suppose you want to switch the &lt;code&gt;&amp;lt;textarea&amp;gt;&lt;/code&gt; element to &lt;code&gt;&amp;lt;selector&amp;gt;&lt;/code&gt; for enabling users to choose the answer rather than typing it manually, but the answer candidates are dynamic, which means you have to fetch the list of the answers from the backend. Then you might "naturally" think of adding &lt;code&gt;useEffect&lt;/code&gt; in the same &lt;code&gt;Form&lt;/code&gt; component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Form&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// [...]&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;countries&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setCountries&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;

    &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;GET_COUNTRY_LIST_API&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nf"&gt;setCountries&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="nx"&gt;countries&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="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nf"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&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="c1"&gt;// [...]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do you think this is a good solution? Some of you might say yes, and others may not. Would it be simpler to fetch &lt;code&gt;countries&lt;/code&gt; here in the same &lt;code&gt;Form&lt;/code&gt; where the data is to be rendered and submitted again, or somewhere else so that &lt;code&gt;Form&lt;/code&gt; is purely responsible for submitting data? There is no absolutely correct or incorrect answer, and it is totally up to the developer to decide. However, whereas there are so-called "best practices" or "design patterns" for the backend, for the frontend there seem to be no such widely used or accepted patterns to the best of my knowledge. &lt;/p&gt;

&lt;h2&gt;
  
  
  Revisiting Container-Presentational pattern
&lt;/h2&gt;

&lt;p&gt;Dan Abramov's famous &lt;a href="https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0" rel="noopener noreferrer"&gt;"Presentational-Container" pattern&lt;/a&gt; provides a useful insight for organizing this mess (for an easier introduction, I recommend reading &lt;a href="https://www.patterns.dev/react/presentational-container-pattern/" rel="noopener noreferrer"&gt;this post on pattern.dev&lt;/a&gt;). From my understanding, you can have the following two patterns of writing React components: &lt;em&gt;stateful&lt;/em&gt;  (or &lt;em&gt;non-functional&lt;/em&gt;) and &lt;em&gt;stateless&lt;/em&gt; (or purely &lt;em&gt;functional&lt;/em&gt;).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Stateful&lt;/em&gt; components manage the application's internal states. They could be either pure client-side states such as the current text value in an input element, or something to be fetched from the backend or third-party APIs. In short, any component with &lt;code&gt;useState&lt;/code&gt;, &lt;code&gt;useEffect&lt;/code&gt;, or &lt;code&gt;fetch&lt;/code&gt; calls is stateful.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Stateless&lt;/em&gt; components are purely functional, in that the data they read is immutable and there is no internal side effect caused by &lt;code&gt;useEffect&lt;/code&gt;. They are only responsible for how to visualize the given data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's get back to the above excerpt. The &lt;code&gt;Form&lt;/code&gt; component is obviously stateful, where it manages several states using &lt;code&gt;useState&lt;/code&gt;. If we ever add &lt;code&gt;useEffect&lt;/code&gt; here for fetching the list of candidate countries, then the component is also responsible for handling data fetched from the backend. &lt;/p&gt;

&lt;p&gt;This separation of concerns is especially useful for maintenance. If you want to add any additional data submission, you can tweak this &lt;code&gt;Form&lt;/code&gt; component. If you have a problem in submitting country text, then there must be something wrong inside this &lt;code&gt;Form&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Furthermore, if we want to refactor this component according to the Presentational-Container pattern, then we separate the HTML components in the &lt;code&gt;return&lt;/code&gt; statement and pass the states and callbacks for state updates like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;FormBox&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;title&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="nx"&gt;answer&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="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;handleSubmit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;handlerTextareaChange&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt; &lt;span class="na"&gt;onSubmit&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleSubmit&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;textarea&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;answer&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
              &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleTextareaChange&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
              &lt;span class="na"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;submitting&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;br&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;
              &lt;span class="nx"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
              &lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;submitting&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
            &lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              Submit
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Error"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&amp;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;However, this logical separation itself may not be enough. Since the frontend elements are hierarchical, there is no limit to putting another stateful element inside a stateless element. If this is the case, then is that stateless element purely stateless? Even if it doesn't manage any state at all, you may have to look into this element because the state you want to check out is managed by this element as a parent.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;FormLayout&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* some other components*/&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Form&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;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;In the above code example, we have &lt;code&gt;Form&lt;/code&gt; inside &lt;code&gt;FormLayout&lt;/code&gt;. Now, although &lt;code&gt;FormLayout&lt;/code&gt; has nothing to do with any form submission logic, you are still very likely to visit this component while searching in your IDE or browser developer tool as long as the &lt;code&gt;FormLayout&lt;/code&gt; component is &lt;em&gt;conceptually&lt;/em&gt; tied to the form submission. Yes, we need a more comprehensive mental model for further organization of our frontend code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Revisiting Atomic Design
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://atomicdesign.bradfrost.com/chapter-2/" rel="noopener noreferrer"&gt;Brad Frost's Atomic Design&lt;/a&gt; suggests another great insight for organizing our React project. Although he introduces five levels of component designs analogous to chemistry, my takeaway is that you can think of an entire frontend page in two aspects. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;em&gt;Layout&lt;/em&gt;: Layout only concerns how to place several visual components on a screen, such as how big this image should be and where to put it, or how we arrange those cards inside a flexbox, etc. This part is purely related to CSS but you need to make sure each individual component doesn't affect the other elements visually such as by unexpected resizing or content overflow.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Feature page&lt;/em&gt;: This is about what this single component is trying to convey with its content to the users product-wise. Please note that I am using the word "single" here, for we want to handle a component with the single responsibility principle. A single product feature can consist of several sub-features. For example, a form submission page can contain several various inputs for text and file upload. Each single feature is responsible for handling UI and data states. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now we can see that the naming &lt;code&gt;FormLayout&lt;/code&gt; is somewhat misleading, in that it can contain not only the form submission page but other features such as the navigation bar or a Google Ads banner. If this is the case, then we might as well use another name such as "QuizPageLayout" instead.&lt;/p&gt;

&lt;p&gt;So far so good, now we have our mental model for separating concerns. There is a hierarchical structure of features for the entire project, and each individual feature should be assigned its own space as a &lt;em&gt;page&lt;/em&gt; by the layout logic at its tree-level. Each feature fetches and updates its own feature data. I would like to refer to this mental model as &lt;strong&gt;Layout - Page&lt;/strong&gt;. Have you noticed any familiar names? You're right. This model works naturally with Next.js.&lt;/p&gt;

&lt;h3&gt;
  
  
  Layout - Page Model
&lt;/h3&gt;

&lt;p&gt;Let's discuss the Layout-Page model in more details in conjunction with the Container-Presentational pattern we discussed previously. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;First, &lt;em&gt;Layout&lt;/em&gt; corresponds to organisms, templates, and pages in Atomic Design. It is responsible only for how to arrange several components on the entire screen. It decides the position, display, and size of each component. It may contain some visual components such as dividers, but those are pretty rare. Layout never deals with how to render each individual component (&lt;em&gt;Page&lt;/em&gt;), even including its margin or padding properties.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Next, each &lt;em&gt;Page&lt;/em&gt; represents a single feature in the product, with the Single Responsibility Principle in mind. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It is responsible for fetching and updating the data relevant to the feature in the backend, and managing the UI states on the client side, if necessary. That is, there could also be stateless and purely functional pages that only visualize the data that is passed to them.&lt;/li&gt;
&lt;li&gt;A page consists of two elements: its own layout and sub-pages(!). Hence, in every single page, there is another layout and sub-pages. If a page only consists of basic HTML elements and no other React components, then we may say this page is a &lt;em&gt;leaf page&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Hence the structure here is recursive. You have a tree of pages, and each page is logically separated into layouts and sub-pages. For example, we can organize the &lt;code&gt;Form&lt;/code&gt; element and possibly related components as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;QuizPage
├── @AdsBanner
│   ├── @Page
│   └── Layout
├── @QuizSubmitPage
│   ├── @Page &lt;span class="c"&gt;# &amp;lt;Form&amp;gt; will be in this page&lt;/span&gt;
│   └── Layout
└── Layout
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that this tree structure is very similar to the structure of Next.js App Router. However, Next.js itself doesn't really enforce any design principles for developers, so you won't find the idea argued here in the Next.js documentation. It is totally up to you, the developer, to decide how to organize your project. However, the mechanism of App Router that Next.js provides fits perfectly with the idea of the Layout-Page model, and in fact, a part of inspiration of this model is from the App Router itself. &lt;/p&gt;

&lt;p&gt;If we translate the structure above into a Next.js file routing system, then it would be like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;quiz
├── @adsbanner
│   ├── page.tsx
│   └── layout.tsx
├── submit
│   ├── page.tsx &lt;span class="c"&gt;# &amp;lt;Form&amp;gt; will be in this page&lt;/span&gt;
│   └── layout.tsx
├── layout.tsx
└── page.tsx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, note that we use a &lt;a href="https://nextjs.org/docs/app/api-reference/file-conventions/parallel-routes" rel="noopener noreferrer"&gt;parallel route&lt;/a&gt; for the ads banner component, since we don't want the user to access the banner only through an exposed route. Also, it is not under &lt;code&gt;submit/&lt;/code&gt; but under &lt;code&gt;quiz/&lt;/code&gt;, which means the banner will show up in the other sub-routes of &lt;code&gt;quiz/&lt;/code&gt;, not limited to its submission page &lt;code&gt;/quiz/submit&lt;/code&gt;. In general, it is essential to utilize the parallel routes in the Next.js App Router system for the Layout-Page model, as there is no guarantee that only one sub-feature exists inside a product feature. &lt;/p&gt;

&lt;p&gt;To recap, the entire recursive tree structure of a project according to the Layout-Page model is like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Project
├── Layout
├── Page0
│   ├── Layout
│   ├── Page00
│   │   ├── Layout
│   │   ├── Page000
│   │   ...
│   ├── Page01
│   ├── Page02
│ ...
├── Page1
├── Page2
├── Page3
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Before the end the post
&lt;/h2&gt;

&lt;p&gt;I would like to mention that this might not be my original idea, and someone somewhere could have already thought of this mental model and publicized under a name that I haven't heard of yet. However, it was not easy for me to come up with this idea after a long time of searching for any useful idea for organizing the frontend &lt;em&gt;messes&lt;/em&gt;, that wasn't much successful. It would be great to see any comments on this. Thank you.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>react</category>
      <category>frontend</category>
      <category>nextjs</category>
    </item>
    <item>
      <title>[Book Review]AI Engineering by Chip Huyen</title>
      <dc:creator>UponTheSky</dc:creator>
      <pubDate>Fri, 28 Nov 2025 17:15:09 +0000</pubDate>
      <link>https://dev.to/uponthesky/book-reviewai-engineering-by-chip-huyen-4e26</link>
      <guid>https://dev.to/uponthesky/book-reviewai-engineering-by-chip-huyen-4e26</guid>
      <description>&lt;p&gt;&lt;a href="https://www.amazon.com/AI-Engineering-Building-Applications-Foundation/dp/1098166302" rel="noopener noreferrer"&gt;Amazon Page&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I finally finished reading AI Engineering by Chip Huyen. It is a truly amazing book in many ways, but to name a few:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;It is comprehensive: From hardware to software, from foundation models to user-facing applications, the author covers almost every aspect we can think of when it comes to AI engineering. I was astonished by how huge the field is, and there are myriad things to know and consider when building an AI-powered application. Of course, the book was published a while ago (early this year), so it cannot cover the most recent updates in the AI industry, but it tries to explain the essential parts rather than excessive details. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It is reader-friendly and well organized: I have read many technical books for my profession, but obviously there are so many books that simply "dump" explanations with insufficient context and incoherent structure. This book reads as if there were a young graduate student tutor at a university who tries to make you understand as much as possible. There are hardly any difficult concepts left unexplained, and each of the chapters has a clear and reasonable structure. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It is a well-grounded technical book: The author doesn't simply tell you what things are based solely on her own opinions. Every paragraph is full of quotations from trusted technical papers, blogs, articles, and more. You might feel like you are reading a technical report or a paper from an AI conference. Therefore, I think this book is very useful as a reference that you can return to frequently. I would probably re-read it a few months.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Overall, I think the book is a very good start to understanding the general concepts of AI engineering and the field itself. Of course, given the depth of its content, the book serves not only as an excellent introduction but also as a valuable reference. &lt;/p&gt;

</description>
      <category>ai</category>
    </item>
    <item>
      <title>[Book Review] Build a Large Language Model (From Scratch) by Sebastian Raschka</title>
      <dc:creator>UponTheSky</dc:creator>
      <pubDate>Wed, 08 Oct 2025 01:25:13 +0000</pubDate>
      <link>https://dev.to/uponthesky/book-review-build-a-large-language-model-from-scratch-by-sebastian-raschka-1286</link>
      <guid>https://dev.to/uponthesky/book-review-build-a-large-language-model-from-scratch-by-sebastian-raschka-1286</guid>
      <description>&lt;h2&gt;
  
  
  TL; DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A very practical book to learn the general concepts of LLMs

&lt;ul&gt;
&lt;li&gt;Saving tons of time from having to search for materials for many topics separately&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Very informative but somewhat intensive; must take some time to follow the book while getting your hands dirty with Python code&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Overall Review
&lt;/h2&gt;

&lt;p&gt;In the era of LLMs, there seem to be a strong demand for understanding them. However, like other "hot" fields, there are so many materials about LLMs and it is not easy to find a solid resource. Either they focus on how to use LLMs (yes, you need &lt;code&gt;OPEN_AI_KEY=your_own_openai_key&lt;/code&gt;!) or fill entire pages with pure texts and diagrams explaining what a transformer architecture is.  &lt;/p&gt;

&lt;p&gt;I know, the field is literally &lt;em&gt;overwhelming&lt;/em&gt;. Developing and serving LLMs is one of the most fast-moving fields both in academia and industry, and there are so many parts to cover, from bare-metal hardware to user experiences on edge devices. Considering tons of papers and codebases out there, I doubted anyone would dare to touch the topic so thoroughly, such as &lt;strong&gt;building an LLM from scratch&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;But here we are - &lt;a href="https://sebastianraschka.com/" rel="noopener noreferrer"&gt;Sebastian Raschka, PhD&lt;/a&gt;&lt;br&gt;
has accomplished such tremendous work in his book &lt;a href="https://www.manning.com/books/build-a-large-language-model-from-scratch" rel="noopener noreferrer"&gt;Build a Large Language Model (From Scratch) &lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;I know there are already thousands, if not millions, of great reviews of the book, so I would like to briefly share my takeaways from reading it over the last few days. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;With only a basic understanding of ML and Python coding, you can grasp the general concepts of how an LLM works from this book. The code examples are not overly technical and clear to understand. &lt;/li&gt;
&lt;li&gt;The explanations are very friendly and thorough. As you work through the book and type out the Python code yourself, you can tell whether you're going in the right direction. However, because the explanations are so detailed, reading through the book make take more time than you expect, given the book's length.&lt;/li&gt;
&lt;li&gt;The book covers core concepts of modern LLMs - token embedding, attention and the transformer architecture, deep learning and neural networks, pre- and post-training(or fine tuning). After finishing the book, I feel more ready to understand articles and posts about topics like attention or KV-cache. &lt;/li&gt;
&lt;li&gt;Personally, it was a very good review of deep learning and neural networks. For people who have no idea what PyTorch is, one of the appendices is dedicated to introducing PyTorch. I highly recommend reading it before diving into chapter 1. &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  My 2 Cents for Those Who Haven't Read the Book Yet
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;My opinion on the prerequisites:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Python: I don't think you need to worry too much about your proficiency with the language. Reading a general introductory book on the language is sufficient. The book doesn't use very sophisticated Python techniques, such as writing your own context managers or decorators. &lt;/li&gt;
&lt;li&gt;Math, Deep Learning, and PyTorch: In addition to basic knowledge of linear algebra, I feel hands-on experience with matrix computation is essential. Especially when it comes to constructing your own attention algorithm, complex tensor multiplications could be somewhat confusing, and you should keep track of the dimension of each of &lt;code&gt;nn.Linear&lt;/code&gt; layers.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Still, running the code on local Apple machines is not desirable. I used my Mac M3 Pro with the &lt;a href="https://docs.pytorch.org/docs/stable/notes/mps.html" rel="noopener noreferrer"&gt;MPS backend&lt;/a&gt;, but a few computation results were different from what those shown in the book. I would try using Google Colab or other similar services on the second read. &lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Appendices are not negligible. I think the one about LoRA is a must-read. Also, I find the ones from the &lt;a href="https://github.com/rasbt/LLMs-from-scratch" rel="noopener noreferrer"&gt;book's Github Repo&lt;/a&gt; are extremely useful to keep up with the recent LLM research and developments. &lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;That's it! This is my short review of the book, &lt;a href="https://www.manning.com/books/build-a-large-language-model-from-scratch" rel="noopener noreferrer"&gt;Build a Large Language Model (From Scratch) &lt;/a&gt;. I hope you enjoy reading it as much as I did!&lt;/p&gt;

</description>
      <category>machinelearning</category>
      <category>llm</category>
    </item>
    <item>
      <title>[Go, Opinion] How can we write truly "middle"ware with Go's net/http?</title>
      <dc:creator>UponTheSky</dc:creator>
      <pubDate>Wed, 01 Oct 2025 07:41:43 +0000</pubDate>
      <link>https://dev.to/uponthesky/go-opinion-how-can-we-write-truly-middleware-with-gos-nethttp-27nk</link>
      <guid>https://dev.to/uponthesky/go-opinion-how-can-we-write-truly-middleware-with-gos-nethttp-27nk</guid>
      <description>&lt;h2&gt;
  
  
  TL; DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A common middleware pattern with the &lt;code&gt;net/http&lt;/code&gt; package cannot handle outgoing responses&lt;/li&gt;
&lt;li&gt;A delicate approach to manipulating &lt;code&gt;Handler&lt;/code&gt; is necessary, but it is still fairly limited&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  So, we all know how to write middleware with Go's &lt;code&gt;net/http&lt;/code&gt;?
&lt;/h2&gt;

&lt;p&gt;After learning and playing around with the &lt;code&gt;net/http&lt;/code&gt; package for a while (of course, with some help from books and other resources), I was pretty satisfied with how I came up with a way to write middleware in Go. It was elegant and very straightforward, as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;AddSomeMiddleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;someFunc&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handler&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandlerFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// do something right before the handler handles the request&lt;/span&gt;
        &lt;span class="n"&gt;someFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c"&gt;// the handler that this middleware wraps around&lt;/span&gt;
        &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ServeHTTP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&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;The function above takes a handler and a function to be invoked &lt;em&gt;before&lt;/em&gt; the handler, and returns a new handler by simply composing them with &lt;code&gt;http.HandlerFunc&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;If you search for how to write middleware in Go, I would say about 7 or 8 out of 10 results will show exactly the same pattern as above. I thought this pattern serves exactly what we need from middleware when writing server applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Middleware of &lt;code&gt;net/http&lt;/code&gt; is only &lt;em&gt;half&lt;/em&gt; middleware
&lt;/h2&gt;

&lt;p&gt;However, I ran into a problem this simple pattern cannot handle. Did you notice? Yes, this middleware cannot touch the response part! Take a look at the code again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;AddSomeMiddleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;someFunc&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handler&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandlerFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;someFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ServeHTTP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c"&gt;// what about afterwards?&lt;/span&gt;
        &lt;span class="c"&gt;// we want something like postProcess(w)&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;Of course &lt;code&gt;AddSomeMiddlware&lt;/code&gt; can still mess with &lt;code&gt;http.ResponseWriter&lt;/code&gt; even after &lt;code&gt;handler.ServeHTTP(w, r)&lt;/code&gt; is invoked. But what if &lt;code&gt;handler&lt;/code&gt; has already written a body that you want to postprocess? &lt;/p&gt;

&lt;p&gt;The problem gets trickier when it comes to writing headers, as once &lt;a href="https://pkg.go.dev/net/http#ResponseWriter" rel="noopener noreferrer"&gt;&lt;code&gt;ResponseWriter.WriteHeader&lt;/code&gt;&lt;/a&gt; has been called:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Changing the header map after a call to &lt;a href="//or%20[ResponseWriter.Write]"&gt;ResponseWriter.WriteHeader&lt;/a&gt; has no effect unless the HTTP status code was of the 1xx class or the modified headers are trailers.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Since &lt;code&gt;ResponseWriter.Write&lt;/code&gt; calls &lt;code&gt;ResponseWriter.WriteHeader&lt;/code&gt; if it has not been explicitly invoked beforehand, you cannot add, remove, or modify the headers (try yourself!). In short, you lose control over the response part once you hand over &lt;code&gt;http.ResponseWriter&lt;/code&gt; to the handler. &lt;code&gt;net/http&lt;/code&gt; expects &lt;code&gt;http.Handler&lt;/code&gt; to finish handling an entire HTTP request. This extraordinary feature of the &lt;code&gt;net/http&lt;/code&gt; package makes our middleware as &lt;em&gt;half&lt;/em&gt; middleware. &lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping another &lt;code&gt;http.Handler&lt;/code&gt; is not a solution
&lt;/h2&gt;

&lt;p&gt;We might &lt;em&gt;trust&lt;/em&gt; an &lt;code&gt;http.Handler&lt;/code&gt; not to write the response, and wrap it with middleware:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;AddSomeMiddleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;someFunc&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;postProcess&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handler&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandlerFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;someFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ServeHTTP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c"&gt;// this postProcess knows nothing about the handler above&lt;/span&gt;
        &lt;span class="n"&gt;postProcess&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&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;Unfortunately, this doesn't resolve the problem at all, since &lt;code&gt;postProcess&lt;/code&gt; knows nothing about what's happening inside &lt;code&gt;handler.ServeHTTP&lt;/code&gt;. What are the headers? What is the status code? Without that information, we cannot send back a response to the client. Also, what about early return? If there is an error inside &lt;code&gt;handler.ServeHTTP&lt;/code&gt;, writing a response afterward is meaningless. &lt;/p&gt;

&lt;p&gt;Moreover, there are several useful functions that help write an HTTP response directly to &lt;code&gt;http.ResponseWriter&lt;/code&gt;. For example, &lt;a href="https://pkg.go.dev/net/http#Error" rel="noopener noreferrer"&gt;&lt;code&gt;http.Error&lt;/code&gt;&lt;/a&gt; is very useful to write a succinct error response, and the &lt;code&gt;encode/json&lt;/code&gt; package has &lt;a href="https://pkg.go.dev/encoding/json#Encoder.Encode" rel="noopener noreferrer"&gt;&lt;code&gt;Encoder.Encode&lt;/code&gt;&lt;/a&gt; that enables writing an &lt;code&gt;application/json&lt;/code&gt; response in a single line.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewEncoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jsonBody&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"internal server error"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusInternalServerError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Therefore, it is very tempting to write the response inside &lt;code&gt;handler.ServeHTTP&lt;/code&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  How about writing custom "handlers"?
&lt;/h2&gt;

&lt;p&gt;One way of resolving this issue would be to write our own handlers that don't expose themselves to the raw &lt;code&gt;*http.Request&lt;/code&gt; and &lt;code&gt;http.ResponseWriter&lt;/code&gt;.  A mock example could be as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Controller handles low-level ResponseWriter and Request&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;SomeController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// parse the raw request&lt;/span&gt;
    &lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;parseRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// middleware for the incoming request&lt;/span&gt;
    &lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requestMiddleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;SomeService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// early return&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"some error message"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;someErrorCode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// middleware for the outgoing response&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;responseMiddlware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// write the response finally&lt;/span&gt;
    &lt;span class="n"&gt;writeResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// custom request&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Request&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// custom response&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// custom handler&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Handler&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This may comes at a cost. It could be overwhelming to redesign the &lt;code&gt;Request&lt;/code&gt; and &lt;code&gt;Response&lt;/code&gt; if we want to do it properly. However, once we know what we're doing, it doesn't have to be difficult. You might not use a brand new &lt;code&gt;Request&lt;/code&gt; at all but instead use the plain &lt;code&gt;*http.Request&lt;/code&gt;. Furthermore, the response type could be this simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="k"&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="n"&gt;cookies&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Cookie&lt;/span&gt;
    &lt;span class="n"&gt;body&lt;/span&gt;    &lt;span class="n"&gt;any&lt;/span&gt;

    &lt;span class="c"&gt;// additional necessary fields&lt;/span&gt;
    &lt;span class="c"&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 what about middleware? One strategy is to divide middleware into two categories:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The first category of middleware directly interact with &lt;code&gt;*http.Request&lt;/code&gt;, such as &lt;a href="https://pkg.go.dev/net/http#TimeoutHandler" rel="noopener noreferrer"&gt;&lt;code&gt;http.TimeoutHandler&lt;/code&gt;&lt;/a&gt;, or the middleware pattern we introduced early in this article. This category provides low-level functionality, such as logging the basic information about the request.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The second category is about the service level of the application, such as &lt;code&gt;requestMiddleware&lt;/code&gt; or &lt;code&gt;responseMiddleware&lt;/code&gt; functions inside &lt;code&gt;SomeController&lt;/code&gt; in the example code. As long as the service logic functions maintain the functional form of &lt;code&gt;func Handler(Request) (Response, error)&lt;/code&gt;, then we can easily chain those functions where wrapping functions work as middleware.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;WrappingServiceHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;beforeMiddleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;WrappedServiceHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// early return&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;afterMiddleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Unless we write our own web framework in Go, this &lt;em&gt;half&lt;/em&gt; middleware pattern is not easy to overcome. In this article, we suggested a pattern with an abstraction cost. Of course, it doesn't resolve all our problems and might incur several edge case problems. &lt;/p&gt;

&lt;p&gt;If we know what we are doing, maybe it is more sensible to repeat the post processing logic right before writing the response inside each of &lt;code&gt;handler.ServeHTTP&lt;/code&gt;. Yes, as usual, &lt;em&gt;it depends&lt;/em&gt;...&lt;/p&gt;

</description>
      <category>go</category>
      <category>webdev</category>
      <category>backend</category>
    </item>
    <item>
      <title>[C#]I tried Primeagen’s way for learning C#</title>
      <dc:creator>UponTheSky</dc:creator>
      <pubDate>Tue, 28 Jan 2025 14:59:41 +0000</pubDate>
      <link>https://dev.to/uponthesky/ci-tried-primeagens-way-for-learning-c-kj6</link>
      <guid>https://dev.to/uponthesky/ci-tried-primeagens-way-for-learning-c-kj6</guid>
      <description>&lt;p&gt;&lt;em&gt;Source of the title image: &lt;a href="https://commons.wikimedia.org/wiki/File:Logo_C_sharp.svg" rel="noopener noreferrer"&gt;https://commons.wikimedia.org/wiki/File:Logo_C_sharp.svg&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you’re a software engineer, you’ll probably have learned multiple programming languages either due to your interest or need. That is, while you may have a main language, you need to learn a new language for different projects. In my case, expecting my next few projects to require knowledge of C#, I was looking for some smart ways to learn it &lt;em&gt;efficiently&lt;/em&gt; - methods that are not mundane but still cover essential parts of the language.&lt;/p&gt;

&lt;p&gt;Then I came across a few videos by &lt;a href="https://www.youtube.com/@ThePrimeTimeagen" rel="noopener noreferrer"&gt;ThePrimeagen&lt;/a&gt; about learning a new programming language. Primeagen is one of the most famous IT influencers, and I’ve been enjoying his videos on YouTube for quite a while. So, I thought it was a good opportunity to try his method and see if it works for me.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is "Primeagen’s way?"
&lt;/h2&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/E8cM12jRH7k"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;The video above and a &lt;a href="https://www.youtube.com/shorts/E1H9AFtwxfE" rel="noopener noreferrer"&gt;short&lt;/a&gt; are the resources that I followed. In short, his method for learning a new programming language can be summarized in three to four steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First, skim through the documentation of the language and briefly review its syntax.&lt;/li&gt;
&lt;li&gt;Second, try several exercises from &lt;a href="https://adventofcode.com/" rel="noopener noreferrer"&gt;Advent of Code&lt;/a&gt; to get some ideas about the language.&lt;/li&gt;
&lt;li&gt;Third, implement a very simple chat client.&lt;/li&gt;
&lt;li&gt;Finally, work on a larger project. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A disclaimer: I tried the first three parts but omitted the final one, since it is expected to be a long-term project and it doesn’t only involve pure software engineering skills. Also, I chose to implement a chat server instead of chat client, because I was more familiar with the backend programming.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I followed "Primeagen's way"
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. A tour of the language
&lt;/h3&gt;

&lt;p&gt;To begin the first step, I chose to skim through &lt;a href="https://learn.microsoft.com/en-us/dotnet/csharp/tour-of-csharp/overview" rel="noopener noreferrer"&gt;Tour of C#&lt;/a&gt;. While it wasn't a thorough introduction, it allowed me to sketch a broad overview of the language, including the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Basic types, operations, loops, conditions&lt;/li&gt;
&lt;li&gt;OOP features such as &lt;code&gt;class&lt;/code&gt;, &lt;code&gt;struct&lt;/code&gt;, inheritance, and access modifiers&lt;/li&gt;
&lt;li&gt;LINQ (I felt this was a really cool feature of the language)&lt;/li&gt;
&lt;li&gt;Asynchronous programming&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In addition to "Tour of C#", I explored other pages and tried to get familiar with the language. My first impression was that C# is very much like Java, but with a few features for functional programming such as Delegates. &lt;/p&gt;

&lt;h3&gt;
  
  
  2. Ten exercises of Advent of Code
&lt;/h3&gt;

&lt;p&gt;Then I dived into &lt;a href="https://adventofcode.com/" rel="noopener noreferrer"&gt;Advent of Code&lt;/a&gt;, a popular platform for challenging and fun coding exercises. I only tried ten (five days, two problems per day) days of exercises from the 2024 version, because I didn’t want to focus solely on coding exercises.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;To solve the problems, I began with printing “Hello, World!” on my local machine. So I installed .NET SDK (version 9.0) and generate a CLI template with it.&lt;/li&gt;
&lt;li&gt;Then I learned how to read data from &lt;code&gt;.txt&lt;/code&gt; files on disk. I used &lt;code&gt;.txt&lt;/code&gt; files for reading the inputs. &lt;/li&gt;
&lt;li&gt;I practiced a few OOP concepts, such as access modifiers, namespaces, inheritance, and &lt;code&gt;static&lt;/code&gt; keywords.&lt;/li&gt;
&lt;li&gt;I used built-in data structures like &lt;code&gt;LinkedList&amp;lt;T&amp;gt;&lt;/code&gt; and &lt;code&gt;Dictionary&amp;lt;K, V&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Although this was a good start, I began to wonder whether doing AoC is an ideal way to learn a new language.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The platform provides no hint, so you must devise on your own solutions. This might encourage brute force methods instead of teaching yourself efficient data structures or language-specific features.&lt;/li&gt;
&lt;li&gt;Many problems involve extensive use of regex to parse input data, which can shift your focus from learning the language itself to searching for various regex patterns.&lt;/li&gt;
&lt;li&gt;A few exercises were tricky, taking up much longer time to complete than expected. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In retrospect, it could have been more effective to solve easy-level problems on LeetCode instead. Platforms like &lt;a href="https://neetcode.io/" rel="noopener noreferrer"&gt;NeetCode&lt;/a&gt; offer helpful recommendations, such as "NeetCode 150".&lt;/p&gt;

&lt;p&gt;This is &lt;a href="https://github.com/UponTheSky/adventofcode/tree/main/csharp" rel="noopener noreferrer"&gt;my repo for AoC&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;CSharp&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;internal&lt;/span&gt; &lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BaseSolution&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;IEnumerable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;ReadFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&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="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;OpenText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadLine&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;line&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
AoC taught me the basics of C#.





&lt;h3&gt;
  
  
  3. Implementing a chat server
&lt;/h3&gt;

&lt;p&gt;After completing the first ten exercises from AoC, I moved on to the next step - implementing a chat server. At this point, I wasn’t really sure what Primeagen meant by "implementing". Did he mean I should start from scratch and use low-level socket libraries? Or was I allowed to simply use a well-tested web framework? I thought the former would be daunting, so I chose the latter approach and looked up the .NET documentation.&lt;/p&gt;

&lt;p&gt;There are several ways to implement backend APIs in .NET.  I chose the &lt;a href="https://learn.microsoft.com/en-us/aspnet/core/web-api/?view=aspnetcore-9.0" rel="noopener noreferrer"&gt;controller-based APIs&lt;/a&gt; because they were simpler and required less boilerplate than the &lt;a href="https://dotnet.microsoft.com/en-us/apps/aspnet/mvc" rel="noopener noreferrer"&gt;“classic” MVC&lt;/a&gt;, but still more structured than the &lt;a href="https://learn.microsoft.com/en-us/aspnet/core/fundamentals/minimal-apis/overview?view=aspnetcore-9.0" rel="noopener noreferrer"&gt;minimal APIs&lt;/a&gt;. Since I expected to frequently encounter old-style C# code, I thought it would be a good opportunity to get used to the &lt;em&gt;old&lt;/em&gt; OOP style of C#. For implementing chat communication, I referenced &lt;a href="https://learn.microsoft.com/en-us/dotnet/fundamentals/networking/websockets" rel="noopener noreferrer"&gt;.NET’s WebSockets documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;During the project, I learned how .NET handles a web application in general. It was interesting to compare .NET with Python frameworks that I was familiar with. It was very similar to &lt;a href="https://fastapi.tiangolo.com/" rel="noopener noreferrer"&gt;FastAPI&lt;/a&gt;, where APIs are declared rather than manually implemented, and it is allowed to adjust details such as middlewares and other initial configurations. It was also similar to &lt;a href="https://www.djangoproject.com/" rel="noopener noreferrer"&gt;Django&lt;/a&gt;, since DB migration and ORM were fully integrated through &lt;a href="https://learn.microsoft.com/en-us/ef/core/" rel="noopener noreferrer"&gt;Entity Framework Core&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;HttpGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ws/{id}/join"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;JoinChatRoom&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;FromRoute&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// reference: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/websockets?view=aspnetcore-9.0&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HttpContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WebSockets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsWebSocketRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;userIpAddress&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;GetUserIPAddress&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="n"&gt;_logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LogInformation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"User {ip} joins ChatRoom {id}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;userIpAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;Guid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryParse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="n"&gt;Guid&lt;/span&gt; &lt;span class="n"&gt;idInUUID&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;HttpContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusCode&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;StatusCodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Status400BadRequest&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;chatRoom&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ChatRoomItems&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SingleAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;idInUUID&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chatRoom&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;HttpContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusCode&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;StatusCodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Status404NotFound&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;webSocket&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;HttpContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WebSockets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AcceptWebSocketAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;RunChatLoop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;webSocket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chatRoom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;userIpAddress&lt;/span&gt; &lt;span class="p"&gt;??&lt;/span&gt; &lt;span class="s"&gt;"noname"&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;
I implemented a very simple chat server API.





&lt;p&gt;However, I am not sure I learned any advanced features of C# throughout this project, because I literally followed the well-structured documentation rather than implementing my own functions. I didn’t need to exploit several strong features of C#. Alternatively, I might have had a better chance to try advanced C# features, if I had started by implementing a web server from scratch. However, as I mentioned earlier, that would have turned into a much longer project.&lt;/p&gt;

&lt;p&gt;This is the &lt;a href="https://github.com/UponTheSky/chatroom/tree/main/csharp/ChatRoom" rel="noopener noreferrer"&gt;repo for my chat server project&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is Primeagen’s way recommendable for learning a new language?
&lt;/h2&gt;

&lt;p&gt;I don’t like to say this silver bullet phrase but… "it depends". However, I would like to extend the sentence as follows: "it depends on the LANGUAGE of choice". &lt;/p&gt;

&lt;h3&gt;
  
  
  Is the language similar to the one you are already familiar with?
&lt;/h3&gt;

&lt;p&gt;For example, if your main language is Python or JavaScript, learning C++ or Rust as a new language might be more difficult and certainly I can’t recommend Primeagen’s way. However, if it is Ruby, the initial effort required would be much lower. In my case, I was a little bit familiar with Java, so picking up the features and syntax of C# was relatively smooth. &lt;/p&gt;

&lt;h3&gt;
  
  
  Are there good resources for the language or frameworks?
&lt;/h3&gt;

&lt;p&gt;Personally, I think this is one of the most important aspects of learning a new language (or any new technology in general). Compared with Ruby or Python, C# has a very good collection of the official documentation pages and it is very beginner-friendly. &lt;/p&gt;

&lt;h3&gt;
  
  
  Do you already have a clear idea about a fun project?
&lt;/h3&gt;

&lt;p&gt;You may recall that I omitted the last step - doing an actual project of your interest. When working on your own project, you will need to consider logic involving data structures and algorithms, as well as organize a larger project, where you have to take care of building and publishing the application.&lt;/p&gt;

&lt;p&gt;In other words, you will learn the nuts and bolts of the features of the language applied to the application. But I think this is more about how to design a product and not just about learning a new language. So I think this step must be about a project that you are already familiar with, and you have a clear design for the entire application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;To summarize, I suggest you to try this Primeagen’s way if&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the language you want to learn is similar to a language you are already familiar with; otherwise you would be better off starting from a few tutorials,&lt;/li&gt;
&lt;li&gt;you can easily access beginner-friendly resources for the language, and&lt;/li&gt;
&lt;li&gt;you have a fun project and you already have a clear idea about it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Additionally, if I start over Primeagen’s way again for another language, I would probably try my own variation as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First, skim through a concise tutorial that covers the essential concepts of the language.&lt;/li&gt;
&lt;li&gt;Next, solve all the easy-level problems from &lt;a href="https://neetcode.io/" rel="noopener noreferrer"&gt;"NeetCode 150"&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Implement a simple multi-threaded web server. Rust’s &lt;a href="https://doc.rust-lang.org/book/ch20-00-final-project-a-web-server.html" rel="noopener noreferrer"&gt;&lt;strong&gt;THE BOOK&lt;/strong&gt; has a good example&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Overall, it was a good experience, and I learned a lot from Primeagen’s approach. However, I think you need to modify it to suit your own case.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>csharp</category>
      <category>learning</category>
    </item>
    <item>
      <title>[Opinion] I’ve passed an AWS cert… but is this something for me?</title>
      <dc:creator>UponTheSky</dc:creator>
      <pubDate>Sun, 20 Oct 2024 03:56:48 +0000</pubDate>
      <link>https://dev.to/uponthesky/opinion-ive-passed-an-aws-cert-but-is-this-something-for-me-2al9</link>
      <guid>https://dev.to/uponthesky/opinion-ive-passed-an-aws-cert-but-is-this-something-for-me-2al9</guid>
      <description>&lt;p&gt;(Image source: &lt;a href="https://www.irasutoya.com/2020/08/blog-post_42.html" rel="noopener noreferrer"&gt;https://www.irasutoya.com/2020/08/blog-post_42.html&lt;/a&gt;)&lt;/p&gt;

&lt;h2&gt;
  
  
  Passing an exam must feel great, but…
&lt;/h2&gt;

&lt;p&gt;Yes, as the title suggests, I’ve passed &lt;a href="https://aws.amazon.com/certification/certified-solutions-architect-associate/" rel="noopener noreferrer"&gt;AWS SAA(solutions architect associate)&lt;/a&gt;. It is one of the most well-known certification in the IT world, and many developers try to start their cloud journey with this cert. I’ve spent almost three months preparing for the exam, including taking a famous Udemy course and an exam bundle from &lt;a href="https://tutorialsdojo.com/" rel="noopener noreferrer"&gt;another famous website&lt;/a&gt;(of course, a completely legitimate one).&lt;/p&gt;

&lt;p&gt;Do I feel good? Yes, but at the same time, No. As a matter of fact, I kind of feel incomplete and unsatisfied for having taken this exam. I am not saying that AWS or this SAA-03 cert is bad at all. However, I’d like to share my experience and thoughts on this cert. And you might relate my thoughts to any certifications in general.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftvo3g5xanqbvxin23h03.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftvo3g5xanqbvxin23h03.png" alt="Image description" width="800" height="254"&gt;&lt;/a&gt;&lt;/p&gt;
I pass the exam but I feel somewhat unsatisfied.



&lt;h2&gt;
  
  
  Purpose of getting a cert
&lt;/h2&gt;

&lt;p&gt;I had two main purposes for getting this cert:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Getting familiar with AWS services: First of all, I listed my experience with AWS on my resume, but somehow I felt I knew nothing about it. So I thought it would be good to review the service and fundamental concepts such as IAM, scalability, or serverless.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Improving my resume: Another reason was a 'practical' one - to explicitly tell recruiters that I am &lt;em&gt;certified&lt;/em&gt; and therefore &lt;em&gt;qualified&lt;/em&gt;. Being in such an extremely saturated and competitive field, I thought getting a cert would be an essential one for landing my next job.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So let me ask myself: has successful getting the cert accomplished my original purposes? I would say &lt;strong&gt;WELL...&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How SAA cert preparation was actually like
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. The SAA covers not just a few well-known services but a wide range of AWS services
&lt;/h3&gt;

&lt;p&gt;You probably know the 80/20 principle. Basically it means that we use only 20% of something 80% of the time. For instance, we use 20% of all the English words way more often than the other 80%.&lt;/p&gt;

&lt;p&gt;I think this applies to AWS services as well. As an ordinary web developer, I have only &lt;em&gt;used&lt;/em&gt; EC2, ECS, Lambda, S3, and RDS. If you are more experienced and work at a big organization, your list would be longer. However, the number would be not that different.&lt;/p&gt;

&lt;p&gt;However, while preparing the exam, I had to put into my head some very unfamiliar services that I might never use in the future, such as DataSync, Storage Gateway, Polly, and VPC Flow, to name a few. It makes sense that if I were to work as a solutions architect using AWS extensively, then I need to be familiar with the catalog of services that AWS provides, so that I could make reasonable decisions about which to use. Nevertheless, I had to memorize every detail of many services that I had never touched before. I felt like I was reading a food recipe that I have never seen, touched, or tasted before.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmcvalo0onne8d0ist2bj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmcvalo0onne8d0ist2bj.png" alt="Image description" width="800" height="537"&gt;&lt;/a&gt;&lt;/p&gt;
There are many AWS services out there(source: https://aws.amazon.com/blogs/architecture/maintain-visibility-over-the-use-of-cloud-architecture-patterns/).



&lt;h3&gt;
  
  
  2. The exam questions presents real-world scenarios
&lt;/h3&gt;

&lt;p&gt;Most of the questions are like this: "You are a solutions architect at a company and the company uses this and that services, and you have a problem with that. How would you solve it?"&lt;/p&gt;

&lt;p&gt;So if you have actual experience in using AWS extensively, you might find those exams interesting. However, as a person who have been spent 90% of time in writing application code, I found it difficult to engage with the practice problems.&lt;/p&gt;

&lt;p&gt;For example, imagine you have never worked with Windows before, and you're asked to design a solution where you have to manage employee credentials using Windows AD on your on-premise server and migrate a Windows file systems database from the data center to AWS. Again, if you are a solutions architect, then I think you should know how to deal with such a problem. But as an application developer, would I ever encounter similar cases in the future?&lt;/p&gt;

&lt;h2&gt;
  
  
  Experience outweighs theory.
&lt;/h2&gt;

&lt;p&gt;Overall, &lt;strong&gt;My LACK OF EXPERIENCE IN AWS&lt;/strong&gt; was the main reason for my painful time in preparing for the cert. Although I managed to get a high score in the exam, I still feel I only become familiar with terminologies like subnet, IAM policy, IOPS, and so on. How could I claim to know more or work better than those who don't have the cert but have actual experience in AWS? Even if I can add a cert to my resume, can I confidently say that I can design a resilient and scalable distributed system in AWS?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9zns02g6h2efvyrnc0c6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9zns02g6h2efvyrnc0c6.png" alt="Image description" width="800" height="352"&gt;&lt;/a&gt;&lt;/p&gt;
All you need is experience. Keep practicing, and practicing.



&lt;h2&gt;
  
  
  What I would do if I go back in time?
&lt;/h2&gt;

&lt;p&gt;As a matter of fact, the &lt;a href="https://aws.amazon.com/certification/certified-solutions-architect-associate/" rel="noopener noreferrer"&gt;official guide of the cert recommends this cert to those who have more than one year of hands-on experience in AWS&lt;/a&gt;. You might say that getting a cert first gives you the whole picture of the AWS services at a high level, so that you would be able to touch the AWS services more smoothly. I woudl say &lt;strong&gt;NO&lt;/strong&gt;. It was very painful experience to learn about services that I had never touched before. I would first gain more experience with those services first.&lt;/p&gt;

&lt;p&gt;Personal project, actual work experience in enterprises, anything would do. I think it would be great to have an application that simulates AWS services so that one can exercise for free or at little cost. I haven't found any except &lt;a href="https://www.localstack.cloud/" rel="noopener noreferrer"&gt;LocalStack&lt;/a&gt;, so please let me know if there are other similar applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Well, having a cert is definitely worth it. I won't deny that. I learned a lot while preparing for the exam. However, now I realize that having a certification doesn't prove that you can actually solve real-world problems. I should keep learning and practicing; otherwise the cert itself would become a false representation of my skills.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cloud</category>
      <category>webdev</category>
    </item>
    <item>
      <title>[Python] How do we lazyload a Python module? - analyzing LazyLoader from MLflow</title>
      <dc:creator>UponTheSky</dc:creator>
      <pubDate>Sat, 05 Oct 2024 11:53:18 +0000</pubDate>
      <link>https://dev.to/uponthesky/python-how-do-we-lazyload-a-python-module-analyzing-lazyloader-from-mlflow-5757</link>
      <guid>https://dev.to/uponthesky/python-how-do-we-lazyload-a-python-module-analyzing-lazyloader-from-mlflow-5757</guid>
      <description>&lt;p&gt;(image source: &lt;a href="https://www.irasutoya.com/2019/03/blog-post_72.html" rel="noopener noreferrer"&gt;https://www.irasutoya.com/2019/03/blog-post_72.html&lt;/a&gt;)&lt;/p&gt;

&lt;h1&gt;
  
  
  Intro
&lt;/h1&gt;

&lt;p&gt;One day I was hopping around a few popular ML libraries in Python, including &lt;a href="https://mlflow.org/" rel="noopener noreferrer"&gt;MLflow&lt;/a&gt;. While glancing at its source code, one class attracted my interest, &lt;code&gt;LazyLoader&lt;/code&gt; in &lt;a href="https://github.com/mlflow/mlflow/blob/master/mlflow/__init__.py" rel="noopener noreferrer"&gt;&lt;code&gt;__init__.py&lt;/code&gt;&lt;/a&gt; (well, this actually mirrors from the &lt;a href="https://github.com/wandb/wandb/blob/main/wandb/sdk/lib/lazyloader.py" rel="noopener noreferrer"&gt;wandb project&lt;/a&gt;, but the original code has changed from what MLflow is using now, as you can see). &lt;/p&gt;

&lt;p&gt;You probably heard about the concept of lazyloading from many contexts, such as web frontend image loading, caching strategy, and so on. I think the essence of all those lazyloading concepts is, that "I am too &lt;em&gt;lazy&lt;/em&gt; to &lt;em&gt;load&lt;/em&gt; &lt;strong&gt;RIGHT NOW&lt;/strong&gt;" - yes, the hidden words "right now". Namely, the application will load and use that resource only when it is needed. So here in this MLflow library, the modules are loaded only when the resources in it — variables, functions, and classes — are accessed.&lt;/p&gt;

&lt;p&gt;But &lt;strong&gt;HOW&lt;/strong&gt;? This was my main interest. So I read the &lt;a href="https://github.com/mlflow/mlflow/blob/master/mlflow/utils/lazy_load.py" rel="noopener noreferrer"&gt;source code&lt;/a&gt;, which looked very simple at first glance. However,   surprisingly, it took a bit of time to understand how it works, and I learned a lot from reading the code. This article is about analyzing this source code of MLflow so that we understand how such lazyloading works using various techniques of Python language.&lt;/p&gt;

&lt;h2&gt;
  
  
  Playing around with &lt;code&gt;LazyLoader&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;For the purpose of our analysis, I created a simple package called &lt;em&gt;lazyloading&lt;/em&gt; on my local machine, and placed modules as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;lazyloading/
├─ __init__.py
├─ __main__.py
├─ lazy_load.py
├─ heavy_module.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;__init__.py&lt;/code&gt;: This file makes the entire directory into a package.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;__main__.py&lt;/code&gt;: This file is the entry point when we want to run the entire package as follows: &lt;code&gt;python -m lazyloading&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;lazy_load.py&lt;/code&gt;: &lt;code&gt;LazyLoader&lt;/code&gt; is in this file. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;heavy_module.py&lt;/code&gt;:  This represents a module with heavy packages to be loaded (such as PyTorch) for a simulation:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; seconds left before loading&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;I am heavier than Pytorch!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;HEAVY_ATTRIBUTE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;heavy”
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we import this &lt;code&gt;heavy_module&lt;/code&gt; inside &lt;code&gt;__main__.py&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;lazyloading&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;heavy_module&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s run this package and see the result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; lazyloading
5  seconds left before loading
4  seconds left before loading
3  seconds left before loading
2  seconds left before loading
1  seconds left before loading
I am heavier than pytorch!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we can clearly see that if we simply import heavy packages such as PyTorch, it could be an overhead for the entire application. That’s why we need lazyloading here. Let’s change &lt;code&gt;__main__.py&lt;/code&gt; to look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;lazyloading.lazy_load&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;LazyLoader&lt;/span&gt;
    &lt;span class="n"&gt;heavy_module&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LazyLoader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lazyloading.heavy_module&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;globals&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lazyloading.heavy_module&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;nothing happens yet&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;heavy_module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HEAVY_ATTRIBUTE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the result should be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="n"&gt;lazyloading&lt;/span&gt;
&lt;span class="n"&gt;nothing&lt;/span&gt; &lt;span class="n"&gt;happens&lt;/span&gt; &lt;span class="n"&gt;yet&lt;/span&gt;
&lt;span class="mi"&gt;5&lt;/span&gt;  &lt;span class="n"&gt;seconds&lt;/span&gt; &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="n"&gt;before&lt;/span&gt; &lt;span class="n"&gt;loading&lt;/span&gt;
&lt;span class="mi"&gt;4&lt;/span&gt;  &lt;span class="n"&gt;seconds&lt;/span&gt; &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="n"&gt;before&lt;/span&gt; &lt;span class="n"&gt;loading&lt;/span&gt;
&lt;span class="mi"&gt;3&lt;/span&gt;  &lt;span class="n"&gt;seconds&lt;/span&gt; &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="n"&gt;before&lt;/span&gt; &lt;span class="n"&gt;loading&lt;/span&gt;
&lt;span class="mi"&gt;2&lt;/span&gt;  &lt;span class="n"&gt;seconds&lt;/span&gt; &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="n"&gt;before&lt;/span&gt; &lt;span class="n"&gt;loading&lt;/span&gt;
&lt;span class="mi"&gt;1&lt;/span&gt;  &lt;span class="n"&gt;seconds&lt;/span&gt; &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="n"&gt;before&lt;/span&gt; &lt;span class="n"&gt;loading&lt;/span&gt;
&lt;span class="n"&gt;heavy&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yes, any module imported by &lt;code&gt;LazyLoader&lt;/code&gt; doesn’t need to execute any script or import other packages. It happens only when any attribute of the module is accessed. This is the power of lazyloading!&lt;/p&gt;

&lt;h1&gt;
  
  
  How LazyLoader works in MLflow? - source code analysis
&lt;/h1&gt;

&lt;p&gt;The code itself is short and simple. I added type annotations and a few comments (lines enclosed in &lt;code&gt;&amp;lt;, &amp;gt;&lt;/code&gt;) for explanations. All the other comments are the ones in the original source code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Utility to lazy load modules.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;importlib&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;types&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TypeVar&lt;/span&gt;

&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;TypeVar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;T&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# &amp;lt;this is added by me&amp;gt;
&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LazyLoader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ModuleType&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Class for module lazy loading.

    This class helps lazily load modules at package level, which avoids pulling in large
    dependencies like `tensorflow` or `torch`. This class is mirrored from wandb&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s LazyLoader:
    https://github.com/wandb/wandb/blob/79b2d4b73e3a9e4488e503c3131ff74d151df689/wandb/sdk/lib/lazyloader.py#L9
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

    &lt;span class="n"&gt;_local_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="c1"&gt;# &amp;lt;the name of the package that is used inside code&amp;gt;
&lt;/span&gt;    &lt;span class="n"&gt;_parent_module_globals&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ModuleType&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;# &amp;lt;importing module's namespace, accessible by calling globals()&amp;gt;
&lt;/span&gt;    &lt;span class="n"&gt;_module&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ModuleType&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="c1"&gt;# &amp;lt;actual module&amp;gt;
&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="n"&gt;local_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="n"&gt;parent_module_globals&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ModuleType&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; 
        &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt; &lt;span class="c1"&gt;# &amp;lt;to be used in types.ModuleType(name=str(name)), the full package name (such as pkg.subpkg.subsubpkg)&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_local_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;local_name&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_parent_module_globals&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parent_module_globals&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_module&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

        &lt;span class="nf"&gt;super&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; 

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ModuleType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Load the module and insert it into the parent&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s globals.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_module&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# If already loaded, return the loaded module.
&lt;/span&gt;            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_module&lt;/span&gt;

        &lt;span class="c1"&gt;# Import the target module and insert it into the parent's namespace
&lt;/span&gt;
        &lt;span class="c1"&gt;# &amp;lt;see https://docs.python.org/3/library/importlib.html#importlib.import_module&amp;gt;
&lt;/span&gt;        &lt;span class="c1"&gt;# &amp;lt;absolute import, importing the module itself from a package rather than the top-level package only(like __import__)&amp;gt;
&lt;/span&gt;        &lt;span class="c1"&gt;# &amp;lt;here, self.__name__ is the variable `name` in __init__&amp;gt;
&lt;/span&gt;        &lt;span class="c1"&gt;# &amp;lt;this is why that `name` in __init__ must be the full module path&amp;gt;
&lt;/span&gt;        &lt;span class="n"&gt;module&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;importlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;import_module&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# this automatically updates sys.modules
&lt;/span&gt;
        &lt;span class="c1"&gt;# &amp;lt;add the name of the module to the importing module(=parent module)'s namespace&amp;gt;
&lt;/span&gt;        &lt;span class="c1"&gt;# &amp;lt;so that you can use this module's name as a variable inside the importing module, even if it is called inside a function defined in the importing module&amp;gt;
&lt;/span&gt;        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_parent_module_globals&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_local_name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;module&lt;/span&gt;

        &lt;span class="c1"&gt;# &amp;lt;add the module to the list of loaded modules for caching&amp;gt;
&lt;/span&gt;        &lt;span class="c1"&gt;# &amp;lt;see https://docs.python.org/3/reference/import.html#the-module-cache&amp;gt;
&lt;/span&gt;        &lt;span class="c1"&gt;# &amp;lt;this makes possible to import cached module with the variable _local_name
&lt;/span&gt;        &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;modules&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_local_name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;module&lt;/span&gt;

        &lt;span class="c1"&gt;# Update this object's dict so that if someone keeps a reference to the `LazyLoader`,
&lt;/span&gt;        &lt;span class="c1"&gt;# lookups are efficient (`__getattr__` is only called on lookups that fail).
&lt;/span&gt;        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__dict__&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__dict__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;module&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__getattr__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;module&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_load&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__dir__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;module&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_load&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__repr__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_module&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;module &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; (Not loaded yet)&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;repr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_module&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 investigate the code while lazyloading our &lt;code&gt;heavy_module&lt;/code&gt;. Since we don’t need to simulate the heaviness of the module anymore, let’s get rid of the &lt;code&gt;time.sleep(1)&lt;/code&gt; loop part.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Creating an instance of &lt;code&gt;LazyLoader&lt;/code&gt;, proxying the original module
&lt;/h3&gt;

&lt;p&gt;Let’s look at &lt;code&gt;__init__()&lt;/code&gt; of &lt;code&gt;LazyLoader&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LazyLoader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ModuleType&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# …
&lt;/span&gt;    &lt;span class="c1"&gt;# code omitted
&lt;/span&gt;    &lt;span class="c1"&gt;# …
&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="n"&gt;local_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="n"&gt;parent_module_globals&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ModuleType&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; 
        &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt; &lt;span class="c1"&gt;# &amp;lt;to be used in types.ModuleType(name=str(name)); the full package name(such as pkg.subpkg.subsubpkg)&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_local_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;local_name&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_parent_module_globals&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parent_module_globals&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_module&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

        &lt;span class="nf"&gt;super&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We provide &lt;code&gt;local_name&lt;/code&gt;, &lt;code&gt;parent_module_globals&lt;/code&gt;, and &lt;code&gt;name&lt;/code&gt; to the constructor &lt;code&gt;__init__()&lt;/code&gt;. At the moment, we are not sure what all those means, but at least the last line indicates that we are actually generating a module - &lt;code&gt;super().__init__(str(name))&lt;/code&gt;, since &lt;code&gt;LazyLoader&lt;/code&gt; inherits &lt;a href="https://docs.python.org/3/library/types.html#types.ModuleType" rel="noopener noreferrer"&gt;&lt;code&gt;types.ModuleType&lt;/code&gt;&lt;/a&gt;. By providing the variable &lt;code&gt;name&lt;/code&gt;, our module created by &lt;code&gt;LazyLoader&lt;/code&gt; is recognized as a module with name &lt;code&gt;name&lt;/code&gt;(which is the same as &lt;code&gt;heavy_module.__name__&lt;/code&gt;). &lt;/p&gt;

&lt;p&gt;Printing out the module itself proves this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# __main__.py
# run python -m lazyloading
&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;lazyloading.lazy_load&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;LazyLoader&lt;/span&gt;
    &lt;span class="n"&gt;heavy_module&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LazyLoader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lazyloading.heavy_module&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;globals&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lazyloading.heavy_module&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;heavy_module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which gives on our terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;lazyloading.heavy_module
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, in the constructor we only assigned values to the instance variables and gave the name of the module to this &lt;em&gt;proxy&lt;/em&gt; module. Now, what happens when we try to access an attribute of the module?&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Accessing an attribute - &lt;code&gt;__getattribute__&lt;/code&gt;, &lt;code&gt;__getattr__&lt;/code&gt;, and &lt;code&gt;getattr&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This is one of the fun parts of this class. What happens when we access an attribute of a Python object in general? Say we access &lt;code&gt;HEAVY_ATTRIBUTE&lt;/code&gt; of &lt;code&gt;heavy_module&lt;/code&gt; by calling &lt;code&gt;heavy_module.HEAVY_ATTRIBUTE&lt;/code&gt;. From the code here, or from your own experience in several Python projects, you might guess that &lt;code&gt;__getattr__()&lt;/code&gt; is called, and that’s partially correct. Look at the &lt;a href="https://docs.python.org/3/reference/datamodel.html#object.__getattr__" rel="noopener noreferrer"&gt;official docs&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Called when the default attribute access fails with an AttributeError (either &lt;strong&gt;getattribute&lt;/strong&gt;() raises an AttributeError because name is not an instance attribute or an attribute in the class tree for self; or &lt;strong&gt;get&lt;/strong&gt; of a name property raises AttributeError).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;(Please ignore &lt;code&gt;__get__&lt;/code&gt; because it is out of scope of this post, and our &lt;code&gt;LazyLoader&lt;/code&gt; doesn’t implement &lt;code&gt;__get__&lt;/code&gt; either). &lt;/p&gt;

&lt;p&gt;So &lt;code&gt;__getattribute__()&lt;/code&gt; the key method here is &lt;code&gt;__getattribute__&lt;/code&gt;.  According to the docs, when we try to access an attribute, &lt;code&gt;__getattribute__&lt;/code&gt; will be called first, and if the attribute we’re looking for cannot be found by &lt;code&gt;__getattribute__&lt;/code&gt;, &lt;code&gt;AttributeError&lt;/code&gt; will be raised, which will in turn invoke our &lt;code&gt;__getattr__&lt;/code&gt; in the code. To verify this, let’s override &lt;code&gt;__getattribute__&lt;/code&gt; of the &lt;code&gt;LazyLoader&lt;/code&gt; class, and change &lt;code&gt;__getattr__()&lt;/code&gt; a little bit as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__getattribute__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__getattribute__ is called when accessing attribute &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;super&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;__getattribute__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;an error has occurred when __getattribute__() is invoked as accessing &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__getattr__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__getattr__ is called when accessing attribute &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;module&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_load&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When we access &lt;code&gt;HEAVY_ATTRIBUTE&lt;/code&gt; that exists in &lt;code&gt;heavy_module&lt;/code&gt;, the result is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;lazyloading.lazy_load&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;LazyLoader&lt;/span&gt;
    &lt;span class="n"&gt;heavy_module&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LazyLoader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lazyloading.heavy_module&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;globals&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lazyloading.heavy_module&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;heavy_module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HEAVY_ATTRIBUTE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; lazyloading
__getattribute__ is called when accessing attribute &lt;span class="s1"&gt;'HEAVY_ATTRIBUTE'&lt;/span&gt;
an error has occurred when __getattribute__&lt;span class="o"&gt;()&lt;/span&gt; is invoked as accessing &lt;span class="s1"&gt;'HEAVY_ATTRIBUTE'&lt;/span&gt;: module &lt;span class="s1"&gt;'lazyloading.heavy_module'&lt;/span&gt; has no attribute &lt;span class="s1"&gt;'HEAVY_ATTRIBUTE'&lt;/span&gt;
__getattr__ is called when accessing attribute &lt;span class="s1"&gt;'HEAVY_ATTRIBUTE'&lt;/span&gt;
__getattribute__ is called when accessing attribute &lt;span class="s1"&gt;'_load'&lt;/span&gt;
__getattribute__ is called when accessing attribute &lt;span class="s1"&gt;'_module'&lt;/span&gt;
__getattribute__ is called when accessing attribute &lt;span class="s1"&gt;'__name__'&lt;/span&gt;
I am heavier than Pytorch!
__getattribute__ is called when accessing attribute &lt;span class="s1"&gt;'_parent_module_globals'&lt;/span&gt;
__getattribute__ is called when accessing attribute &lt;span class="s1"&gt;'_local_name'&lt;/span&gt;
__getattribute__ is called when accessing attribute &lt;span class="s1"&gt;'__dict__'&lt;/span&gt;
heavy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So &lt;code&gt;__getattr__&lt;/code&gt; is actually not called directly, but &lt;code&gt;__getattribute__&lt;/code&gt; is called first, and it raises &lt;code&gt;AttributeError&lt;/code&gt; because our &lt;code&gt;LazyLoader&lt;/code&gt; instance doesn’t have attribute &lt;code&gt;HEAVY_ATTRIBUTE&lt;/code&gt;. Now &lt;code&gt;__getattr__()&lt;/code&gt; is called as a failover. Then we meet &lt;a href="https://docs.python.org/3/library/functions.html#getattr" rel="noopener noreferrer"&gt;&lt;code&gt;getattr()&lt;/code&gt;&lt;/a&gt;, but this code line &lt;code&gt;getattr(module, item)&lt;/code&gt; is equivalent to code &lt;code&gt;module.item&lt;/code&gt; in Python. So eventually, we access the &lt;code&gt;HEAVY_ATTRIBUTE&lt;/code&gt; in the actual module &lt;code&gt;heavy_module&lt;/code&gt;, if &lt;code&gt;module&lt;/code&gt; variable in &lt;code&gt;__getattr__()&lt;/code&gt; is correctly imported and returned by &lt;code&gt;self._load()&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;But before we move on to investigating &lt;code&gt;_load()&lt;/code&gt; method, let’s call &lt;code&gt;HEAVY_ATTRIBUTE&lt;/code&gt; once again in &lt;code&gt;__main__.py&lt;/code&gt; and run the package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;lazyloading.lazy_load&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;LazyLoader&lt;/span&gt;
    &lt;span class="n"&gt;heavy_module&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LazyLoader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lazyloading.heavy_module&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;globals&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lazyloading.heavy_module&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;heavy_module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HEAVY_ATTRIBUTE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;heavy_module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HEAVY_ATTRIBUTE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we see the additional logs on the terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# … the same log as above&lt;/span&gt;
__getattribute__ is called when accessing attribute &lt;span class="s1"&gt;'HEAVY_ATTRIBUTE'&lt;/span&gt;
heavy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It seems that &lt;code&gt;__getattribute__&lt;/code&gt; can access &lt;code&gt;HEAVY_ATTRIBUTE&lt;/code&gt; now inside the &lt;em&gt;proxy&lt;/em&gt; module(our &lt;code&gt;LazyLoader&lt;/code&gt; instance). This is because(!!!spoiler alert!!!) &lt;code&gt;_load&lt;/code&gt; caches the accessed attribute in &lt;code&gt;__dict__&lt;/code&gt; attribute of the &lt;code&gt;LazyLoader&lt;/code&gt; instance.  We’ll get back to this in the next section.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Loading and caching the actual module
&lt;/h3&gt;

&lt;p&gt;This section covers the core part the post - loading the actual module in the function &lt;code&gt;_load()&lt;/code&gt;. &lt;/p&gt;

&lt;h4&gt;
  
  
  3-1. Module caching at the level of &lt;code&gt;LazyLoader&lt;/code&gt; class
&lt;/h4&gt;

&lt;p&gt;First, it checks whether our &lt;code&gt;LazyLoader&lt;/code&gt; instance has already imported the module before (which reminds us of the Singleton pattern).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_module&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# If already loaded, return the loaded module.
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_module&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  3-2. Importing the actual module with &lt;code&gt;importlib.import_module&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;Otherwise, the method tries to import the module named &lt;code&gt;__name__&lt;/code&gt;, which we saw in the &lt;code&gt;__init__&lt;/code&gt; constructor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# &amp;lt;see https://docs.python.org/3/library/importlib.html#importlib.import_module&amp;gt;
# &amp;lt;absolute import, importing the module itself from a package rather than the top-level package only(like __import__)&amp;gt;
# &amp;lt;here, self.__name__ is the variable `name` in __init__&amp;gt;
# &amp;lt;this is why that `name` in __init__ must be the full module path&amp;gt;
&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;importlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;import_module&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# this automatically updates sys.modules
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;According to the docs of &lt;a href="https://docs.python.org/3/library/importlib.html#importlib.import_module" rel="noopener noreferrer"&gt;&lt;code&gt;importlib.import_module&lt;/code&gt;&lt;/a&gt;, when we don’t provide the &lt;code&gt;pkg&lt;/code&gt; argument and only the path string, the function tries to import the package in the absolute manner. Therefore, when we create a &lt;code&gt;LazyLoader&lt;/code&gt; instance, the name argument should be the absolute term. You can run your own experiment to see it raises &lt;code&gt;ModuleNotFoundError&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;lazyloading.lazy_load&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;LazyLoader&lt;/span&gt;
    &lt;span class="n"&gt;heavy_module&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LazyLoader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;heavy_module&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;globals&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;heavy_module&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;heavy_module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HEAVY_ATTRIBUTE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# logs omitted&lt;/span&gt;
ModuleNotFoundError: No module named &lt;span class="s1"&gt;'heavy_module'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notably, invoking &lt;code&gt;importlib.import_module(self.__name__)&lt;/code&gt; caches the module with name &lt;code&gt;self.__name__&lt;/code&gt; in the global scope. If you run the following lines in &lt;code&gt;__main__.py&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;lazyloading.lazy_load&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;LazyLoader&lt;/span&gt;
    &lt;span class="n"&gt;heavy_module&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LazyLoader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;heavy_module&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;globals&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lazyloading.heavy_module&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# check whether the module is cached at the global scope
&lt;/span&gt;    &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lazyloading.heavy_module&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;modules&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# accessing any attribute to load the module
&lt;/span&gt;    &lt;span class="n"&gt;heavy_module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HEAVY_ATTRIBUTE&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lazyloading.heavy_module&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;modules&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and run the package, then the logs should be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; lazyloading
False
I am heavier than Pytorch!
True
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This way of caching using &lt;a href="https://docs.python.org/3/reference/import.html#the-module-cache" rel="noopener noreferrer"&gt;&lt;code&gt;sys.modules&lt;/code&gt;&lt;/a&gt; is related to the next two lines that also cache the module in different ways. &lt;/p&gt;

&lt;h4&gt;
  
  
  3-3. Caching the module with given &lt;code&gt;local_name&lt;/code&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# &amp;lt;add the name of the module to the importing module(=parent module)'s namespace&amp;gt;
# &amp;lt;so that you can use this module's name as a variable inside the importing module, even if it is called inside a function defined in the importing module&amp;gt;
&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_parent_module_globals&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_local_name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;module&lt;/span&gt;

&lt;span class="c1"&gt;# &amp;lt;add the module to the list of loaded modules for caching&amp;gt;
# &amp;lt;see https://docs.python.org/3/reference/import.html#the-module-cache&amp;gt;
# &amp;lt;this makes possible to import cached module with the variable _local_name
&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;modules&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_local_name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;module&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both lines cache the module in the dictionaries &lt;code&gt;self._parent_module_globals&lt;/code&gt; and &lt;code&gt;sys.modules&lt;/code&gt; respectively, but with the key &lt;code&gt;self._local_name&lt;/code&gt;(not &lt;code&gt;self.__name__&lt;/code&gt;). This is the variable we provided as &lt;code&gt;local_name&lt;/code&gt; when creating this proxy module instance with &lt;code&gt;__init__()&lt;/code&gt;. But what does this caching accomplish?&lt;/p&gt;

&lt;p&gt;First, we can use the module with the given &lt;code&gt;_local_name&lt;/code&gt; in the "parent module"’s globals(from the parameter’s name and seeing how &lt;a href="https://github.com/mlflow/mlflow/blob/master/mlflow/__init__.py" rel="noopener noreferrer"&gt;MLflow uses in its uppermost &lt;code&gt;__init__.py&lt;/code&gt;&lt;/a&gt;, we can infer that here the word &lt;em&gt;globals&lt;/em&gt; means (&lt;a href="https://docs.python.org/3/library/functions.html#globals" rel="noopener noreferrer"&gt;&lt;code&gt;globals()&lt;/code&gt;&lt;/a&gt;). This means that importing the module inside a function doesn’t limit the module to be used outside the function’s scope:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;lazyloading.lazy_load&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;LazyLoader&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;load_heavy_module&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# import the module inside a function
&lt;/span&gt;        &lt;span class="n"&gt;heavy_module&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LazyLoader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;heavy_module&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;globals&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lazyloading.heavy_module&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;heavy_module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HEAVY_ATTRIBUTE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# loads the heavy_module inside the function's scope
&lt;/span&gt;    &lt;span class="nf"&gt;load_heavy_module&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;# the module is now in the scope of this module
&lt;/span&gt;    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;heavy_module&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running the package gives:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; lazyloading
I am heavier than Pytorch!
heavy
&amp;lt;module &lt;span class="s1"&gt;'lazyloading.heavy_module'&lt;/span&gt; from ‘…’&amp;gt; &lt;span class="c"&gt;# the path of the heavy_module(a Python file)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Of course, if you provide the second argument &lt;a href="https://docs.python.org/3/library/functions.html#locals" rel="noopener noreferrer"&gt;&lt;code&gt;locals()&lt;/code&gt;&lt;/a&gt;, then you’ll get &lt;code&gt;NameError&lt;/code&gt;(give it a try!). &lt;/p&gt;

&lt;p&gt;Second, we can also import the module in any other place inside the whole package with the given local name. Let’s create another module &lt;code&gt;heavy_module_loader.py&lt;/code&gt; inside the current package &lt;code&gt;lazyloading&lt;/code&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;lazyloading/
├─ __init__.py
├─ __main__.py
├─ lazy_load.py
├─ heavy_module.py
├─ heavy_module_loader.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that I used a custom name &lt;code&gt;heavy_module_local&lt;/code&gt; for the local variable name of the proxy module.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# heavy_module_loader.py
&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;lazyloading.lazy_load&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;LazyLoader&lt;/span&gt;

&lt;span class="n"&gt;heavy_module&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LazyLoader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;heavy_module_local&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;globals&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lazyloading.heavy_module&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;heavy_module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HEAVY_ATTRIBUTE&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let &lt;code&gt;__main__.py&lt;/code&gt; be simpler:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;lazyloading&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;heavy_module_loader&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;heavy_module_local&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;heavy_module_local&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your IDE will probably alert this line as having a syntax error, but actually running it will give us the expected result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; lazyloading
I am heavier than Pytorch!
&amp;lt;module &lt;span class="s1"&gt;'lazyloading.heavy_module'&lt;/span&gt; from ‘…’&amp;gt; &lt;span class="c"&gt;# the path of the heavy_module(a Python file)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Although MLflow seems to use the same string value for both &lt;code&gt;local_name&lt;/code&gt; and &lt;code&gt;name&lt;/code&gt; when creating &lt;code&gt;LazyLoader&lt;/code&gt; instances, we can use the &lt;code&gt;local_name&lt;/code&gt; as an alias for the actual package name, thanks to this caching mechanism.&lt;/p&gt;

&lt;h4&gt;
  
  
  3-4. Caching the attributes of the actual module in &lt;code&gt;__dict__&lt;/code&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Update this object's dict so that if someone keeps a reference to the `LazyLoader`,
# lookups are efficient (`__getattr__` is only called on lookups that fail).
&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__dict__&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__dict__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Python, the attribute &lt;a href="https://docs.python.org/3/library/stdtypes.html#object.__dict__" rel="noopener noreferrer"&gt;__dict__&lt;/a&gt; gives the dictionary of attributes of the given object. Updating this proxy module’s attributes with the actual module’s ones makes the user easier to access the attributes of the real one. As we discussed in section 2(2. Accessing an attribute - &lt;code&gt;__getattribute__&lt;/code&gt;, &lt;code&gt;__getattr__&lt;/code&gt;, and &lt;code&gt;getattr&lt;/code&gt;) and noted in the comments of the original source code, this allows &lt;code&gt;__getattribute__&lt;/code&gt; and &lt;code&gt;__getattr__&lt;/code&gt; to directly access the target attributes.&lt;/p&gt;

&lt;p&gt;In my view, this part is somewhat unnecessary, as we already cache modules and use them whenever their attributes are accessed. However, this could be useful when we need to debug and inspect &lt;code&gt;__dict__&lt;/code&gt;. &lt;/p&gt;

&lt;h3&gt;
  
  
  4. &lt;code&gt;__dir__&lt;/code&gt; and &lt;code&gt;__repr__&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Similar to &lt;code&gt;__dict__&lt;/code&gt;, these two dunder functions might not be strictly necessary when using &lt;code&gt;LazyLoader&lt;/code&gt; modules. However, they could be useful for debugging. &lt;code&gt;__repr__&lt;/code&gt; is particularly helpful as it indicates whether the module has been loaded.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_module&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;module &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; (Not loaded yet)&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;repr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_module&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Although the source code itself is quite short, we covered several advanced topics, including importing modules, module scopes, and accessing object attributes in Python. Also, the concept of lazyloading is very common in computer science, but we rarely get the chance to examine how it is implemented in detail. By investigating how &lt;code&gt;LazyLoader&lt;/code&gt; works, we learned more than we expected. Our biggest takeaway is that short code doesn’t necessarily mean easy code to analyze! &lt;/p&gt;

</description>
      <category>python</category>
      <category>machinelearning</category>
      <category>mlflow</category>
    </item>
    <item>
      <title>[Book Review] Beej's Guide to Network Programming</title>
      <dc:creator>UponTheSky</dc:creator>
      <pubDate>Sat, 13 Jul 2024 01:38:11 +0000</pubDate>
      <link>https://dev.to/uponthesky/book-review-beejs-guide-to-network-programming-9mg</link>
      <guid>https://dev.to/uponthesky/book-review-beejs-guide-to-network-programming-9mg</guid>
      <description>&lt;h2&gt;
  
  
  Intro - what is this book about?
&lt;/h2&gt;

&lt;p&gt;Yes, I finally finished reading this book. &lt;/p&gt;

&lt;p&gt;As a person who has never taken a computer networking course in university, I had thought for a long time of learning that subject intensively. However, I could not find a solid university course that is open to public(something like &lt;a href="https://ocw.mit.edu/courses/6-006-introduction-to-algorithms-spring-2020/" rel="noopener noreferrer"&gt;MIT’s introduction to algorithms&lt;/a&gt;). And many of the textbooks prefixed “introduction” spent hundreds of pages explaining quite low-level concepts such as routing algorithms or even physical wires that connect the continents!&lt;/p&gt;

&lt;p&gt;Then I found &lt;a href="https://beej.us/guide/bgnet/" rel="noopener noreferrer"&gt;Beej's Guide to Network Programming&lt;/a&gt; that is recommended frequently on the Internet. At a glance, I found it easy to read because of the author’s way of explaining concepts in a humorous manner. But at the same time, compared to other computer network books, this book contains many code examples, so that I thought it suits more for the programmers who want practical socket programming practice. &lt;/p&gt;

&lt;p&gt;And after reading through all the chapters except chapter 9(because it is more like a reference for a bunch of C socket functions), I found it a good read.&lt;/p&gt;

&lt;h2&gt;
  
  
  Good parts
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Friendly introduction to technical concepts
&lt;/h3&gt;

&lt;p&gt;The book starts with a few basic concepts such as IP, port, and socket. However, it doesn’t go deeper into introducing very technical algorithms or physical devices used for network communications. As a developer who deals with web applications daily, I found it more relevant to my job. Even though the book sometimes mentions bits and bytes, it is still readable and you usually never do any bitwise operations while reading the C code in the book.&lt;/p&gt;

&lt;h3&gt;
  
  
  Plenty of code examples
&lt;/h3&gt;

&lt;p&gt;For those who want to get their hands dirty with code, this book is for you. Except for the general overview parts on computer networking, most of the explanations in the book come with code examples in C. This is particularly useful for knowing how actual network communications occur inside our web applications. For example, the &lt;a href="https://beej.us/guide/bgnet/html/split/slightly-advanced-techniques.html#poll" rel="noopener noreferrer"&gt;polling operation&lt;/a&gt; sweeps through all the registered sockets to check whether there are incoming events to be handled.&lt;/p&gt;

&lt;p&gt;Moreover, the examples don’t import any external libraries, so you don’t have to deal with irritating third-party dependency problems.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Soso parts
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Mainly focused on socket programming only
&lt;/h3&gt;

&lt;p&gt;This book is very good as a friendly reference to socket programming and relevant system calls. However, it does not go “higher” or “lower”:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"higher": Most of today’s web applications rely on the HTTP protocol. It could have been better if the book contained more explanations on this higher layer with actual running code.&lt;/li&gt;
&lt;li&gt;"lower": I think the book could have shown how a packet looks like using tools such as Wireshark that snatches packets generated by the examples. Introducing a few Linux/Unix commands for networking could also have been helpful for understanding how our application code interacts with the kernel.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, I found another good resource written by the same author: &lt;a href="https://beej.us/guide/bgnet0/" rel="noopener noreferrer"&gt;Beej's Guide to Networking Concepts&lt;/a&gt;. It seems to cover many core concepts more comprehensively than this book with a lot of coding exercises. I hope this “concept” book will fill the gap of the “programming” book. &lt;/p&gt;

&lt;h3&gt;
  
  
  Not recommended for those who are not familiar with C code
&lt;/h3&gt;

&lt;p&gt;If you don’t know much about C programming, this book could be overwhelming. It doesn’t explain any basic concepts such as pointers or type casting. Although we don’t suffer from dependency hell like when dealing with CMake, if you don’t know much about C then reading code would still be difficult. &lt;/p&gt;

&lt;p&gt;Personally I am okay with C code. However, the book could have been more beginner-friendly if it were written in Python, which has almost all the counterparts of the socket functions of C in its &lt;a href="https://docs.python.org/3/library/socket.html" rel="noopener noreferrer"&gt;socket library&lt;/a&gt;. The &lt;a href="https://beej.us/guide/bgnet0/" rel="noopener noreferrer"&gt;"concept" book&lt;/a&gt; by the same author uses Python this time, so we can expect some fun there.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Overall, the book is filled with practical code examples that are useful when understanding a network application using socket system calls. Of course, you won’t really need to use these functions when writing your own application, because many languages support their own wrappers for those "low-level" socket networking functions(Python has libraries like &lt;a href="https://docs.python.org/3/library/socketserver.html" rel="noopener noreferrer"&gt;socketserver&lt;/a&gt; and &lt;a href="https://docs.python.org/3/library/http.html" rel="noopener noreferrer"&gt;http&lt;/a&gt;). Nonetheless, I think once in your career as a developer you should understand what is going on behind all these highly abstracted communications using HTTPS or websocket. In that sense, this book is a good read and also a good reference.&lt;/p&gt;

</description>
      <category>computerscience</category>
      <category>socket</category>
      <category>c</category>
    </item>
    <item>
      <title>[Programming, Opinion] Should you read the GoF(design pattern) book?</title>
      <dc:creator>UponTheSky</dc:creator>
      <pubDate>Tue, 28 May 2024 23:29:46 +0000</pubDate>
      <link>https://dev.to/uponthesky/programming-opinion-should-you-read-the-gofdesign-pattern-book-2cef</link>
      <guid>https://dev.to/uponthesky/programming-opinion-should-you-read-the-gofdesign-pattern-book-2cef</guid>
      <description>&lt;p&gt;&lt;em&gt;image source: &lt;a href="https://www.irasutoya.com/2021/01/blog-post_11.html"&gt;https://www.irasutoya.com/2021/01/blog-post_11.html&lt;/a&gt;&lt;/em&gt;&lt;br&gt;
(A sleeping woman in front of a PC)&lt;/p&gt;

&lt;h2&gt;
  
  
  TL; DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;I won’t recommend reading it without much experience in programming - Have experience of real-world problems first&lt;/li&gt;
&lt;li&gt;Use it as a reference, especially when building a complex system on your own&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In software engineering world, there are several books that allegedly called &lt;strong&gt;MUST-READ&lt;/strong&gt;. There are millions of such, but one of the noticeable books is the &lt;a href="https://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612"&gt;"Design Patterns" book a.k.a. the GoF(Gang of Four) book&lt;/a&gt;. Regardless of its age, this book is being mentioned frequently on the Internet even in 2024 as of this writing. To introduce it shortly, it is considered as a "bible" for designing objected-oriented applications, with examples in C++ and SmallTalk. Some even say you &lt;strong&gt;MUST READ&lt;/strong&gt; it before becoming a senior level engineer.&lt;/p&gt;

&lt;p&gt;Attracted by so many compliments on this book, I read through this book as well, checking every pattern introduced. But after finishing the book and working on a real-world product, I now doubt about whether this book is really something you &lt;strong&gt;MUST READ&lt;/strong&gt;. Has this book helped me writing better code, or led to making better design and decision in software development in general?  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DISCLAIMER&lt;/strong&gt;: I am not a senior engineer with 10+ YOE, so my opinion is highly skewed towards the standpoint of junior software engineers of YOE less than 5 years. I highly value different opinions on this book as well. &lt;/p&gt;

&lt;h2&gt;
  
  
  Why I won’t recommend the GoF book for beginners
&lt;/h2&gt;

&lt;p&gt;One thing I want to speak up is that this book is not for beginners in programming and software engineering. There are several reasons I can think up but here are two main things:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. You might focus too much on the patterns themselves
&lt;/h3&gt;

&lt;p&gt;You may have heard these seemingly "professional" jargons from a lot of documentations, such as &lt;em&gt;Singleton&lt;/em&gt;, &lt;em&gt;Facade&lt;/em&gt;, &lt;em&gt;Factory&lt;/em&gt;, &lt;em&gt;Strategy&lt;/em&gt;, etc. These are the patterns introduced in the GoF book. If you don’t have that much experience in software engineering, you may feel that you have to read the book to understand these concepts thoroughly. &lt;/p&gt;

&lt;p&gt;However, personally I think this is a bad approach to software engineering in general. Being exposed to the patterns first may obscure the practical intention of the patterns themselves - organize the solution in structured ways to solve designing software problems. Unless you face and touch the problems first, you won’t fully grasp why you use those patterns in the first place.&lt;/p&gt;

&lt;p&gt;Conversely, you may concentrate on memorizing the patterns and their code examples. But do you actually understand why the singleton pattern is used here and not there, and why the prototype pattern is not discussed in languages like Python? These insights are only learnable from real experiences, not from the book. &lt;/p&gt;

&lt;p&gt;Basically, we only need knowledge that we use. There should be several patterns that are implicitly used in your daily work, but even so, you don’t have to memorize the patterns themselves. If your hands know them, then you know them. &lt;/p&gt;

&lt;h3&gt;
  
  
  2. The code examples are abstract and you can’t run them
&lt;/h3&gt;

&lt;p&gt;The other reason is because of the code examples introduced in the book. The code itself is not bad, although it is rather old(even before C++11). The problem of the code examples is that it is abstract and not used in a real application example. &lt;/p&gt;

&lt;p&gt;Of course, the book introduces a real application example before the catalogs, in chapter 1 and 2. However, in my opinion it is too short to grasp each of the patterns. Also, in 2024, we need examples that we are more familiar with, such as web, mobile, and machine learning applications. &lt;/p&gt;

&lt;p&gt;When it comes to the examples in the individual patterns, they are not a part of an actually running application, but a collection of mock classes and functions in C++. Thus, even if you read the code, you won’t really understand how it would be implemented in a real application. And the problem is, you only learn from concrete code that actually runs and gives expected results. &lt;/p&gt;

&lt;h2&gt;
  
  
  How I would approach this book in the second read
&lt;/h2&gt;

&lt;p&gt;But I am not saying you should not read this book. Rather, I think it would be good to read after having experienced in several software projects so that you can relate your own experience to the patterns from the book. If I would read this book again in the future, I would take the following approaches:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Looking up the list of the patterns only when the names of the patterns come up from documentations
&lt;/h3&gt;

&lt;p&gt;Some software authors love to quote the patterns introduced in this book. Therefore, unfortunately, you have to know what the patterns do that the author of a documentation mentions(for example, &lt;a href="https://doc.rust-lang.org/book/ch17-03-oo-design-patterns.html"&gt;Rust's THE BOOK directly discuss the state pattern in a single chapter&lt;/a&gt;). However, it doesn’t mean that you have to know every single design pattern in GoF. Only after you bump into the jargons, then you look up the book. &lt;/p&gt;

&lt;p&gt;Read the general introduction of the pattern from the book, then read the documentation. Compare the code examples in the book with the one in the documentation. Write your own code according to the documentation and understand why the author mentions those specific patterns.&lt;/p&gt;

&lt;p&gt;For example, &lt;a href="https://docs.llamaindex.ai/en/stable/module_guides/supporting_modules/settings/"&gt;LlamaIndex framework uses the singleton pattern for configuration&lt;/a&gt;. Why did the authors use this pattern for configuration, and why not something else? You many find useful insights from the GoF book about this design decision.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Consulting the designs when designing a complex system on your own
&lt;/h3&gt;

&lt;p&gt;Sometimes, we may create an application that is totally brand new - not using highly opinionated frameworks written by others but your own one. It is absolutely necessary for you to design the application from scratch, and you need to consider various options. &lt;/p&gt;

&lt;p&gt;In this case, I think it would be good to brush up on your knowledge on design patterns. The GoF book already contains a lot of patterns with clear explanations in diagrams, so it is a good way to replenish your options. Especially, the design patterns in the book are for managing a complex system efficiently, thus you would benefit from skimming through the list of the patterns.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Against the hype that “You should read the GoF book”, I strongly claimed here in this article that you should face the real-world problems first and use the book as a helpful reference. There is no such book as &lt;strong&gt;MUST READ&lt;/strong&gt; - you &lt;strong&gt;USE&lt;/strong&gt; books for your own good and efficiency.&lt;/p&gt;

</description>
      <category>books</category>
      <category>productivity</category>
      <category>programming</category>
    </item>
    <item>
      <title>[Book Review] Linux Basics for Hackers by OccupyTheWeb</title>
      <dc:creator>UponTheSky</dc:creator>
      <pubDate>Sat, 06 Apr 2024 10:25:46 +0000</pubDate>
      <link>https://dev.to/uponthesky/book-review-linux-basics-for-hackers-by-occupytheweb-4f7c</link>
      <guid>https://dev.to/uponthesky/book-review-linux-basics-for-hackers-by-occupytheweb-4f7c</guid>
      <description>&lt;p&gt;*image source: &lt;a href="https://commons.wikimedia.org/wiki/File:African_penguin,_Cape_Town_(_1050598).jpg"&gt;African Penguin, Cape Town from Wikipedia Commons&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  TL; DR
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;The book is for introducing basic features and commands of Linux(Kali) in general.&lt;/li&gt;
&lt;li&gt;It is a good overview/review for those who are already familiar with programming and CLI, but not having had a chance to directly deal with Linux.&lt;/li&gt;
&lt;li&gt;It would be a good book for those who are actually interested in cybersecurity field.&lt;/li&gt;
&lt;li&gt;Personally, I think the number of topics covered is a bit too high that the depth of each topic is inevitably shallow due to the limit on the number of pages.&lt;/li&gt;
&lt;li&gt;It would be difficult to follow the book material without access to a linux machine.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Intro - why did I choose this book?
&lt;/h1&gt;

&lt;p&gt;Always feeling ashamed of not having enough knowledge and experience in Linux, I have been searching for a comprehensive and yet hands-on introduction to Linux. Although there are a myriad of such materials out there, I found this book &lt;a href="https://www.amazon.com/Linux-Basics-Hackers-Networking-Scripting/dp/1593278551"&gt;Linux Basics for Hackers&lt;/a&gt; by OccupyTheWeb particularly interesting. I have looked up a few Linux books that are popular but many of them are like a reference, which means you won’t learn Linux by doing something. But with its specific catch-phrase &lt;em&gt;Hacking&lt;/em&gt;, I thought this book would be both enjoyable and informative to read.&lt;/p&gt;

&lt;h1&gt;
  
  
  Good Parts
&lt;/h1&gt;

&lt;h2&gt;
  
  
  1. Comprehensive introduction to many core concepts of Linux
&lt;/h2&gt;

&lt;p&gt;In the first few chapters, you might feel that this book tries to explain very basic commands like &lt;code&gt;ls&lt;/code&gt; and &lt;code&gt;ps aux&lt;/code&gt;. This might be something to be taken for granted for an experienced programmer. &lt;/p&gt;

&lt;p&gt;But still, I find this approach helpful for those who have begun learning or reviewing the Linux system. One of the strengths of this book is that it explains only necessary concepts that are relevant to the theme of the book - &lt;em&gt;Hacking&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;However, since hacking a system is equivalent to knowing how the system works in general, the book in effect deals with most of the basic and core parts of the Linux. From running the &lt;code&gt;apt-get&lt;/code&gt; command to running a Python script, the book covers as many topics as possible for hackers.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Focusing on a practical purpose - cybersecurity and hacking
&lt;/h2&gt;

&lt;p&gt;Compared to other books introducing Linux, I find this book fun to read, because it constantly explains how the concepts are related to hacking and cybersecurity. As a result, the book is less like prose and more consistent in conveying its message to the readers. &lt;/p&gt;

&lt;p&gt;Moreover, it introduces a couple of low-level parts of Linux such as networks, Wifi, device driver, etc. As a person who has only developing high-level web applications throughout my career, I found this "new world" fairly refreshing. The book provides absolutely a good introduction to entry points that a young hacker can explore and enjoy. &lt;/p&gt;

&lt;h1&gt;
  
  
  Soso Parts
&lt;/h1&gt;

&lt;h2&gt;
  
  
  1. Limited number of pages for a number of topics
&lt;/h2&gt;

&lt;p&gt;This book manages to introduce core concepts and examples of Linux. However, since this book is not large enough in its physical size, there are only a few sections that explain concepts deep enough. Many of the topics I read are covered shallowly, usually by explaining how a certain command is run and what result of it is like. In order to learn deeper about a command or a concept, I had to look up the Internet often. &lt;/p&gt;

&lt;p&gt;Thus, even though there are a lot of concepts that I have learned from the book, many of them remain as very basic. For instance, I still don’t really know how exactly a Linux kernel is started and how to force quit "zombie" processes if an application has not been closed properly. I think it would have been better if the author simplified very basic commands like &lt;code&gt;ls&lt;/code&gt; and explained more of concepts like access list or socket programming.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Not easy for non-Linux users to follow
&lt;/h2&gt;

&lt;p&gt;Of course, this book is about Linux so it seems not fair to blame the book for the accessibility. However, a lot of programmers like me use MacOS, and many of the commands introduced in the book don’t exist on MacOS. I personally used Docker for running the example code, but still it was time consuming to search for packages to install. &lt;/p&gt;

&lt;p&gt;Because running the &lt;a href="https://www.virtualbox.org/"&gt;Virtualbox&lt;/a&gt; application is daunting for low-performing computers, it would have been better if the author also provided alternative methods for following the materials of the book on MacOS.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Nevertheless, I think this book is good for brushing up on the knowledge on Linux in general. At least I now know what part of Linux I need to look into if there is a problem. The book itself is very concisely and clearly written, so you wouldn’t find it difficult to follow the author while practicing the commands for hacking. &lt;/p&gt;

</description>
      <category>linux</category>
      <category>network</category>
      <category>cybersecurity</category>
      <category>beginners</category>
    </item>
    <item>
      <title>[Go, Book Review] Learn Go with Tests by Chris James</title>
      <dc:creator>UponTheSky</dc:creator>
      <pubDate>Sat, 23 Mar 2024 09:26:19 +0000</pubDate>
      <link>https://dev.to/uponthesky/book-review-learn-go-with-tests-by-chris-james-587b</link>
      <guid>https://dev.to/uponthesky/book-review-learn-go-with-tests-by-chris-james-587b</guid>
      <description>&lt;p&gt;*image credit to &lt;a href="https://reneefrench.blogspot.com/"&gt;Renee French&lt;/a&gt;, the &lt;a href="https://go.dev/blog/gopher"&gt;source is the one of the official Go blog posts&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  TL; DR
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;The book covers from the very basic concepts of the language to writing complex applications.&lt;/li&gt;
&lt;li&gt;You learn Go interactively by writing tests.&lt;/li&gt;
&lt;li&gt;This book is more than learning Go itself - you learn practical TDD methodology from the author.&lt;/li&gt;
&lt;li&gt;Highly recommended for those who have just started learning Go, or the Software engineering in general.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Intro - why did I choose this book?
&lt;/h1&gt;

&lt;p&gt;Since my &lt;a href="https://dev.to/uponthesky/rust-what-ive-learned-from-reading-the-book-over-the-last-10-months-5f89"&gt;painful memory of starting my Rust journey&lt;/a&gt;, I setup my own principle of learning a new programming language: begin with very simple tutorial, and write as many examples as possible before moving on to advanced cases. &lt;/p&gt;

&lt;p&gt;Therefore, I was very fortunate to get to know this amazing book, &lt;a href="https://quii.gitbook.io/learn-go-with-tests"&gt;Learn Go with Tests&lt;/a&gt;. Right after skimming through &lt;a href="https://go.dev/tour/"&gt;&lt;em&gt;the tour&lt;/em&gt;&lt;/a&gt;, I was looking for a material that provides plenty of examples and good practices. The &lt;strong&gt;LGWT&lt;/strong&gt; book exactly suits the needs. &lt;/p&gt;

&lt;h1&gt;
  
  
  Good Parts
&lt;/h1&gt;

&lt;h2&gt;
  
  
  1. Learning features of Go interactively with tests
&lt;/h2&gt;

&lt;p&gt;This book starts from basic concepts of the language such as types, loops, pointers, interfaces, etc. But it also covers several advanced and frequently used concepts such as context and concurrency. The book provides a very good introduction to these difficult topics in general, with actual running examples as tests rather than with abstract words.&lt;/p&gt;

&lt;p&gt;I would like to say that learning the language with writing test code is one of the best features of this book. Usually, learning a compile language like C/C++ or Rust requires users to run compilation commands, which usually takes a long time. However, by writing test and run it, you can actually check how a few lines of Go work right away. Even on my old 2017 MacBook Pro with 8GB RAM, running tests usually took around half a second. &lt;/p&gt;

&lt;p&gt;Additionally, almost all the chapters of this book contain tests. Thus, as you read through the book, actually writing and running those tests, you will become much familiar with writing Go.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Rethinking of software design and tests
&lt;/h2&gt;

&lt;p&gt;In the chapters of building an application, the author constantly bring up the idea of what is a good software design and how you can achieve it with the TDD principle. Except the chapters about Go language features, the book is more like a TDD and software design book with examples written in Go. The author gives his real-life stories from his long time of software engineering careers, and these are what normal software engineers usually face day to day. I was astonished how his stories and claims resonate with my own experience with bad software design and messy test code I had written in the past. If the &lt;a href="https://www.amazon.com/Test-Driven-Development-Kent-Beck/dp/0321146530"&gt;TDD book by Kent Back&lt;/a&gt; can be thought of as a manifesto for TDD, this book is more like an anecdote from a senior engineer at the reader’s company. &lt;/p&gt;

&lt;h1&gt;
  
  
  Soso Parts
&lt;/h1&gt;

&lt;p&gt;There are not particularly bad parts. Overall the book is well written and organized. Moreover, Since it is also an &lt;a href="https://github.com/quii/learn-go-with-tests"&gt;open-source material&lt;/a&gt;, many readers have contributed to the contents of the book(including a few of mine :)). I hope there are more books like this for other languages such as Rust or Python. &lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;I highly recommend this book for Go newbies. It covers the language features extensively, and also provides practical code examples that you can run on your machine. You will also learn rigorous principles of writing maintainable and robust software with TDD by reading this book. Even if you’re an experienced Go developer, I am pretty sure you could learn important lessons from this book as well. &lt;/p&gt;

</description>
      <category>go</category>
      <category>testing</category>
      <category>begineer</category>
    </item>
    <item>
      <title>[Go] Understanding net/http - How to run a server like a Pro?</title>
      <dc:creator>UponTheSky</dc:creator>
      <pubDate>Fri, 01 Mar 2024 17:23:07 +0000</pubDate>
      <link>https://dev.to/uponthesky/go-understanding-nethttp-how-to-run-a-server-like-a-pro-379m</link>
      <guid>https://dev.to/uponthesky/go-understanding-nethttp-how-to-run-a-server-like-a-pro-379m</guid>
      <description>&lt;p&gt;*image credit to &lt;a href="https://reneefrench.blogspot.com/"&gt;Renee French&lt;/a&gt;, the &lt;a href="https://go.dev/blog/gopher"&gt;source is the one of the official Go blog posts&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  TL; DR
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;ServeMux&lt;/code&gt; as the multiplexer&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;Serve&lt;/code&gt; struct for detailed configurations&lt;/li&gt;
&lt;li&gt;It’s okay with using &lt;code&gt;Serve::ListenAndServe&lt;/code&gt;, but &lt;code&gt;Listen&lt;/code&gt; and &lt;code&gt;Serve&lt;/code&gt; can be called separately(&lt;code&gt;Listen&lt;/code&gt; is in the &lt;a href="https://pkg.go.dev/net"&gt;net&lt;/a&gt; package)&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Introduction - Stop relying on default functions
&lt;/h1&gt;

&lt;p&gt;At a glance, It looks simple to write an HTTP server in Go, using the standard &lt;a href="https://pkg.go.dev/net/http"&gt;net/http&lt;/a&gt; package. Many of the tutorials and blog posts usually don’t go beyond using default functions like &lt;code&gt;http.HandleFunc&lt;/code&gt; or &lt;code&gt;http.ListenAndServe&lt;/code&gt;.  And there don’t seems to be many issues with it. Who cares as long as it works well?&lt;/p&gt;

&lt;p&gt;Well, if you’re a professional software engineer, you would highly disagree with this. We need to take control over every aspect of what we’re wielding as our mighty weapon, if possible. Relying on default functions provided by the package may obscure the details under the hood. As I spend more time learning Go, I wanted to know what’s behind this “default layer”, and be able to write an HTTP server in a more sophisticated way. &lt;/p&gt;

&lt;p&gt;In this short article, I want to discuss the ways of starting a server in net/http package, from simple ones to more advanced ones. Before diving into the main part of the article, let me point out the following three points:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;This article is motivated by a &lt;a href="https://grafana.com/blog/2024/02/09/how-i-write-http-services-in-go-after-13-years/"&gt;blog post by an engineer at Grafana&lt;/a&gt;, which has been quite popular in the Go community recently.&lt;/li&gt;
&lt;li&gt;I won’t consider any of the third-party libraries like &lt;a href="https://gin-gonic.com/"&gt;Gin&lt;/a&gt; or &lt;a href="https://echo.labstack.com/"&gt;Echo&lt;/a&gt;. It is not because they are not good, but because I want to dig into what is considered as “standard” in Go language and by its developers. &lt;/li&gt;
&lt;li&gt;Also, it could mean so many things when I say “How to write a server in Go”, because there are a myriads of things to consider - middleware, router, security, network protocols, concurrency issues, to name a few. Therefore, this article only aims to explore how to write and run a "server instance" rather a "web server application".
&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Various ways to run a server using net/http package
&lt;/h1&gt;

&lt;h2&gt;
  
  
  1. Start simple - &lt;code&gt;DefaultServeMux&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Many learning materials for beginners in Go(such as &lt;a href="https://gobyexample.com/http-server"&gt;Go by Example&lt;/a&gt; or &lt;a href="https://gowebexamples.com/http-server"&gt;Go Web Examples&lt;/a&gt; shows how to run an HTTP server in a simple example like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"log"&lt;/span&gt;
    &lt;span class="s"&gt;"net/http"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Hello, Go HTTP Server!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":8000"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&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;In a nutshell, this method simply registers a plain function of two parameters &lt;code&gt;(w http.ResponseWriter, r *http.Request)&lt;/code&gt; such that the function is called whenever a client requests the targeted endpoint. In this way, there is no need to fully understand the interface &lt;code&gt;Handler&lt;/code&gt;; you just need to write logic to process incoming requests.&lt;/p&gt;

&lt;p&gt;However, there is an interesting point to look at here. What is the relationship between &lt;code&gt;http.HandleFunc&lt;/code&gt; and &lt;code&gt;http.ListenAndServe&lt;/code&gt;, as these two functions have nothing in common. But, as a matter of fact, they &lt;strong&gt;DO&lt;/strong&gt; share a global variable called &lt;code&gt;DefaultServeMux&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you read the &lt;a href="https://pkg.go.dev/net/http"&gt;documentation&lt;/a&gt;, it says&lt;/p&gt;

&lt;p&gt;for &lt;code&gt;HandlerFunc&lt;/code&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;HandleFunc registers the handler function for the given pattern in DefaultServeMux&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;and for &lt;code&gt;ListenAndServe&lt;/code&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The handler is typically nil, in which case DefaultServeMux is used.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Thus, a function registered by &lt;code&gt;HandleFunc&lt;/code&gt; is stored in the global variable &lt;code&gt;DefaultServeMux&lt;/code&gt; of the package, which is then used by &lt;code&gt;ListenAndServe&lt;/code&gt;. So the key now is to understand &lt;code&gt;ServeMux&lt;/code&gt; in general.&lt;/p&gt;

&lt;h3&gt;
  
  
  (&lt;strong&gt;REMARK&lt;/strong&gt;) What is &lt;code&gt;ServeMux&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;Let’s look at the documentation once again:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;ServeMux is an HTTP request multiplexer. It matches the URL of each incoming request against a list of registered patterns and calls the handler for the pattern that most closely matches the URL.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As a &lt;a href="https://en.wikipedia.org/wiki/Multiplexing"&gt;multiplexer&lt;/a&gt;, a &lt;code&gt;ServeMux&lt;/code&gt; instance receives multiple HTTP requests and hands each of them over to an appropriate handler. Thus, &lt;code&gt;ListenAndServe&lt;/code&gt; starts a server that &lt;strong&gt;listens&lt;/strong&gt; to requests headed to the specified address(in this case, it is "&lt;a href="http://localhost:8000%22"&gt;http://localhost:8000"&lt;/a&gt;), and then delegates them to its &lt;code&gt;(Default)ServeMux&lt;/code&gt; in order to handle(note that &lt;code&gt;ServeMux&lt;/code&gt; implements the interface &lt;code&gt;http.Handler&lt;/code&gt;). &lt;/p&gt;

&lt;h2&gt;
  
  
  2. More sophisticated usage - make your own &lt;code&gt;ServeMux&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;But why is it not a good practice to use &lt;code&gt;DefaultServeMux&lt;/code&gt;? Mainly because it is a global object. According to &lt;a href="https://www.amazon.com/Practical-Go-Building-Non-Network-Applications/dp/1119773814"&gt;Practical Go by Amit Saha&lt;/a&gt;, many unnoticed packages could also access the object, such that related security or concurrency problems could occur. Therefore, it is better to create our own &lt;code&gt;ServeMux&lt;/code&gt; instances using &lt;code&gt;http.NewServeMux&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;mux&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewServeMux&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Hello, Go HTTP Server!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":8000"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mux&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;Of course, since &lt;code&gt;ListenAndServe&lt;/code&gt; accepts the &lt;code&gt;http.Handler&lt;/code&gt; interface in general, we can wrap &lt;code&gt;mux&lt;/code&gt; with middlewares(the technique is introduced in &lt;a href="https://dev.to/uponthesky/go-understanding-nethttp-package-handler-family-2422"&gt;one of my previous article&lt;/a&gt;)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;someMiddleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handler&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandlerFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// custom logic&lt;/span&gt;
        &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ServeHTTP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c"&gt;// custom logic&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// …&lt;/span&gt;
    &lt;span class="n"&gt;mux&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewServeMux&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;mux&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;someMiddleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c"&gt;// …&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  3. Writing your own &lt;code&gt;Server&lt;/code&gt;
&lt;/h1&gt;

&lt;p&gt;But &lt;code&gt;ServeMux&lt;/code&gt; is only a multiplexer that distributes incoming requests, and the server is bootstrapped at &lt;code&gt;http.ListenAndServe&lt;/code&gt;.  Obviously, it doesn’t accept any configuration for the server application it sets up. Therefore, if we need to tweak a few configurations for a server, we use &lt;a href="https://pkg.go.dev/net/http#hdr-Servers"&gt;&lt;code&gt;http.Server&lt;/code&gt; struct&lt;/a&gt; in the package. &lt;/p&gt;

&lt;p&gt;As you see the &lt;a href="https://pkg.go.dev/net/http#Server"&gt;documentation&lt;/a&gt;, the configurable variables are related to fairly low-level concepts. But if we’re considering a production environment, complicated configuration is inevitable.&lt;/p&gt;

&lt;p&gt;Now we have more freedom in writing a web server in Go, only using the net/http package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;addr&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SERVER_ADDRESS"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;addr&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;addr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;":8080"&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// step 1: make your own `ServeMux`&lt;/span&gt;
        &lt;span class="n"&gt;mux&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewServeMux&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="c"&gt;// add handlers &amp;amp; middlewares&lt;/span&gt;
    &lt;span class="c"&gt;// …&lt;/span&gt;

    &lt;span class="c"&gt;// step 2: make your own `Server`&lt;/span&gt;
    &lt;span class="n"&gt;srv&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Addr&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Handler&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ReadHeaderTimeout&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Minute&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;srv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListenAndServe&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;Also, we may go deeper into setting up the TLS support using &lt;code&gt;ListenAndServeTLS&lt;/code&gt; instead of plain &lt;code&gt;ListenAndServe&lt;/code&gt;, with necessary certificate files. For simplicity, we will keep using &lt;code&gt;ListenAndServe&lt;/code&gt; for the rest of the article.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Advanced - Splitting &lt;code&gt;ListenAndServe&lt;/code&gt; into &lt;code&gt;Listen&lt;/code&gt; and &lt;code&gt;Serve&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Many of the learning materials and blog posts on writing Go server with net/http simply use the &lt;code&gt;ListenAndServe&lt;/code&gt; method. In most of the cases it is fine &lt;br&gt;
since it uses &lt;a href="https://pkg.go.dev/net/http#Server.ListenAndServe"&gt;TCP connections under the hood&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;So we break down the function to &lt;code&gt;Listen&lt;/code&gt; and &lt;code&gt;Serve&lt;/code&gt;, instead of the last line &lt;code&gt;log.Fatal(s.ListenAndServe())&lt;/code&gt; in the above code chunk like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// step 3: Listen to TCP connections&lt;/span&gt;
&lt;span class="n"&gt;ln&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"tcp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; 

&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;ln&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;srv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Serve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ln&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you might have already expected, &lt;code&gt;Listen&lt;/code&gt; function is a wrapper of the &lt;a href="https://cs.opensource.google/go/go/+/master:src/syscall/zsyscall_linux_amd64.go;drc=45b641ce15159e29fa4494b837493042d1e10384;l=1212"&gt;system call &lt;code&gt;listen&lt;/code&gt; at the OS kernel level&lt;/a&gt;. And &lt;code&gt;Serve&lt;/code&gt; &lt;a href="https://cs.opensource.google/go/go/+/refs/tags/go1.22.0:src/net/http/request.go;l=1051"&gt;reads request data from the socket buffer&lt;/a&gt; and &lt;a href="https://cs.opensource.google/go/go/+/refs/tags/go1.22.0:src/net/http/server.go;l=2039"&gt;hands over the information(with pre-generated response instance) to its handler&lt;/a&gt;. We can go deeper here but it is beyond the scope of this post. However, savor the beauty of the naming "Listen"(the incoming connection from a socket) and "Serve"(the request from the listened connection with enrolled handler) here - how well they are made!&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;In effect, we have break down "convenient" default functions in the net/http package into several components that we can configure directly. As we go deeper, it goes down to the fundamental part of the network programming - TCP socket programming, as we discussed at Advanced - Splitting &lt;code&gt;ListenAndServe&lt;/code&gt; into &lt;code&gt;Listen&lt;/code&gt; and &lt;code&gt;Serve&lt;/code&gt;. I am not sure whether we need to configure at this level. Nevertheless, I believe it is important to understand how the mechanism works when we write a server program. &lt;/p&gt;

&lt;p&gt;Still, it is of course not writing a server instance "as a Pro". There are more details uncovered yet in this post. But "like a Pro", we mimic the way a professional software engineer writes code. &lt;/p&gt;

&lt;h1&gt;
  
  
  references
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Go by Example: &lt;a href="https://gobyexample.com/http-server"&gt;https://gobyexample.com/http-server&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Go Web Examples: &lt;a href="https://gowebexamples.com/http-server"&gt;https://gowebexamples.com/http-server&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;net/http package: &lt;a href="https://pkg.go.dev/net/http"&gt;https://pkg.go.dev/net/http&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Learn Go with Tests: &lt;a href="https://quii.gitbook.io/learn-go-with-tests/build-an-application/http-server"&gt;https://quii.gitbook.io/learn-go-with-tests/build-an-application/http-server&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;"How I write HTTP services in Go after 13 years" by Mat Ryer: &lt;a href="https://grafana.com/blog/2024/02/09/how-i-write-http-services-in-go-after-13-years/"&gt;https://grafana.com/blog/2024/02/09/how-i-write-http-services-in-go-after-13-years/&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;Network Programming with Go by Adam Woodcock, Ch9: &lt;a href="https://www.amazon.com/Network-Programming-Go-Adam-Woodbeck/dp/1718500882"&gt;https://www.amazon.com/Network-Programming-Go-Adam-Woodbeck/dp/1718500882&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Practical Go by Amit Saha, Ch5~7: &lt;a href="https://www.amazon.com/Practical-Go-Building-Non-Network-Applications/dp/1119773814"&gt;https://www.amazon.com/Practical-Go-Building-Non-Network-Applications/dp/1119773814&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>go</category>
      <category>webdev</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
