<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Dmitrii’s Substack]]></title><description><![CDATA[World understanding from geeky perspective! Architecture!]]></description><link>https://kuragin.dev</link><image><url>https://substackcdn.com/image/fetch/$s_!7P6c!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F59b88e05-1a70-41ac-a99e-fd777050da91_353x353.png</url><title>Dmitrii’s Substack</title><link>https://kuragin.dev</link></image><generator>Substack</generator><lastBuildDate>Wed, 03 Jun 2026 12:30:51 GMT</lastBuildDate><atom:link href="https://kuragin.dev/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Dmitrii Kuragin]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[kuragin@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[kuragin@substack.com]]></itunes:email><itunes:name><![CDATA[Dmitrii Kuragin]]></itunes:name></itunes:owner><itunes:author><![CDATA[Dmitrii Kuragin]]></itunes:author><googleplay:owner><![CDATA[kuragin@substack.com]]></googleplay:owner><googleplay:email><![CDATA[kuragin@substack.com]]></googleplay:email><googleplay:author><![CDATA[Dmitrii Kuragin]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Sharing is Caring (Bus Factor)]]></title><description><![CDATA[You can do so much on your own! And, you can do much more with a team!]]></description><link>https://kuragin.dev/p/sharing-is-caring-bus-factor</link><guid isPermaLink="false">https://kuragin.dev/p/sharing-is-caring-bus-factor</guid><dc:creator><![CDATA[Dmitrii Kuragin]]></dc:creator><pubDate>Tue, 04 Feb 2025 17:35:39 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f31c24f-9be4-4a51-b28c-b3c3a9d2e3d2_512x512.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Regardless of your position on the team, have you ever wondered what would happen if the key person were no longer available? Let's say, what if they got hit by a bus? Win the lottery? Today? Tomorrow? Next week?</p><p><em>Bus factor</em> - is a minimum number of key people that have to disappear before the project collapses. This idea highlights an important question: Are you truly working as a team, or is your project in sharp decline due to over-reliance on very specific individuals?</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://kuragin.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Dmitrii&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>Of course, there is no need for all team members to equally know everything or being absolutely replaceable at any time. And, at the same time, do people feel confident to go on vacation? To take a sick day? Delegate code review at busy times? Trust others to represent the team on some meeting?</p><p>Do you have documentation people can use in case of absence of the key person? Playbooks? Do they frequently share and explain their technical decisions and vision? Do you have an architect who is not very good at written or verbal communications and is not capable of explaining the "why" behind their requests?</p><p>Do you have a person who is really proud they've built the entire system? All by themselves! And even more proud to single-handedly and heroically support it on Sunday morning? What happens to the project and the managers when that person goes on vacation? Do they grab the laptop w/ them because they think that no one is capable of handling anything?</p><p>How good is your manager? What would happen if they go on vacation? Change the job? How do you onboard new teammates? <strong>DO</strong> you board new teammates or just throw them at the code?</p><p>What happens when the code owner is unavailable for a day or two? Are the people blocked? Can they be unblocked? What if it is a 3-week vacation?</p><p>When a single point of knowledge has a bus factor of less than 2 you might find the team in a very peculiar situation. Not only it can lead to a disaster when the person is unavailable, but it can also drastically reduce the productivity of your team in the long term.</p><p>What can you do?</p><ul><li><p><strong>Accept people's opinions</strong>. Not everybody is the same. Having alternative perspectives is a strength and the power of working as a team.</p></li><li><p>Make quality <strong>code reviews</strong> your team habit - both genuinely asking for people's opinion and providing clear explanations of your feedback to them.</p></li><li><p><strong>Documentation</strong> - Write things down, ask for review, and own it.</p></li><li><p><strong>Pair program</strong> - The forum where questions can find answers in their depths and as early as possible.</p></li><li><p><strong>Delegate</strong> - Can't? Why not? Don't you trust your teammates to handle the situation?</p></li><li><p><strong>Navigate</strong> - Don't know the answer? Do you know someone else who <strong>DOES</strong> know the answer?</p></li><li><p><strong>Simplify</strong> - is your code and documentation easy to read and accessible to everyone?</p></li><li><p><strong>Explain your decisions</strong> - Explain the "why" behind your choices to help others understand your point of view and learn from your thought process.</p></li><li><p><strong>Teach and Learn</strong> - don't let people miss out on the learning opportunities even if it slows things down in the short term.</p></li></ul><p>Share the knowledge, encourage solving unknowns, and foster collaboration! Be a good teammate and a good person.</p><p>Further reading: <a href="https://en.wikipedia.org/wiki/Bus_factor">Bus Factor on Wikipedia</a>.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://kuragin.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Dmitrii&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Join my new subscriber chat]]></title><description><![CDATA[A private space for us to converse and connect]]></description><link>https://kuragin.dev/p/join-my-new-subscriber-chat</link><guid isPermaLink="false">https://kuragin.dev/p/join-my-new-subscriber-chat</guid><dc:creator><![CDATA[Dmitrii Kuragin]]></dc:creator><pubDate>Sat, 16 Nov 2024 02:01:13 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!KYZT!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0f63c9a-2296-4c96-a2f9-52648999bb00_2000x1000.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Today I&#8217;m announcing a brand new addition to my Substack publication: Dmitrii&#8217;s Substack subscriber chat.</p><p>This is a conversation space exclusively for subscribers&#8212;kind of like a group chat or live hangout. I&#8217;ll post questions and updates that come my way, and you can jump into the discussion.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://open.substack.com/pub/kuragin/chat&quot;,&quot;text&quot;:&quot;Join chat&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://open.substack.com/pub/kuragin/chat"><span>Join chat</span></a></p><div><hr></div><h2>How to get started</h2><ol><li><p><strong>Get the Substack app by clicking <a href="https://substack.com/app/app-store-redirect">this link</a> or the button below.</strong> New chat threads won&#8217;t be sent sent via email, so turn on push notifications so you don&#8217;t miss conversation as it happens. You can also access chat <a href="https://open.substack.com/pub/kuragin/chat">on the web</a>.</p></li></ol><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://substack.com/app/app-store-redirect&quot;,&quot;text&quot;:&quot;Get app&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://substack.com/app/app-store-redirect"><span>Get app</span></a></p><ol start="2"><li><p><strong>Open the app and tap the Chat icon.</strong> It looks like two bubbles in the bottom bar, and you&#8217;ll see a row for my chat inside.</p></li></ol><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!KYZT!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0f63c9a-2296-4c96-a2f9-52648999bb00_2000x1000.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!KYZT!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0f63c9a-2296-4c96-a2f9-52648999bb00_2000x1000.jpeg 424w, https://substackcdn.com/image/fetch/$s_!KYZT!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0f63c9a-2296-4c96-a2f9-52648999bb00_2000x1000.jpeg 848w, https://substackcdn.com/image/fetch/$s_!KYZT!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0f63c9a-2296-4c96-a2f9-52648999bb00_2000x1000.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!KYZT!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0f63c9a-2296-4c96-a2f9-52648999bb00_2000x1000.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!KYZT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0f63c9a-2296-4c96-a2f9-52648999bb00_2000x1000.jpeg" width="1456" height="728" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e0f63c9a-2296-4c96-a2f9-52648999bb00_2000x1000.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:728,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:241528,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://kylewarrentest.substack.com/i/114198534?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0f63c9a-2296-4c96-a2f9-52648999bb00_2000x1000.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!KYZT!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0f63c9a-2296-4c96-a2f9-52648999bb00_2000x1000.jpeg 424w, https://substackcdn.com/image/fetch/$s_!KYZT!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0f63c9a-2296-4c96-a2f9-52648999bb00_2000x1000.jpeg 848w, https://substackcdn.com/image/fetch/$s_!KYZT!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0f63c9a-2296-4c96-a2f9-52648999bb00_2000x1000.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!KYZT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0f63c9a-2296-4c96-a2f9-52648999bb00_2000x1000.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><ol start="3"><li><p><strong>That&#8217;s it!</strong> Jump into my thread to say hi, and if you have any issues, check out <a href="https://support.substack.com/hc/en-us/sections/360007461791-Frequently-Asked-Questions">Substack&#8217;s FAQ</a>.</p></li></ol>]]></content:encoded></item><item><title><![CDATA[How hard could it be to iterate over a collection… in… C++?]]></title><description><![CDATA[C++ has a couple quite unique properties: zero-cost abstractions and backward compatibility.]]></description><link>https://kuragin.dev/p/how-hard-could-it-be-to-iterate-over</link><guid isPermaLink="false">https://kuragin.dev/p/how-hard-could-it-be-to-iterate-over</guid><dc:creator><![CDATA[Dmitrii Kuragin]]></dc:creator><pubDate>Sat, 16 Nov 2024 00:11:46 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!7P6c!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F59b88e05-1a70-41ac-a99e-fd777050da91_353x353.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>C++ has a couple quite unique properties: zero-cost abstractions and backward compatibility. While those properties are not perfectly followed in C++, the commitment to achieving them remains strong.</p><h3>Iteration in Pre-C++11</h3><p>Before C++11, there were few common ways to iterate over a collection (<em>std::vector</em> specifically). One of them is to use C++'s iterators:</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://kuragin.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Dmitrii&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><pre><code>for (
  std::vector&lt;Employee&gt;::const_iterator it = begin(input);
  it != end(input);
  it++
) {
  if (it-&gt;job == "programmer")
    names.push_back(it-&gt;name);
}</code></pre><p>The iterators provide a unified (unified is a buzzword recently) way to traverse over all types of collections. In C++, iterators are zero-cost abstraction, meaning developers incur (almost?) no performance overhead when using them. However, despite their universality, simply using indices can make the code more concise, since the type of the iterator is quite cumbersome to type:</p><pre><code>for (int ii = 0; ii &lt; input.size(); ++ii) {
  const Employee&amp; element = input[ii];

  if (element.job == "programmer")
    names.push_back(element.name);
}</code></pre><blockquote><p>Note: Using double "i" is an old-school way of defining an "i", which is very easy to search for in any text editor.</p></blockquote><h3>C++11 is like a new language!</h3><p>In C++11, we've got so many improvements, that it feels almost like a new language.</p><p>With introduction of <a href="https://en.cppreference.com/w/cpp/language/auto">auto</a>, one can simply avoid writing the iterator type:</p><pre><code>for (auto it = begin(input); it != end(input); it++) {
  if (it-&gt;job == "programmer")
    names.push_back(it-&gt;name);
}</code></pre><p>Yes, the only difference is <code>std::vector&lt;Employee&gt;::const_iterator</code> was replaced with <code>auto</code>. Despite the not-quite-trivial type deduction rules, <code>auto</code> is very good default option for very verbose names.</p><p>Also, C++11 brings <a href="https://en.cppreference.com/w/cpp/language/range-for">range-based for loops</a>, what makes the life so much easier:</p><pre><code>for (const auto&amp; element: input) {
  if (element.job == "programmer")
    names.push_back(element.name);
}</code></pre><h3>Bottom Line</h3><p>The <em>range-base for loop</em> is an alternative syntax for the iterator-based approach and requires the collection to be "iterable", i.e. implement speicific properties of a collection and iterator types.</p><p>The range-based for loop is implemented using C++'s iterators. The iterators are implemented using concrete types without extra overhead. The iterator implementation as efficient as the low-level code. The range-based for loop is a perfect example of zero-cost abstraction. Also, each of the ways of iterating over a collection would likely lead to nearly identical assembly code. And each way still works on newest compilers!</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://kuragin.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Dmitrii&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Add context to your error messages!]]></title><description><![CDATA[Something went wrong, please try again later.]]></description><link>https://kuragin.dev/p/add-context-to-your-error-messages</link><guid isPermaLink="false">https://kuragin.dev/p/add-context-to-your-error-messages</guid><dc:creator><![CDATA[Dmitrii Kuragin]]></dc:creator><pubDate>Mon, 19 Aug 2024 18:47:25 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!7P6c!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F59b88e05-1a70-41ac-a99e-fd777050da91_353x353.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Many of us, one way or the other saw an error message like this:</p><blockquote><p>Something went wrong, please try again later.</p></blockquote><p>If the error doesn't go away, what might be very frustrating on its own, the &#14;user have to call the support&#8230; All of us know, how daunting the experience could be. And even after the long waiting, the support team would do the troubleshooting and then&#8230; the support would suggest to <em><strong>reinstall your Operating System</strong></em> or <em><strong>return\replace the device</strong></em>.</p><p>Not all people equally know and care about how the "<em>bits and bytes</em>" work. And for many of the people, such error message luckily might mean the error will be fixed&#8230; somehow&#8230; on its own&#8230;</p><p>Also, one might see error messages like this:</p><ul><li><p>"Failed make an RPC request to "http://backend.example.com (Status Code: 500)".</p></li><li><p>"Failed to parse JSON message on line 347".</p></li><li><p>"Server returns \r\r where \r\n is expected".</p></li></ul><p>That kind of error message also do not bring much value even to skilled software engineer. Because complexity of the system might be to high to quickly jump into the right conclusion.</p><p>And, it seems like we're loosing some value there&#8230; and what does it have to do with context in error messages?! What does the error message lack of is the context!</p><p>Consider the following Python function which is supposed to fetch user information basing on <em>user id</em> and the given HTTP <em>client</em>:</p><pre><code>def show_user_name(session):
    try:
        user_name = fetch_user_name(session.client, session.user_id)
        show('User Name: {}'.format(user_name))
    except Exception:
        show('Error: Something went wrong, please try again later.')
