<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Written by Rahul]]></title><description><![CDATA[Written by Rahul]]></description><link>https://blogs.rahultgeorge.com</link><generator>RSS for Node</generator><lastBuildDate>Thu, 16 Apr 2026 01:41:51 GMT</lastBuildDate><atom:link href="https://blogs.rahultgeorge.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[W1203: logging-fstring-interpolation (Solved)]]></title><description><![CDATA[A few days back, I was implementing a feature, and when I was done and happy with my work, I decided to commit the code. We have enabled pre-commit hooks in our repository to maintain some coding formats and reduce the burden on the folks reviewing t...]]></description><link>https://blogs.rahultgeorge.com/w1203-logging-fstring-interpolation-solved</link><guid isPermaLink="true">https://blogs.rahultgeorge.com/w1203-logging-fstring-interpolation-solved</guid><category><![CDATA[logging-not-lazy]]></category><category><![CDATA[logging-format-interpolation]]></category><category><![CDATA[logging-fstring-interpolation]]></category><category><![CDATA[W1203]]></category><category><![CDATA[W1201]]></category><category><![CDATA[W1202]]></category><category><![CDATA[Python]]></category><category><![CDATA[Python 3]]></category><category><![CDATA[string]]></category><category><![CDATA[string interpolation]]></category><category><![CDATA[logging]]></category><dc:creator><![CDATA[Rahul George]]></dc:creator><pubDate>Tue, 16 Jan 2024 14:50:53 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1705416293041/12f5b415-5efe-4856-b23f-46526685630b.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A few days back, I was implementing a feature, and when I was done and happy with my work, I decided to commit the code. We have enabled pre-commit hooks in our repository to maintain some coding formats and reduce the burden on the folks reviewing the code. One of the code checkers that run as part of the pre-commit check is Pylint. Pylint gave me the warning '<strong>logging-fstring-interpolation (W1203)'</strong> and the pre-commit check kept failing. Even though I knew what needed to be done to fix the warning, being me, I could not just leave it be. I wanted to know the why part of it.</p>
<p>Other Pylint warnings related to the logging module are:</p>
<ul>
<li><p>logging-not-lazy / W1201</p>
</li>
<li><p>logging-format-interpolation / W1202</p>
</li>
</ul>
<h3 id="heading-pylint">Pylint</h3>
<p>A little introduction about <a target="_blank" href="https://pylint.readthedocs.io/en/latest/">pylint</a>. Pylint is a static code analyzer, it analyses your code without actually running it. Pylint looks for potential errors, gives suggestions on coding standards that your code is not adhering to, potential places where refactoring might help, and also warnings about smelly code.</p>
<p>Sometimes there are false positives, but you can inspect and decide for yourself whether it flagged the line incorrectly or not. If you identify it as a false positive, you can disable the pylint check for that particular line.</p>
<p>Overall, I think it takes out a lot of pain from the reviewer to point out code smells and enforce coding standards. I would say this module has saved hours of review time.</p>
<h3 id="heading-logging-fstring-interpolation-warning">logging-fstring-interpolation warning</h3>
<p>Python has multiple ways of string interpolation. I have explained the details of it in a previous blog - <a target="_blank" href="https://blogs.rahultgeorge.com/string-interpolation-in-python">String Interpolation in Python</a></p>
<p>Even though we are using the latest string interpolation mechanism in python, the Pylint checker is giving us a warning that there is something wrong. The official documentation for this warning says:</p>
<blockquote>
<p><em>Use another type of string formatting instead. You can use % formatting but leave interpolation to the logging function by passing the parameters as arguments.</em></p>
</blockquote>
<p>To understand what was happening behind the hood, I wrote this code.</p>
<p>Here, I have an Employee class with an <code>__str__</code> magic method. The logging module is configured to log into the console and the logging level is set to DEBUG. The statements of interest are all debug statements, and I also added some headings to understand what section we are executing now.</p>
<p>Running this code with the logging level set to DEBUG. I expect to see the str method called for all the cases because the log level is DEBUG is the lowest and all the log messages will be printed.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1705398105716/de9c9cb6-ce03-4015-b485-010720180320.png" alt class="image--center mx-auto" /></p>
<p>The response is as expected. The string evaluation of the object takes place and then the log statement is evaluated.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1705398129541/02510270-3152-4277-b4a2-eed78afa876d.png" alt class="image--center mx-auto" /></p>
<p>What if the log level is set to INFO, but the log statements are at the DEBUG level?<br />I expect the string evaluation to be deferred until the logger determines whether this log statement is above the log level set, i.e., all the statements with log level as INFO and higher will be printed whereas all the statements with log level as DEBUG will be ignored. If the log statements with DEBUG are ignored, then there is no need to call the str method of the objects.</p>
<p>Making only 1 change on line #5, I executed the code.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1705398082601/6b6ef088-7b55-4860-884e-272378dd9ad0.png" alt class="image--center mx-auto" /></p>
<p>The response was not something I was expecting.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1705398150750/7853d767-bdab-403e-a055-9dcef8f4ef0c.png" alt class="image--center mx-auto" /></p>
<p>Upon inspection, it was clear the evaluation of the message objects was happening irrespective of whether the statement was executed or discarded.</p>
<p>So irrespective of what type of string interpolation I use, the order of events is as follows:</p>
<ol>
<li><p>evaluate all the arguments to the log.debug() - this calls the str method,</p>
</li>
<li><p>Call the log.debug(),</p>
</li>
<li><p>Determine whether to log it or discard it.</p>
</li>
</ol>
<p>This seemed very counterintuitive because then the logging statement when turned off will still consume time and memory. I decided to peek into the logging library. Looking at the function signature it was clear, there is nothing wrong with the library. But I am not using the library in the intended way.</p>
<p>The intended way to use the logger function is to pass the string template as the first argument and the arguments to be substituted as *args. This way, the string interpolation happens within the logger library and not when I call the logger method.</p>
<blockquote>
<p>The correct way to invoke the logging statement where the string interpolation is deferred until it is necessary.</p>
</blockquote>
<p>Added two more lines of code and repeated the experiment. In this case, I am passing the %-formatted string template separately and the argument to substitute it with separately.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1705399497972/e7103fd4-06eb-4255-9135-bf9654716988.png" alt class="image--center mx-auto" /></p>
<p>Running this code again, the result is as expected, the string evaluation is not happening because the log level is set to INFO.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1705399538850/78c59aeb-d086-4e7e-a27a-670da33121ed.png" alt class="image--center mx-auto" /></p>
<p>After changing the log level to debug on line #5, the log statement is getting printed as expected.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1705399635808/80fd6643-f1f2-450b-83d3-ee74c778a756.png" alt class="image--center mx-auto" /></p>
<p>So, the order of events will be:</p>
<ol>
<li><p>Call the log.debug(),</p>
</li>
<li><p>Determine whether to log it or discard it.</p>
</li>
<li><p>Discards the log because the log level is below the level set.</p>
</li>
<li><p>Evaluate the message object by substituting the arguments.</p>
</li>
</ol>
<p>Now that the internal workings and the correct usage is clear, let us understand the impact of this small change on our program.</p>
<h3 id="heading-impact">Impact</h3>
<p>You might think this string interpolation is harmless, but if the logging statement is in a function that is called frequently and the logging level is set to be discarded during normal operation, you are wasting away a lot of execution cycles. To understand the impact, I looped the logging statements 100,000 times, collected the run time, and tabulated it.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1705403099446/8987542d-797b-4339-a65c-42955fffafd7.png" alt class="image--center mx-auto" /></p>
<p>The x-axis defines different approaches and the y-axis gives the time in milliseconds for each approach.</p>
<p>When we are logging and the log message evaluation is expensive, using the approach of deferred evaluation can save a lot of time. When you want to turn off the debug logs and run in optimized mode. Otherwise, all the approaches are yielding similar run time.</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>Hope this blog helps someone who is scratching their head trying to figure out why the Pylint-type checker is giving this weird warning. Pylint is trying to tell you to check your syntax because you could be committing a mistake by not using deferred evaluation. This warning message is generated when you are trying to use f-string substitution in the logging statement.</p>
<p>Instead of simply disabling the warning, now you know the reason behind it and how to handle it the correct way. </p>
<p>Share with me your thoughts on this in the comments! Or leave a like if you learned something new. </p>
]]></content:encoded></item><item><title><![CDATA[String Interpolation in Python]]></title><description><![CDATA[String interpolation in computer programming is the process of creating string literals from string templates that contain one or more placeholders, by replacing the placeholders with their corresponding values.
Python has three ways of string interp...]]></description><link>https://blogs.rahultgeorge.com/string-interpolation-in-python</link><guid isPermaLink="true">https://blogs.rahultgeorge.com/string-interpolation-in-python</guid><category><![CDATA[Technical Blogs]]></category><category><![CDATA[data structures]]></category><category><![CDATA[algorithms]]></category><category><![CDATA[Python]]></category><category><![CDATA[python beginner]]></category><category><![CDATA[Python 3]]></category><category><![CDATA[Tutorial]]></category><category><![CDATA[string interpolation]]></category><category><![CDATA[string formatting]]></category><category><![CDATA[interview preparation]]></category><dc:creator><![CDATA[Rahul George]]></dc:creator><pubDate>Mon, 15 Jan 2024 13:30:29 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1705308806281/218b7eb7-2d74-4b3c-b30e-6a9b972fd591.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>String interpolation in computer programming is the process of creating string literals from string templates that contain one or more placeholders, by replacing the placeholders with their corresponding values.</p>
<p>Python has three ways of string interpolation. I am going to explain each of these with one or two examples.</p>
<h3 id="heading-f-strings">f-strings</h3>
<p>One of the latest and most developer-friendly approaches is to use the f-strings. F-strings are a concise and efficient way to embed expressions inside string literals.</p>
<pre><code class="lang-python">name = <span class="hljs-string">'John'</span>
age = <span class="hljs-number">25</span>
print(<span class="hljs-string">f'My name is <span class="hljs-subst">{name}</span> and I am <span class="hljs-subst">{age}</span> years old.'</span>)
</code></pre>
<p>Let's look at a more complicated example. Having a list comprehension inside of the string interpolation.</p>
<pre><code class="lang-python">vowels = (<span class="hljs-string">'a'</span>, <span class="hljs-string">'e'</span>, <span class="hljs-string">'i'</span>, <span class="hljs-string">'o'</span>, <span class="hljs-string">'u'</span>)
print(<span class="hljs-string">f"These are vowels in English: <span class="hljs-subst">{<span class="hljs-string">', '</span>.join(vowels)}</span>"</span>)
</code></pre>
<p>One thing to note in the above example is, if you have single quotes in the f-string, the outer quotes cannot be single quotes.</p>
<h3 id="heading-strformat">str.format()</h3>
<p>The format method of the string class is another way to perform string interpolation. It works by putting one or more placeholders in the string and the values to substitute these placeholders with should be passed as arguments to the format method.</p>
<pre><code class="lang-python">name = <span class="hljs-string">'John'</span>
age = <span class="hljs-number">25</span>
print(<span class="hljs-string">'My name is {} and I am {} years old.'</span>.format(name, age))
</code></pre>
<p>One alternative syntax to use the str.format() is to have named placeholders like in the example below and pass keyworded arguments to replace the placeholders. In the below example, I have to replace the name in two places, but I can get away by passing it only once to the string.</p>
<pre><code class="lang-python">name = <span class="hljs-string">'John'</span>
age = <span class="hljs-number">25</span>
print(<span class="hljs-string">'My name is {name} and I am {age} years old. \
    My grandfather was also named {name}'</span>.format(name=name, age=age))