</code></pre><p>The possible outcome of the function is to print either the user name or an error message w/o any extra information on kind of error we have. The current solution's built in a such way, that it's hard to add any meaningful information which comes from <code>fetch_user_name</code> function. But, we still can improve the side:</p><pre><code>logger = logging.getLogger(__name__)

def show_user_name(session):
    try:
        user_name = fetch_user_name(session.client, session.user_id)
        show('User Name: {}'.format(user_name))
    except Exception as e:
        logger.exception(
            'while fetching user name for user id {}.'.format(session.user_id)
        )

        show('Error: {} while fetching user name for {}'.format(repr(e)), user_id)
</code></pre><p>As you can see, we added few statements here and there and here're the improvements:</p><ul><li><p>The error message contains the information about the user id and what kind of exception is occurring during fetching the information. In case developers receive a ticket, they already have much more context to address the problem quicker w/ fewer turn-arounds.</p></li><li><p>The logger statement adds very useful context information for developers&#8230; Stacktrace! Which on its own might contain a lot more, but might be less useful to the end users.</p></li><li><p>Logging provides useful tool for developers to proactively solve the problems and not to wait for the user feedback or support ticket. Because the errors can be addressed earlier, the cost of software development is lower.</p></li></ul><p>Now, let's take a look into the function implementation.</p><pre><code>def fetch_user_name(client, user_id):
    response = client.request(
        "/api/user/{}".format(user_id)
    )

    serialized_response = json.loads(response)

    return serialized_response['preferred_name']
</code></pre><p>From the first sight, there nothing bad. But, does it give enough information about the error? It is hard to say:</p><ul><li><p>What kind of exceptions does <code>client.request</code> raises?</p></li><li><p>What do we do in case of failed JSON parsing?</p></li><li><p>What if the field is not present in the response?</p></li></ul><p>The code might be doing an absolutely correct and expected thing (take a look into the unit-tests of the function to make sure), but there might be also an alternative view:</p><pre><code>def fetch_user_name(client, user_id):
    try:
        response = client.request(
            "/api/user/{}".format(user_id)
        )
    except http_client.Error as e:
        raise Error(
            'Failed to fetch user info for client {} and user id {}.'.format(
                repr(client), repr(user_id)
            )
        ) from e

    try:
        serialized_response = json.loads(response)
    except json.JSONDecodeError as e:
        raise Error(
            'Failed to parse JSON response: {}, for client {}, user id {}'.format(
                repr(response),
                repr(client),
                repr(user_id)
            )
        ) from e

    try:
        return serialized_response['preferred_name']
    except KeyError as e:
        raise Error(
            """
            Failed to retrieve 'preferred_name' from the response.
            Available Keys {}.
            Response: {}.
            User id: {}.
            """.format(
                serialized_response.keys(),
                repr(response),
                repr(user_id)
            )
        ) from e