</code></pre>
<p>I can also store the string with the placeholders as a template somewhere and perform string substitution on demand.</p>
<h3 id="heading-formatting"><strong>%-formatting</strong></h3>
<p>The last mechanism of formatting a Python string is to use the % operator. This syntax feels similar to the printf style in C. Here, the character after the % tells the compiler what the intended value is to be substituted in its place. Check out the example below.</p>
<pre><code class="lang-python">name = <span class="hljs-string">'John'</span>
age = <span class="hljs-number">25</span>
print(<span class="hljs-string">'My name is %s and I am %d years old.'</span> % (name, age))
</code></pre>
<p>Use the below table as a guide for some of the common % symbols. The full list of symbols is available <a target="_blank" href="https://docs.python.org/3.3/library/stdtypes.html#printf-style-string-formatting">here</a>.</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>%-sign</td><td>Meaning</td></tr>
</thead>
<tbody>
<tr>
<td>%s</td><td>Placeholder for string</td></tr>
<tr>
<td>%d</td><td>Placeholder for signed integer decimal</td></tr>
<tr>
<td>%f</td><td>Placeholder for floating point decimal</td></tr>
<tr>
<td>%r</td><td>Replace with raw data of a variable.</td></tr>
<tr>
<td>%x</td><td>Replace with hexadecimal value.</td></tr>
<tr>
<td>%o</td><td>Replace with octal value.</td></tr>
<tr>
<td>%c</td><td>Replace with special characters.</td></tr>
</tbody>
</table>
</div><h3 id="heading-conclusion">Conclusion</h3>
<p>There are also Template strings in Python. I did not cover it in this list of interpolation techniques because it is a vast topic of its own.</p>
<p>Out of the three techniques I like to use f-strings the most followed by %-formatting style when I am using logging statements. The str.format() style is preferred when I have to store the string to interpolate separately and inject the values to the placeholders as keyworded arguments. I use these three techniques during coding depending on the scenario.</p>
<p>I would love to hear if I have missed any other techniques or if you guys have any preferences.</p>
]]></content:encoded></item><item><title><![CDATA[Nominative Case Explained]]></title><description><![CDATA[What is the Nominativ case?
In German grammar, the nominative case is the basic form of the noun. The subject in a given sentence is always in the nominative case.
How do you find a subject?
Let us look at a simple sentence for this.
Deu: Er schläft
...]]></description><link>https://blogs.rahultgeorge.com/nominative-case-explained</link><guid isPermaLink="true">https://blogs.rahultgeorge.com/nominative-case-explained</guid><category><![CDATA[German Language Classes]]></category><category><![CDATA[german]]></category><category><![CDATA[grammar]]></category><category><![CDATA[nominative]]></category><dc:creator><![CDATA[Rahul George]]></dc:creator><pubDate>Thu, 05 Oct 2023 19:16:02 GMT</pubDate><content:encoded><![CDATA[<h3 id="heading-what-is-the-nominativ-case">What is the Nominativ case?</h3>
<p>In German grammar, the nominative case is the basic form of the noun. The subject in a given sentence is always in the nominative case.</p>
<h3 id="heading-how-do-you-find-a-subject">How do you find a subject?</h3>
<p>Let us look at a simple sentence for this.</p>
<pre><code class="lang-plaintext">Deu: Er schläft
Eng: He sleeps
</code></pre>
<p>In this sentence, the action is sleep. To find the subject in the sentence, you need to ask the question, "<mark>Who</mark> is doing the action?". We get the solution as "Er". So, Er is the subject of this sentence.</p>
<p>If I take another example,</p>
<pre><code class="lang-plaintext">Deu: Das Auto ist schön
Eng: The car is beautiful
</code></pre>
<p>In the above sentence, it makes no sense to ask the question "Who" here. We should ask, "What is beautiful?" in this context. We get the subject as "Das Auto".</p>
<h3 id="heading-structure-of-a-simple-sentence">Structure of a Simple Sentence</h3>
<p>The structure of a simple sentence is:<br /><code>&lt;Subject&gt; + &lt;Conjugated form of the Verb&gt;</code></p>
<p>The subject will be in the nominative form of the noun.</p>
<p>Another point to note here is that the <mark>verb conjugation is based on the subject</mark> in the sentence.</p>
<p>The subject in a sentence can be the name of a person, a thing, or a personal pronoun.</p>
<h3 id="heading-personal-pronouns-in-nominativ-case">Personal pronouns in nominativ case</h3>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Deutsche</td><td>English</td></tr>
</thead>
<tbody>
<tr>
<td>Ich</td><td>I</td></tr>
<tr>
<td>Du</td><td>You</td></tr>
<tr>
<td>Er/Sie/Es</td><td>He/She/It</td></tr>
<tr>
<td>Ihr</td><td>Your(s)</td></tr>
<tr>
<td>Wir</td><td>We</td></tr>
<tr>
<td>Sie/sie</td><td>Indicate plural or in a formal context</td></tr>
</tbody>
</table>
</div><h3 id="heading-conclusion">Conclusion</h3>
<p>We understood what a nominative case is, and how to find the subject in a sentence. To find a subject, we need to ask "Who is doing the action/What is?"</p>
]]></content:encoded></item><item><title><![CDATA[Unlocking Success: The Role of a Product Manager]]></title><description><![CDATA[I see a lot of things change around me especially in the tech space, the way people work, and also in the start-up space. I am also at a point in my career trying to figure out in what direction I should steer myself - continue in tech, venture into ...]]></description><link>https://blogs.rahultgeorge.com/unlocking-success-the-role-of-a-product-manager</link><guid isPermaLink="true">https://blogs.rahultgeorge.com/unlocking-success-the-role-of-a-product-manager</guid><category><![CDATA[productmanagement]]></category><category><![CDATA[influence]]></category><category><![CDATA[product]]></category><category><![CDATA[business]]></category><category><![CDATA[technology]]></category><dc:creator><![CDATA[Rahul George]]></dc:creator><pubDate>Sun, 24 Sep 2023 09:07:35 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/rxpThOwuVgE/upload/e75b912634c866f49bb8717c5dd72ad9.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I see a lot of things change around me especially in the tech space, the way people work, and also in the start-up space. I am also at a point in my career trying to figure out in what direction I should steer myself - continue in tech, venture into management roles, or try my hands at being an entrepreneur.</p>
<p>During my research, I stumbled upon the job description "<strong>Product Manager</strong>". I am collating all my learnings here hoping it might help someone.</p>
<h2 id="heading-what-is-a-product-manager">What is a product manager?</h2>
<p>In a broad sense, you can consider the product manager as the <strong>CEO of the product</strong>. This term was coined by Ben Horowitz, CEO of Opsware. A product manager is responsible for setting up the <strong>vision</strong> of how the product should be and what the product will not be. A product manager prepares <strong>strategies</strong> that strike a balance between the budget, time to market, and resources available. They also have to motivate the execution team and are responsible for the outcome of the development lifecycle.</p>
<p>Does that mean product managers have special authority? They don't.</p>
<h2 id="heading-responsibilities-of-a-product-manager">Responsibilities of a Product Manager</h2>
<p>Specific responsibilities vary between organizations, but if I had to summarize my research:</p>
<ul>
<li><p>Identify the customer needs and the larger business objectives a product will fulfill through <strong>market research</strong> and <strong>competitor analysis</strong>,</p>
</li>
<li><p>Define the success metrics for the particular product, and,</p>
</li>
<li><p>Rally a team to turn that vision into reality.</p>
</li>
</ul>
<p>In a smaller organization, you may have to do more work from defining the vision and seeing it through the execution. But in larger organizations, they may have more sub-teams and tools to make your life easier but aligning everyone to a single vision might take a lot of effort.</p>
<h2 id="heading-skillsets">Skillsets</h2>
<p>The product manager lies at the intersection of business goals, the tech, and the user experience as you can see from the Venn diagram.</p>
<p><a target="_blank" href="https://unsplash.com/photos/ORWyuz99AUE"><img src="https://images.unsplash.com/photo-1695464480839-62b46cde7070?ixlib=rb-4.0.3&amp;ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&amp;auto=format&amp;fit=crop&amp;w=1932&amp;q=80" alt class="image--center mx-auto" /></a></p>
<p>Even though there are dedicated teams for UX, Tech, and business, he should know the terms and the lay of the land to communicate effectively with these teams. For example, knowing Figma can make brainstorming with the UX designers more productive.</p>
<p>If you already have the skillsets or are willing to cultivate these, then you can be a good product manager:</p>
<ol>
<li><p>Good at prioritizing,</p>
</li>
<li><p>Learn to influence people without authority,</p>
</li>
<li><p>Decision-making on the go,</p>
</li>
<li><p>Know the team you're working with.</p>
</li>
</ol>
<p>All these and a knowledge of a lot of tools to help organize your work - JIRA, Confluence, Trello, Teams, Figma, etc.</p>
<h2 id="heading-salary-scales-for-product-managers">Salary Scales for Product Managers</h2>
<p>All the glam and glory that the product manager role brings apart, what does it pay at the end of the day? Based on my research, the average salary for a product manager in India is about 20 LPA and going up to 35 LPA (at the time of writing this blog). <a target="_blank" href="https://www.ambitionbox.com/profile/product-manager-salary">Check here</a>. Largely varying based on your experience and the type of organization.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Doesn't matter whether you are from a service industry, a product company, or starting your own business, a product manager or knowledge of product management is a game changer for the organization. That one person who can envision and rally a team behind that vision will determine whether your product is <strong>the go-to product</strong> or will be just another product in the market.</p>
]]></content:encoded></item><item><title><![CDATA[Migrate MongoDB Data Seamlessly with mongo-migrate and Python!]]></title><description><![CDATA[The first time I used MongoDB was when we were building an internal ERP system. The use case for MongoDB was not to store any data but to store some schema and workflow data. This data stayed more or less the same once the application is deployed. Wh...]]></description><link>https://blogs.rahultgeorge.com/migrate-mongodb-data-seamlessly-with-mongo-migrate-and-python</link><guid isPermaLink="true">https://blogs.rahultgeorge.com/migrate-mongodb-data-seamlessly-with-mongo-migrate-and-python</guid><category><![CDATA[MongoDB]]></category><category><![CDATA[migration]]></category><category><![CDATA[Databases]]></category><category><![CDATA[Python 3]]></category><category><![CDATA[schema]]></category><dc:creator><![CDATA[Rahul George]]></dc:creator><pubDate>Tue, 22 Aug 2023 18:42:03 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1692727126873/cc19b2ce-7e6e-45d0-be31-fb62e1a4a6fd.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The first time I used <a target="_blank" href="https://www.mongodb.com/">MongoDB</a> was when we were building an internal ERP system. The use case for MongoDB was not to store any data but to store some schema and workflow data. This data stayed more or less the same once the application is deployed. While this project gave me a peek into the MongoDB ecosystem, the actual learning about its capabilities came in the next project where we used MongoDB to store the data for a configuration management system.</p>
<p>After the excitement of using a new system died out, we identified there are issues. I want to talk about one such issue we faced and discuss a solution.</p>
<h2 id="heading-the-problem-statement">The Problem Statement</h2>
<p>We were facing two main issues during the development phase.</p>
<ol>
<li><p>Managing the database schema:</p>
<p> We were unable to test out feature branches independently when the feature being implemented contained database schema changes. When such changes came up, we had to serialize the implementation so that other teams are unaffected by this change.</p>
</li>
<li><p>Migrating the database into production:</p>
<p> When we rolled out the changes into production, it was a cumbersome process. Creating a lot of custom scripts to migrate the user database which was part of version A to the target version. These became largely invalid and not maintained, adding to the technical debt.</p>
</li>
</ol>
<p>The solution that I am going to discuss will solve the below problems:</p>
<ol>
<li><p>Bring up the database to the same schema as it was during the development of that version (or commit).</p>
</li>
<li><p>Both upgrades and downgrades can be performed gracefully by the developer, making the process uniform.</p>
</li>
<li><p>Contains incremental changes and not the whole schema.</p>
</li>
<li><p>Versioning schema changes along with the code.</p>
</li>
</ol>
<h2 id="heading-how-do-you-migrate-mongodb">How do you migrate MongoDB?</h2>
<p>I knew Django had a feature where it generated the migration files using declarative commands and I searched if MongoDB library <a target="_blank" href="https://pymongo.readthedocs.io/en/stable/index.html">Pymongo</a> provided any such feature built-in, but it did not. I checked if other libraries that provided the migrations existed. There were a few, but when I inspected the code, most of them did provide a declarative interface like Django. Thus I decided to write my own. Also, I wanted to develop something open-source (MIT licensed) for a long time and this tool felt like the right one.</p>
<h2 id="heading-mongo-migrate">Mongo-Migrate</h2>
<p>Over the weekend, I created mongo-migrate, a <a target="_blank" href="https://www.python.org/">Python</a> library capable of giving the developer the power to quickly create migrations, and upgrade or downgrade schema based on these incremental migration files. For most of the scenarios, you can use the command line tool <strong><em>mongo-migrate</em></strong> after you pip install, but for advanced use cases, you can import the <strong><em>MigrationManager</em></strong> class and the already created migrations.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/blitzcode-io/mongo-migrate">https://github.com/blitzcode-io/mongo-migrate</a></div>
<p> </p>
<p><a target="_blank" href="https://pypi.org/project/mongo-migrate/">mongo-migrate</a> gives you three commands - create, upgrade, and downgrade. If you are eager to try it out without going through the commands, go ahead and run this command on the command line to install the package.</p>
<pre><code class="lang-bash">pip install mongo-migrate
</code></pre>
<h3 id="heading-the-create-command">The <em>Create</em> Command</h3>
<p>It accepts a migration folder path and creates empty migration files in this folder.</p>
<pre><code class="lang-plaintext">usage: mongo-migrate create [-h] [--host HOST] [--port PORT] 
            [--database DATABASE] [--migrations MIGRATIONS] 
            [--title TITLE] --message MESSAGE