</code></pre><p>Now, developers and clients have much more available information stored in the context:</p><ul><li><p><code>from e</code> allows Python to "chain" exceptions and keeps stacktrace history. When such exception is logged, there is all information on the original exception. See <a href="https://docs.python.org/3/tutorial/errors.html#exception-chaining">Python Docs</a>.</p></li><li><p>Each of the handler is explicit and gives a clue that those situations might happen an developers know about them, just because they explicitly handle them.</p></li><li><p>The information, given to the function, is stored in the error message, what make understanding of the issue easier.</p></li></ul><p>The result function is a great improvement on providing context, but has a couple problems:</p><ul><li><p>Function body is longer: Seems like not a big issue, taking into account the cognitive load is about the same.</p></li><li><p>Duplicates of the information on call-site and function. In case, you own both you can always eliminate the duplicate, but when you don't know, it's better to log more than less?</p></li><li><p>The function "records" the same information multiple times.</p></li></ul><p>Some of the problems can be addressed knowing enough information about who and how uses the function. As an example:</p><pre><code>def fetch_user_name(client, user_id):
    try:
        return _fetch_user_name_internal(client, user_id)
    except Error as e:
        raise Error(
            '{} while fetching user name for user id {} and client {}.'.format(
                repr(e),
                repr(user_id),
                repr(client)
            )
        ) from e

def _fetch_user_name_internal(client, user_id):
    try:
        response = client.request(
            "/api/user/{}".format(user_id)
        )
    except http_client.Error as e:
        raise Error(
            '{} while making api call to /api/user/&lt;user_id&gt;'.format(repr(e))
        ) from e

    try:
        serialized_response = json.loads(response)
    except json.JSONDecodeError as e:
        raise Error(
            '{} while serializing response {} into JSON'.format(repr(e), response)
        ) from e

    try:
        return serialized_response['preferred_name']
    except KeyError as e:
        raise Error(
            '{} while getting "preferred_name" from response: {}'.format(
                repr(e),
                repr(response)
            )
        )
</code></pre><p>Now we have fewer duplicates of the information and the functions are smaller.</p><p>As a results of the improvements we have much more information in case of errors. User has something to act on or to share w/ the support and developers can easier find the information in the logs and even proactively fix the errors for some users.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://kuragin.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Dmitrii&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Good C++ interface doesn't spell "interface"]]></title><description><![CDATA[Naming? Really?]]></description><link>https://kuragin.dev/p/good-c-interface-doesnt-spell-interface</link><guid isPermaLink="false">https://kuragin.dev/p/good-c-interface-doesnt-spell-interface</guid><dc:creator><![CDATA[Dmitrii Kuragin]]></dc:creator><pubDate>Sat, 03 Aug 2024 16:10:16 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!7P6c!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F59b88e05-1a70-41ac-a99e-fd777050da91_353x353.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote><p>Naming is one of <a href="https://martinfowler.com/bliki/TwoHardThings.html">Two Hard Things</a>.</p></blockquote><p>How would one name an interface in C++?</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://kuragin.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Dmitrii&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>Very frequent pattern is to add a suffix to an interface name like this:</p><pre><code>class PaymentService<strong>Interface</strong> {
public:
  virtual ~PaymentService<strong>Interface</strong>() = default;

  virtual void Pay(int employee_id) = 0;
};</code></pre><p>One of the perspective on this is, the name is excessive since from declaration anybody can see that the class is an interface since it has no fields, and contains only pure virtual member function declaration. The most frequent argument for such kind of naming is the client side make the fact invisible and prefix <em>interface</em> is more readable from the client code:</p><pre><code>void example1(PaymentService<strong>Interface</strong>&amp; payment_service) { ... }

void example2(PaymentService<strong>Interface</strong>* payment_service) { ... }

void example3(std::unique_ptr&lt;PaymentService<strong>Interface</strong>&gt; payment_service) { ... }</code></pre><p>As anybody clearly can see the name reflect the fact the class is an interface and should be treated as such. But, what does it mean for us? How do we have to treat the interface? Why should it be any different from any other classes?</p><p>There is nothing special about such class, it is pure abstract class and we can't make a copy of it or move it simply because we can't declare a variable of the abstract class (a.k.a. interface).</p><p>Hold on, but the client side clearly shows: All calls to the interface are polymorphic and without suffix "interface" readers wouldn't be able to understand it and that's absolutely correct:</p><pre><code>void example4(PaymentService<strong>Interface</strong>&amp; payment_service) {
  constexpr int kKentBeckEmployeeId = 1
  payment_service.Pay(/*employee_id=*/kKentBeckEmployeeId);
}</code></pre><p>But, is it important? I think, this is a place where naming became very important. Let's consider some practical examples of names which might be a value?</p><ul><li><p>"ID" - sounds like a great wrapper for some value type with likely utility functions and invariant validations.</p></li><li><p>"string" - we all know the what the <em>string</em> is and it is clearly a value type.</p></li><li><p>"Options" - Would you expect to see a shared pointer to a polymorphic class in such place? I hope, not. But, things happen. Bad things.</p></li></ul><p>On the other hand, we can consider the following my-guts-say-it-is-abstract kind of names:</p><ul><li><p>"Service" - whether it's a network service, or client to some database, or maybe some in-process implementation of some long-running job, I am very confident, it's something abstract.</p></li><li><p>"Repository" - I don't want my class to be copied a bunch of time in such case, and I defiantly want to have some stub implementation for testing.</p></li><li><p>"Delegate" - Clearly abstract reference type.</p></li></ul><p>So, when naming can give us a good hint about how to use a specific class, wouldn't it still make sense to keep "interface" prefix? It is up to you to make this decision, but here are my 2 cents on why it shouldn't be the case.</p><ul><li><p>After sometime of using interfaces, people tend to ignore the prefix "interface" and it became more annoying clutter which only states very obvious things. Do the people use that interface suffix in their vocabulary ever? "Now, we are passing Extension Service Interface into this function.", Likely, the word "Interface" became redundant.</p></li><li><p>The client code spells the interface name more frequently, just because we design the systems around the abstraction and do not declare an abstraction to just ignore it later. Extra clutter to express obvious thing.</p></li></ul><p>Consider the following example:</p><pre><code>class PaymentService {
public:
  virtual ~PaymentService() = default;

  virtual void Pay(int employee_id) = 0;
};</code></pre><p>The interface doesn't have "interface" suffix and the name clearly states abstract behavior. Now, let's consider some client code:</p><pre><code>class PaymentScheduler {
public:
  explicit PaymentScheduler(
    std::unique_ptr&lt;PaymentService&gt; payment_service,
    std::unique_ptr&lt;EmployeeRepository&gt; employee_repository):
    payment_service_(ABSL_DIE_IF_NULL(payment_service)),
    employee_repository_(ABSL_DIE_IF_NULL(employee_repository)) {}

  void Execute() {
    // ...
  }

private:
  std::unique_ptr&lt;PaymentService&gt; payment_service_;
  std::unique_ptr&lt;EmployeeRepository&gt; employee_repository_;
}</code></pre><p>and here's another version where all of the abstractions are suffixed with word "interface":</p><pre><code>class PaymentScheduler {
public:
  explicit PaymentScheduler(
    std::unique_ptr&lt;PaymentService<strong>Interface</strong>&gt; payment_service,
    std::unique_ptr&lt;EmployeeRepository<strong>Interface</strong>&gt; employee_repository):
    payment_service_(ABSL_DIE_IF_NULL(payment_service)),
    employee_repository_(ABSL_DIE_IF_NULL(employee_repository)) {}

  void Execute() {
    // ...
  }

private:
  std::unique_ptr&lt;PaymentService<strong>Interface</strong>&gt; payment_service_;
  std::unique_ptr&lt;EmployeeRepository<strong>Interface</strong>&gt; employee_repository_;
}</code></pre><p>And when you successful application grows, the number of abstractions and layers where those abstractions have to pass through grows as well. And the only thin the suffix adds is a clutter.</p><p>What are the other properties of a good interface would you define?</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://kuragin.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Dmitrii&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Good C++ interface has default virtual destructor]]></title><description><![CDATA[It is easy to make things hard, but hard to make them easy]]></description><link>https://kuragin.dev/p/good-c-interface-has-default-virtual</link><guid isPermaLink="false">https://kuragin.dev/p/good-c-interface-has-default-virtual</guid><dc:creator><![CDATA[Dmitrii Kuragin]]></dc:creator><pubDate>Sat, 22 Jun 2024 17:08:56 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!7P6c!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F59b88e05-1a70-41ac-a99e-fd777050da91_353x353.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Good C++ interface has <em>default</em> <em>virtual</em> destructor</h2><p>As simple as this:</p><pre><code>class PaymentService {
public:
  virtual ~PaymentService() = default;

  virtual void Pay(int employee_id) = 0;
};</code></pre><p>When interface has non-<em>virtual</em> destructor, derived (sub-) classes do not have clear way to release their resources and hence should be avoided. If someone defines an interface without <em>virtual</em> destructor, it is clearly a bug.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://kuragin.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Dmitrii&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><ul><li><p><em>virtual</em> tells the user: "The class is designed for inheritance".</p></li><li><p><em>default</em> describes the intention better than default implementation, saying "We don't plant to do anything tricky here."</p></li></ul><p>Also, The derived classes still keep have their <em>move</em> and <em>copy</em> operations despite the base class (interface) has a user-declared destructor and hence doesn't have implicitly declared/defined move operations (See <a href="https://en.cppreference.com/w/cpp/language/move_constructor#Implicitly-declared_move_constructor">Implicitly-declared move constructor</a>). In order to test it, one can do the following:</p><pre><code>class PaymentService {
public:
  virtual ~PaymentService() = default;
};

class DerivedService: public PaymentService {
    public:
    std::string value = "value";
};

template &lt;typename T&gt;
void Consume(T&amp;&amp; value) {
    T unusedTmp = std::forward&lt;T&gt;(value);
}