optional arguments:
  -h, --help            show this help message and exit
  --host HOST           the database host
  --port PORT           the database port
  --database DATABASE   provide the database name
  --migrations MIGRATIONS
                        provide the folder to store migrations. 
                        By default creates migrations/
  --title TITLE         title will be used in the file name
  --message MESSAGE     message will be recorded as a comment 
                        inside the migration file
</code></pre>
<p>The template migration file (sample below) has three public methods:</p>
<ol>
<li><p><strong>upgrade():</strong> Add code to upgrade the database from the current version to the target version should go here. For example, adding a collection or adding a field.</p>
</li>
<li><p><strong>downgrade():</strong> Add code relevant for downgrading the database from the current version to the target version should go here. For example, removing a collection or removing a field.</p>
</li>
<li><p><strong>comment():</strong> Adds a user-given message as a comment. Currently stored for documentation purposes.</p>
</li>
</ol>
<p>You should add your code to perform the schema migration. (See sample below)</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1692708688022/364628ef-cab0-4daa-8c9f-516c91294e22.jpeg" alt class="image--center mx-auto" /></p>
<h3 id="heading-the-upgrade-command">The <em>Upgrade</em> Command</h3>
<p>The Upgrade command accepts a migration folder path and target version to go to. It systematically performs the upgrade of the database from the current version.</p>
<pre><code class="lang-plaintext">usage: mongo-migrate upgrade [-h] [--host HOST] [--port PORT] 
                [--database DATABASE] [--migrations MIGRATIONS] 
                [--upto UPTO]