int main() {
    auto derivedService = DerivedService();
    std::cout &lt;&lt; "Value before consume: \"" 
              &lt;&lt; derivedService.value &lt;&lt; '"' &lt;&lt; '\n';
    Consume(std::move(derivedService));
    std::cout &lt;&lt; "Value after consume: \"" 
              &lt;&lt; derivedService.value &lt;&lt; '"' &lt;&lt; '\n';

    return 0;
}</code></pre><p>The output is</p><pre><code>Value before consume: "value"
Value after consume: ""</code></pre><p>As expected, the field of <em>DerivedService</em> was moved and has the string has empty (moved-out) state.</p><h3>Alternative: Declare everything <em>final</em>.</h3><p>Keyword <em>final</em> didn't exist prior C++11 (<a href="https://en.cppreference.com/w/cpp/language/final">final specifier</a>) and there was no simple way to define a class which is not designed to be inherited from. Many C++ developers adopted a rule which says "Do not inherit from a class which doesn't have virtual destructor". And it make sense, because sub-classes don't have a reasonable way to release their resources.</p><p>In some other placer, developers adopts even stricter rule "Do not inherit from a class which is not designed to be inherited from", which is, in most cases, stated by documentation. Such rule is easy to use because most of the classes are not designed to be inherited from.</p><p>But, what about <em>final</em> (post-C++11)? Unfortunately <em>final</em> has its own problems. As an example, <em>final</em> makes the code to rigid to refactoring. If someone decides temporarily inherit from our class in order to provide a stub for the new implementation, they wouldn't be able. And they would have to fix the class to be non-<em>final</em> first. Which might break some other assumptions about the code.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://kuragin.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Dmitrii&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Good C++ interface has no fields]]></title><description><![CDATA[When parent- and child- classes have different memory-layouts (contain different data or its representation) and (somehow) assignment is involved, one might get in trouble by slicing part of data from the implementation on top of the other which leads to unexpected results.]]></description><link>https://kuragin.dev/p/good-c-interface-has-no-fields</link><guid isPermaLink="false">https://kuragin.dev/p/good-c-interface-has-no-fields</guid><dc:creator><![CDATA[Dmitrii Kuragin]]></dc:creator><pubDate>Thu, 11 Apr 2024 17:17:26 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!7P6c!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F59b88e05-1a70-41ac-a99e-fd777050da91_353x353.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When parent- and child- classes have different memory-layouts (contain different data or its representation) and (somehow) assignment is involved, one might get in trouble by <a href="https://en.wikipedia.org/wiki/Object_slicing">slicing</a> part of data from the implementation on top of the other which leads to unexpected results. But, when the a <em>class</em> doesn't have any fields, the default (compiler-generated) assignment operator/constructor doesn't do anything, since there is nothing to assign.</p><p>Here's an example of unexpected behavior.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://kuragin.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Dmitrii&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><pre><code>class PaymentService {
public:
  virtual ~PaymentService() = default;

  explicit PaymentService(
    std::string ip, int port): ip_(ip), port_(port) {}

  virtual void DoSomething() const = 0;

  std::string ip_;
  int port_;
};</code></pre><p>The <code>PaymentService</code> has 2 fields: <code>ip_</code> and <code>port</code>, hence the constructor and assignment operation of the class do actual work of copying the data from one instance to another. The same for move-semantics. Here's an example of an implementation:</p><pre><code>class RelayPaymentService: public PaymentService {
public:
  explicit RelayPaymentService(
    std::string ip, int port, std::string relay
  ): PaymentService(ip, port), relay_(relay) {}

  void DoSomething() const override {
    // some code here...
  }

  std::string relay_;
};
</code></pre><p>and second</p><pre><code>class ProxyPaymentService: public PaymentService {
public:
  explicit ProxyPaymentService(
    std::string ip, int port, std::string proxy
  ): PaymentService(ip, port), proxy_(proxy) {}

  void DoSomething() const override {
    // some code here...
  }

  std::string proxy_;
};</code></pre><p>The <em>implementation</em> has an extra-field <code>relay_</code>. Notice, all fields are public for educational purpose and shouldn't be exposed by default. Now, let's define a possible use-case where an instance might be sliced, but it is hard to notice:</p><pre><code>void assignPaymentService(PaymentService&amp; one, PaymentService&amp; two) {
    one = two;
}</code></pre><p>Simply assigning an reference of one instance to another cause here some troubles. Here's an example of code running the above-mentioned code:</p><pre><code>std::cout &lt;&lt; "Running example1...\n";

std::unique_ptr&lt;RelayPaymentService&gt; relay_payment_service =
  std::make_unique&lt;RelayPaymentService&gt;(
    "127.0.0.1",
    8080,
    "&lt;relay&gt;"
  );

std::unique_ptr&lt;ProxyPaymentService&gt; proxy_payment_service =
  std::make_unique&lt;ProxyPaymentService&gt;(
    "192.168.1.12",
    8081,
    "&lt;proxy&gt;"
  );

assignPaymentService(*relay_payment_service, *proxy_payment_service);

std::cout &lt;&lt; "ip: " &lt;&lt; relay_payment_service-&gt;ip_ &lt;&lt; ",\n"
          &lt;&lt; "port: " &lt;&lt; relay_payment_service-&gt;port_ &lt;&lt; ",\n"
          &lt;&lt; "relay: " &lt;&lt; relay_payment_service-&gt;relay_ &lt;&lt; ",\n";</code></pre><p>Now we have multiple possible outcomes:</p><ul><li><p>The code doesn't compile since we try to assign 2 different types</p></li><li><p><code>ip_</code> and <code>port_</code> are not changed since we try to assign 2 different types</p></li><li><p><code>relay_</code> value would turn to <code>proxy_</code> value which is <code>"&lt;proxy&gt;"</code>.</p></li></ul><p>None of the things, actually, happen:</p><ul><li><p>The code compiles successfully</p></li><li><p>The values of <code>ip_</code> and <code>port_</code> are updated</p></li><li><p><code>relay_</code> stays <code>"&lt;relay&gt;"</code> and <code>proxy_</code> stays <code>"&lt;proxy&gt;"</code>.</p></li></ul><p>The outcome is not expected, the types of <code>relay_payment_service</code> and <code>proxy_payment_service</code> stay the same. Where in the most reference-based languages the underlying reference would be changed. In order to prevent such partial data exchange, it is good to avoid any fields in classes which are supposed to be used as interfaces.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://kuragin.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Dmitrii&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Define a Good Interface in C++]]></title><description><![CDATA[In C++, there is no keyword interface or protocol to define something what should conform to specific set of rules.]]></description><link>https://kuragin.dev/p/define-a-good-interface-in-c</link><guid isPermaLink="false">https://kuragin.dev/p/define-a-good-interface-in-c</guid><dc:creator><![CDATA[Dmitrii Kuragin]]></dc:creator><pubDate>Tue, 09 Apr 2024 16:20:34 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!7P6c!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F59b88e05-1a70-41ac-a99e-fd777050da91_353x353.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In C++, there is no keyword <em>interface</em> or <em>protocol</em> to define something what should conform to specific set of rules. But, it doesn't mean we can't express the concept with available tools. C++ has <em>virtual</em> member-function what enables polymorphic behavior and inheritance to share common code across related types.</p><p>Here's an example how to define a good interface:</p><pre><code>struct LoginSession {
  int last_time_active;
};

class Account {
public:
  virtual ~Account() = default;

  virtual std::vector&lt;LoginSession&gt; FetchLoginSessions(
    int since) const = 0;
};</code></pre><p>The interface has the following properties:</p><ul><li><p>does NOT declare any fields</p></li><li><p>defines <em>default</em> <em>virtual</em> destructor</p></li><li><p>does NOT contain any user-defined implementations</p></li><li><p>does NOT use <em>interface</em> in its name</p></li></ul><p>Let's figure out each point one-by-one (<em>to be continued&#8230;</em>)</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://kuragin.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Dmitrii&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[How to Upgrade built-in packages in Emacs]]></title><description><![CDATA[Small note on my recent finding in Emacs.]]></description><link>https://kuragin.dev/p/how-to-upgrade-built-in-packages</link><guid isPermaLink="false">https://kuragin.dev/p/how-to-upgrade-built-in-packages</guid><dc:creator><![CDATA[Dmitrii Kuragin]]></dc:creator><pubDate>Wed, 28 Feb 2024 04:02:41 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!7P6c!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F59b88e05-1a70-41ac-a99e-fd777050da91_353x353.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Recently, I noticed a warning from <a href="https://github.com/magit/magit">Magit</a> (<a href="https://github.com/magit/magit/blob/efb6c0df175eaf35b7a83833194621bdf9cc0d71/lisp/magit-section.el#L59">code reference in magit repo</a>) saying that it requires newer version of `<a href="https://github.com/magit/transient">transient</a>`, but Emacs can't automatically upgrade it, since the build-in packages are not upgrade-able by default. It is done for safety reasons, since not all packages might be ready to upgrade their dependencies.</p><p>Remark, Emacs has build-in packages distributed within Emacs. Frequently, those package have the other version which can be installed using various packages sources. In the most of the cases, those are the same packages, but coming from different update channels (Emacs distribution vs. package repository). Once some packages became widely and frequently used, they might be integrated into Emacs distribution by Emacs maintainers. Some of the examples are <a href="https://github.com/joaotavora/eglot">Eglot</a>, <a href="https://tree-sitter.github.io/tree-sitter/">Tree-Sitter</a>, <a href="https://github.com/jwiegley/use-package">use-package</a>.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://kuragin.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Dmitrii&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>Fortunately, as Magit message suggests, there is a way to solve it. Emacs has a flag which overrides the behavior and allow to install/upgrade a package from using external sources (package repository):</p><pre><code>(setq package-install-upgrade-built-in 't)</code></pre><p>But, unfortunately, not all commands respect the flag. Documentation of <code>package-upgrade-all</code> command says:</p><blockquote><p>Currently, packages which are part of the Emacs distribution are not upgraded by this command. To enable upgrading such a package using this command, first upgrade the package to a newer version from ELPA by using &#8216;i&#8217; after &#8216;M-x list-packages&#8217;.</p></blockquote><p>But, there is a solution: One can navigate to the list of package using <code>package-list-packages</code> command, press <code>U</code>, and then <code>x</code> in order to upgrade all the package and transit them from "build-in" to "external" state. From that point, all of the packages can be updated using <code>package-upgrade-all</code>.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://kuragin.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Dmitrii&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Place of errors in a project (Cohesion, Single-Responsibility Principle)]]></title><description><![CDATA[Why are errors so special? And what's your API?]]></description><link>https://kuragin.dev/p/place-of-errors-in-a-project-cohesion</link><guid isPermaLink="false">https://kuragin.dev/p/place-of-errors-in-a-project-cohesion</guid><dc:creator><![CDATA[Dmitrii Kuragin]]></dc:creator><pubDate>Wed, 07 Feb 2024 03:02:31 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!7P6c!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F59b88e05-1a70-41ac-a99e-fd777050da91_353x353.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>And yes, SRP doesn't stand for "does one and only one thing", SRP stands for "has only 1 reason for change".</p><div><hr></div><p>I used to be a single-file-per-declaration guy&#8230; And in a case when I had a more than once class or structure per single entry of API, I tend to define multiple files for each possible declaration:</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://kuragin.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Dmitrii&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><pre><code>~/project/ImageReader/
  ImageReaderError.swift
  ImageReader.swift
  Image.swift
  ...