optional arguments:
  -h, --help            show this help message and exit
  --host HOST           the database host
  --port PORT           the database port
  --database DATABASE   provide the database name
  --migrations MIGRATIONS
                        provide the folder where the migrations are stored 
                        By default looks for migrations/
  --upto UPTO           target migration timestamp
</code></pre>
<h3 id="heading-the-downgrade-command">The <em>Downgrade</em> Command</h3>
<p>The Downgrade command accepts a migration folder path and target version to go to. It systematically performs the rollback of the database from the current version until reaches the target version.</p>
<pre><code class="lang-plaintext">usage: mongo-migrate downgrade [-h] [--host HOST] [--port PORT] 
                [--database DATABASE] [--migrations MIGRATIONS] 
                [--upto UPTO]

optional arguments:
  -h, --help            show this help message and exit
  --host HOST           the database host
  --port PORT           the database port
  --database DATABASE   provide the database name
  --migrations MIGRATIONS
                        provide the folder where the migrations are stored. 
                        By default looks for migrations/
  --upto UPTO           target migration timestamp
</code></pre>
<h2 id="heading-how-do-i-use-mongo-migrate-in-a-project">How do I use mongo-migrate in a project?</h2>
<p>Let me walk you through the steps quickly without making it sound complicated.</p>
<p><strong>Step 1:</strong> Set up your virtual environment and install mongo-migrate.</p>
<p><strong>Step 2:</strong> Use the mongo-migrate create command to create the first migration file template. You should provide the MongoDB host, port, and database.</p>
<p><strong>Step 3</strong>: Modify the migration file created and add the code necessary to upgrade the database. Add this code to the upgrade() method.</p>
<p><strong>Step 4</strong>: Also, add the steps to revert the above change in the downgrade() method.</p>
<p><strong>Step 5:</strong> Run the mongo-migrate upgrade command to implement these changes onto the database.</p>
<p><strong>Step 6:</strong> In case you need to revert the changes, run the mongo-migrate downgrade command.</p>
<h2 id="heading-package-dependencies">Package Dependencies</h2>
<p>This library was written with minimal dependency to keep it clean. The only library it uses additionally is the Pymongo library.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Remember, MongoDB schema migrations don't have to be complex. With mongo-migrate, managing schema changes, version control, and performing migrations is a breeze. Explore our tool, suggest ideas to improve this tool further, and simplify schema migrations!</p>
]]></content:encoded></item><item><title><![CDATA[Are you heading to technical debt bankruptcy?]]></title><description><![CDATA[In my last blog, I shared what technical debt is and also discussed when to avoid it and when you can leverage it.

Technical Debt is the by-product of a dysfunctional software development process.

In this article, I will try to summarise the red fl...]]></description><link>https://blogs.rahultgeorge.com/are-you-heading-to-technical-debt-bankruptcy</link><guid isPermaLink="true">https://blogs.rahultgeorge.com/are-you-heading-to-technical-debt-bankruptcy</guid><category><![CDATA[refactoring]]></category><category><![CDATA[technical-debt]]></category><category><![CDATA[Bankruptcy ]]></category><category><![CDATA[project management]]></category><category><![CDATA[software development]]></category><dc:creator><![CDATA[Rahul George]]></dc:creator><pubDate>Thu, 03 Aug 2023 07:33:50 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/9j8k3l9afkc/upload/5a6d765eeaaf31f1c07af0d607bb5829.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In my last blog, I shared what technical debt is and also discussed when to avoid it and when you can leverage it.</p>
<blockquote>
<p>Technical Debt is the by-product of a dysfunctional software development process.</p>
</blockquote>
<p>In this article, I will try to summarise the red flags to look out for to identify if you are accumulating technical debt. For folks, who have not read the previous blog on technical debt, check it out <a target="_blank" href="https://rahulgeorge.hashnode.dev/can-you-really-eliminate-technical-debt">here</a>.</p>
<h3 id="heading-red-flags">Red Flags</h3>
<ul>
<li><p><strong>Requirements or the scope of work are still not clearly defined.</strong><br />  Your project owner introduced you to a new project and after the initial discussion asks you to design the software architecture, but the scope of the work is not clearly defined. This lack of clarity is going to create a sub-optimal design and it is accruing technical debt. This process is acceptable to get a jump start on a project or to create a proof-of-concept, but sooner or later you will need to refactor the code.</p>
</li>
<li><p><strong>Tightly coupled components</strong> - <strong>too many dependencies between functions, and functions are not modular.</strong></p>
<p>  Your software architecture is too dense and it is difficult to isolate the responsibilities of different modules and functions. Whenever you are asked to implement a new feature, you end up modifying a whole lot of code because of this dependency. This is a clear indication that your codebase is due for refactoring.</p>
</li>
<li><p><strong>Lack of testing or test suites</strong> - <strong>Manual testing can be time-consuming and can be prone to human errors.</strong><br />  When you are part of an organization (or startup) that does not have a dedicated testing team, it often falls on the team lead (or delivery head) to ensure quality software is being shipped to the end user. When the user base of the tool is within the organization, this is still manageable, but it is still a burden on the team lead to guarantee all the critical paths in the software work, and that no new software bugs are introduced. If your team doesn't believe in writing testable code or incorporating automation testing, the entire project is like a house of cards and you are headed for sleepless nights.<br />  It is a good point to stop and negotiate and/or educate the team on making the code testable and incorporating testing strategies into your development.</p>
</li>
<li><p><strong>Lack of software documentation - Nobody knows why certain things are done the way they are.</strong><br />  Documentation is important, enough said. You should spend effort and time maintaining documents on software architectures, software processes, and software requirements. Requirements evolve and people working on the project change over time too. Sometimes the software processes like deployment guides, migration guides, and version control guides also must be documented to ensure the team is aware of the best practices. I would quote from the <a target="_blank" href="https://peps.python.org/pep-0020/#the-zen-of-python">Zen of Python</a>: <em><mark>Explicit is better than implicit.</mark></em> Ensure best practices are taught to the team and you don't expect them to just know without training.</p>
</li>
<li><p><strong>Lack of collaboration - knowledge is not shared around the organization and the juniors are not properly mentored.</strong><br />  Amidst all the project meetings, standups, and retrospectives, we often forget to have a conversation about what interesting things you read on <a target="_blank" href="https://hashnode.com">Hashnode</a> or other platforms. Have open discussions with the team. When you are brainstorming strategies and requirements, encourage the team to talk. This will instill a sense of belonging and ownership in the team.</p>
</li>
<li><p><strong>Last-minute specification changes</strong><br />  This is a pet peeve of mine. When you do not document the requirements and fail to get a sign-off, you are probably going to end up implementing something different than the person at the receiving end wanted. And sometimes, your product owner wants to wiggle in some last-minute changes. Just be aware of the technical debt accrual and remember to weed them out in a later sprint cycle.</p>
</li>
<li><p><strong>Poor technological leadership - when the leadership team creates frameworks that are not comprehensive or thought through.</strong><br />  The software architect might have created an internal framework for the project based on the initial requirements, but if your software team is not flexible enough to refactor the framework as requirements evolve and change. You are carrying the baggage and creating workarounds.</p>
<p>  Another red flag to look for is when you are trying to bring improvements to the framework but the leadership constantly dismisses you. If they are not open to communication and collaboration, then it is a major red flag.</p>
</li>
<li><p><strong>Lack of knowledge - The developers don't know how to write elegant code.</strong><br />  Elegant code, this is a subjective and touchy subject. I am not just telling about the variable naming conventions, folder structures, and Pythonic or Javascript way of doing it. If your software team is not experienced enough in that particular technology, or if they are creating tightly coupled systems. You are heading towards a scenario where you will need to refactor the code sooner or later.</p>
</li>
</ul>
<p>Technical debt is a hidden cost that robs your business of its ability to be nimble and make needed changes for your customers. Look out for the above red flags and take action if you see your project is headed that way.</p>
]]></content:encoded></item><item><title><![CDATA[Can you really eliminate technical debt?]]></title><description><![CDATA[Let me start with some scenarios to illustrate the concept of technical debt before providing a formal definition and discussing how to eliminate it.
Scenario #1
You are part of a startup trying to ship the latest updates to the customers and your pr...]]></description><link>https://blogs.rahultgeorge.com/can-you-really-eliminate-technical-debt</link><guid isPermaLink="true">https://blogs.rahultgeorge.com/can-you-really-eliminate-technical-debt</guid><category><![CDATA[Design]]></category><category><![CDATA[documentation]]></category><category><![CDATA[Technical writing ]]></category><category><![CDATA[project management]]></category><category><![CDATA[technical-debt]]></category><dc:creator><![CDATA[Rahul George]]></dc:creator><pubDate>Mon, 31 Jul 2023 17:05:37 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1690823064812/d652e7be-a58f-4420-a0e4-76e516b76c57.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Let me start with some scenarios to illustrate the concept of <a target="_blank" href="https://en.wikipedia.org/wiki/Technical_debt">technical debt</a> before providing a formal definition and discussing how to eliminate it.</p>
<p><strong>Scenario #1</strong></p>
<p>You are part of a startup trying to ship the latest updates to the customers and your product owner is concerned if you take two days extra to document the code and add more test cases, the initial traction you have built with the customers will die down. You are accumulating technical debt. If a new teammate joins, this person will not have any references to learn from. He might modify code and may reintroduce bugs that were fixed before.</p>
<p><strong>Scenario #2</strong></p>
<p>You are part of a <em>highly unstructured software team</em>. The development team is involved in customer interaction and bug fixes, the team lead juggles multiple roles in the team - as the software architect, scrum master, and technical team lead. Again by not creating sustainable processes and by investing too much into one resource, you are creating a dependency. If this person leaves, or changes team, the whole knowledge is lost.</p>
<p><strong>Scenario #3</strong></p>
<p>If you have been part of the organization for too long and sometime in the past you and your team worked on the tool. But eventually, you have moved on and the tool is not actively maintained, and then after a year, the customer wants to add features to it. You are the only one around, but you also do not remember the requirements at that time. Also, since the tool is not maintained for a year now, the libraries are all stale. It will take as much time for you as it would take a new person to add a feature to this tool.</p>
<p><strong>Technical Debt - Definition</strong></p>
<p>From all the examples above, you might have gotten a fair understanding of the word "technical debt"(also known as <strong>design debt</strong> or <strong>code debt</strong>. Technical debt is the result of the software development team expediting the delivery of a certain feature or a project without proper documentation, software architecture practices, or employing resources to develop automation testing.</p>
<p><strong>Is technical debt bad?</strong></p>
<p>Technical debt is like monetary debt. It can be good or bad, depending on how it is used. If you use technical debt to create a quick and dirty proof of concept, it can be a valuable tool. However, if you use technical debt to create a system that is not scalable or maintainable, it can be a serious problem. Sooner or later, you will have to rewrite the entire system because it is not scalable, or, did not discuss the requirements properly.</p>
<p>Like borrowed money, if you do not pay it back, it accumulates interest. Similarly, if you remember to maintain the code, refactor it when necessary, and document and write test cases, then you are keeping the yin and the yang together.</p>
<p><strong>How can you eliminate technical debt?</strong></p>
<p>You may not be able to completely get rid of technical debt, but you and your team can reduce the ramifications of it by:</p>
<ol>
<li><p>Allocating resources and prioritizing code documentation,</p>
</li>
<li><p>Paying attention to testing and test case development,</p>
</li>
<li><p>Refactoring the code when necessary, and,</p>
</li>
<li><p>Updating libraries.</p>
</li>
</ol>
<p>I would love to hear how your team is tackling <strong>technical debt</strong> (<strong>design debt</strong> or <strong>code debt</strong>). Do let me know in the comments!</p>
]]></content:encoded></item></channel></rss>