</code></pre><p>And I do not see too many problems with that. I just combine logic into a single folder and keep the files together. So, once I need to change the API, I change some of those files. There is a way to improve it, but it's a bit later&#8230; The other case I frequently see is structuring the project by grouping declarations by their type. For example,</p><pre><code>~/project/errors/
  ImageReaderError.swift
  CameraError.swift
  ...
~/project/
  ImageReader.swift
  Camera.swift
  ...
</code></pre><p>This is quite similar what one can see in the <s>new web framework for cool kids</s> people use where they combine controllers, errors, models separately. What's the matter with that? Low <a href="https://en.wikipedia.org/wiki/Cohesion_(computer_science)">cohesion</a>&#8230; I need to introduce a single change in some functionality the code lays in absolutely random places. Having large projects structured this way makes it hard for new people to discover the possible scenarios, and make API documentation harder.</p><p>When the code for image reading is in the same place, I can see what is going on and why, where having errors and/or models in a separate, predefined structure makes it hard to find. Of course, after a while of working on a project anybody can get used to it and stop seeing problem in that. And when new people come to project, listen! And listen hard! If they find it hard, it is hard, but you do not notice (or choose to ignore?).</p><p>Now, let's consider a better option (from my point, of course): I have the only file: <em>~project/ImageReader.swift</em> which is self-contained and has necessary documentation (I'd like to avoid it as much as I can, or minimize):</p><pre><code>struct ImageReader {
  init(from directory: String) { ... }

  struct Error: `Swift`.Error {
    var message: String
  }

  func read(filename: String) throws -&gt; Image { ... }
}
</code></pre><p>In my opinion, it is clear from the definition what kind of error the image reader can produce. Of course, it doesn't say if it can produce anything else and we probably can document it, but I would expect it to produce nothing but <em>ImageReader.Error</em> until something else is stated.</p><p>Now the logic which changes together stays in the same place. One might ask: Why you have only error message and do not have a bunch of error codes in the error definition? Well, nobody ever asked me to do so. When the API (the <em>ImageReader</em>) is project internal code and is not a part of some library, I do not expose any error which can be handled outside, until anybody needs to handle them.</p><p>Having separate code for each possible scenario is leading to the over-engineering. I know you think it should be perfect, I've been there. But it actually shouldn't. We are better to be ready for a change rather than defining perfect API which is never going to see the light. Additionally, we need to know how the API is going to be used (oh no, this is not perfect). Yes, it is not and it should not be. In the most of cases, we define an API and we (the project developers) are users of that API.</p><p>One of the possible examples might be: The image reader is used only for reading application asserts (resources) delivered inside of an application. In such a case, the error should never (theoretically) happen and we can't even test for it. But, I would still provide reasonable readable error with as much context as possible in case when it happens . Just because I do not wanna ask users to collect their logs and ask a bunch of questions in order to reproduce the error. I wanna be able to see the error message, add test, fix the bug, and provide value. I also wanna be friendly to my colleagues and provide them as much details as possible when they make a mistake, or type, or forget to add a file to the resources.</p><p>An alternative would be to have this:</p><pre><code>struct ImageReader {
  init(from directory: String) { ... }

  // See `ImageReaderError.swift` for error details.
  func read(filename: String) throws -&gt; Image { ... }
}
</code></pre><p>Now, the code is less cohesive and I need to look in a separate file to understand the possible errors (or read the code of course). Modern IDEs can make it relatively easy task, but would it be more readable? Would it be easier to spot a type, mistake, some inconsistency when the errors are defined in a separate file? Would it make code-review easier/faster? Of course, I can always split the screen and open errors in a separate file and make my life somehow better. And in some cases, that what I have to do.</p><p>The errors are the part of the API and should be documented as well. Having errors makes it easier to review, refactor the code, spot mistakes and simply to self-document the code. Someone might see value in having all errors in a single place, but somehow such cases happen very rarely&#8230;</p><p>Extra note: When the class grows and you'd like to break it down into multiple files, but support the same API you always have multiple options:</p><ul><li><p>Keep everything as it is and let the module grow</p></li><li><p>Break it down into multiple sub-classes (maybe even private): with their own errors</p></li><li><p>Break down only implementation, but keep external API the same and re-use the same error</p></li></ul><p>The last one would require you to extract error into a separate file and make your internal implementations depend on it:</p><pre><code>~/project/ImageReader/...
  Error.swift
  ImageReader.swift
  InternalPNGReader.swift
  InternalJPEGReader.swift
  InternalOpenFile.swift
</code></pre><p>Each of <strong>Internal</strong> depends on the <em>Error.swift</em> and <em>ImageReader.swift</em> depends eon each of Internal*. This is of course a trade of and there is more than one way to solve that. And you're the one who knows the most!</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://kuragin.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Dmitrii&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item></channel></rss>