<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ninad Mhatre</title>
    <description>The latest articles on DEV Community by Ninad Mhatre (@ninadmhatre).</description>
    <link>https://dev.to/ninadmhatre</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F330206%2F7462af28-f1ae-44c9-85b0-a58f9a479272.png</url>
      <title>DEV Community: Ninad Mhatre</title>
      <link>https://dev.to/ninadmhatre</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ninadmhatre"/>
    <language>en</language>
    <item>
      <title>Vibe coding - does it actually work?</title>
      <dc:creator>Ninad Mhatre</dc:creator>
      <pubDate>Mon, 29 Dec 2025 09:40:45 +0000</pubDate>
      <link>https://dev.to/ninadmhatre/vibe-coding-does-it-actually-work-56k4</link>
      <guid>https://dev.to/ninadmhatre/vibe-coding-does-it-actually-work-56k4</guid>
      <description>&lt;p&gt;I have been coding for 19+ years and for most of the time my workflow was pretty much similar. Things changed about 3 years back once ChatGPT came on the scene. The way I code has changed a lot after that. Still, at least for me it is far away from replacing developers.&lt;/p&gt;

&lt;h2&gt;
  
  
  What has changed?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Getting unstuck
&lt;/h3&gt;

&lt;p&gt;In my company, AI tools are encouraged and Co-pilot and Windsurf are the official tools. Earlier (before 2022), If I was stuck on coding task, my go to option were "stack overflow" or asking a colleague. This was slow and most of the time, I had to post the  idea without actual code and partially with limited context required for understanding the problem and then, wait till someone responds and further delays in case of follow ups if initial solution does not work.&lt;/p&gt;

&lt;p&gt;This entire flow has changed to inline chat, AI has lot more context about my code and lot more knowledge about the libraries that my code is using. It often times give a solution and if not that, It gives me good pointers to solution. I sometimes switch between models to get code that suite my taste.&lt;/p&gt;

&lt;p&gt;Of course, If there are up-sides then there has to be some downsides as well. AI also has downsides like, code generated with non-existing APIs, way to complicated code or code that does not work at all. For me, I always try to understand the code generated and change it as per my style. &lt;/p&gt;

&lt;p&gt;The most important point here is that, ability to move forward rather quickly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bouncing Ideas
&lt;/h3&gt;

&lt;p&gt;I remember once I wanted opinion of other to compare two ideas. I posted on stack overflow and question was banned as I was asking for opinion and not the definite answer. The whole point of question was to get opinionated answers but I also understand this could lead arguments between conflicting ideas.&lt;/p&gt;

&lt;p&gt;With Copilot and Windsurf, I can bounce my ideas very easily and go deep to understand the solution. I can even ask for what references were used and follow them. I can ask it to generate quick code snippet to try out the idea and data required. All this without judgement and delays.&lt;/p&gt;

&lt;p&gt;There is a good chance that you will get completely crap answers but its up to me to go deep and understand the suggestion and try it out before assuming that everything that is said is correct.&lt;/p&gt;

&lt;p&gt;For e.g, I was working on Pandas based code and It was pulling data greater than 40 GB and then processing that much of data was clearly not best to be done with Pandas. I wanted to see if new "Polars" or existing "PySpark" was best for this task. And how much time will it take for computation in new approaches? I needed a POC to try out both ideas and see the result myself. Thanks for Claude I could complete the POC within few hours.&lt;/p&gt;

&lt;h3&gt;
  
  
  Auto complete &amp;amp; Testing
&lt;/h3&gt;

&lt;p&gt;This has improved a lot, not only for code completion but for adding doc strings in code base. My code is now properly documented with example code. &lt;/p&gt;

&lt;p&gt;Even before AI Tools I always added doc strings and examples but that whole process took longer and now, its auto-generated correctly in 95% cases.&lt;/p&gt;

&lt;p&gt;One thing I am positively surprised about generated code is, sometimes as a developer I tend to use known API of any library instead of using new or better API which was added recently. I came across few PySpark &amp;amp; Pandas API that I learned because of AI tools.&lt;/p&gt;

&lt;p&gt;I prefer to have partial code with test suite rather than all features and no test coverage. I try to build tests incrementally, and AI tools have helped me greatly to get started with test setup and adding basic tests. I iterate over basic tests and improve them, most of the time I keep the scaffolding created by tool and write my tests.&lt;/p&gt;

&lt;h3&gt;
  
  
  Learning
&lt;/h3&gt;

&lt;p&gt;Learning is way easier with LLMs. Learn a new programming language or a library/tool (Terraform, Plumi, K8S) is very easy. You have inline help to get unstuck and learn quickly. You can ask all sort of questions without feeling being judged. All you need is curiosity.&lt;/p&gt;

&lt;p&gt;I intentionally keep my auto-complete off when I am learning a language otherwise LLMs are so good that you will have a working code but zero-learning. Its a double edged sword!&lt;/p&gt;

&lt;p&gt;I have realized that focusing on basics or concepts is far more important than learning a language or a specific tool. &lt;/p&gt;

&lt;h2&gt;
  
  
  Is it good enough to replace Devs?
&lt;/h2&gt;

&lt;p&gt;I am impressed with the code generation ability of LLMs, but is it going to replace Devs? Short answer, I don't think so!&lt;/p&gt;

&lt;p&gt;I have tried spec driven development when I wanted to build a job monitor, which would scan multiple database tables and compare the rows inserted everyday for last 7 days and flag if latest results are not in line with last 7 days.&lt;/p&gt;

&lt;p&gt;I only used prompts to implement whole logic and for any changes relied on prompts. This whole process worked and I had monitor job created as per my wish in within 2 hours (accumulated all changes over a week). &lt;/p&gt;

&lt;p&gt;One more example would be, I wanted to build a FastAPI based job scheduler, I (LLMs) built the UI for job scheduler using only prompts. I was 100% sure that I am not going to improve this code and just use forever once it works. Just like external package, as long as its working I am good!&lt;/p&gt;

&lt;p&gt;If everything is working, then what is down side?&lt;/p&gt;

&lt;p&gt;My Job monitor code generated 10+ files with 1000+ LOC and it explained me all the changed it did every time I asked it to change things. But that's just too much of code to review. It changed 500+ lines in HTML file, and I was asked for review those changes! &lt;/p&gt;

&lt;p&gt;I prefer to understand the logic when I review instead of just looking for syntactical accuracy. &lt;/p&gt;

&lt;p&gt;After so many years being a developer, One thing I know is, amount of code we maintain over time is far more compared to time we spend writing new code. I would say 80% is maintain and improve and rest is adding completely new code. I am just not sure how LLMs will handle this? Till now I have only seen LLMs producing new code but nothing about maintaining. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When I say maintain, I mean keeping the backward compatibility, thinking about the deployment, run time constraints etc. And adding new functionality in code base.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I feel confident when I know in-and-outs of code Bases I work on. And I don't mean line by line but the bigger picture, like which part deals with DB, file system or specific front-end component. In LLM generated code, I don't feel that confidence, maybe I need to invest more time to study the generated code to get that confidence.&lt;/p&gt;

&lt;p&gt;Do you have a successful code base (with users) which is completely written and maintained by LLMs? Please let me know in comments. I would love to understand how its used.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>coding</category>
      <category>githubcopilot</category>
      <category>ai</category>
    </item>
    <item>
      <title>Rust: cargo release flags or codegen options</title>
      <dc:creator>Ninad Mhatre</dc:creator>
      <pubDate>Thu, 29 May 2025 09:39:07 +0000</pubDate>
      <link>https://dev.to/ninadmhatre/rust-cargo-release-flags-or-codegen-options-398j</link>
      <guid>https://dev.to/ninadmhatre/rust-cargo-release-flags-or-codegen-options-398j</guid>
      <description>&lt;p&gt;I am learning Rust actively since a last 6 months, In order to learn I am building small personal projects to learn aspects of  language. As I mentioned, I am still a newbie in Rust, so when Microsoft released &lt;code&gt;edit&lt;/code&gt; (vim like editor) for windows which is fully written in Rust, I decided to take a look at the code base (I love open-source) in order to learn from it.&lt;/p&gt;

&lt;p&gt;First thing I looked at was &lt;code&gt;Cargo.toml&lt;/code&gt; and I was surprised by optimizations done for release build.&lt;/p&gt;

&lt;p&gt;I decided to try those on my personal project. I created this small utility to parse parquet files using Rust (&lt;a href="https://github.com/ninadmhatre/rupy/tree/main/pq" rel="noopener noreferrer"&gt;https://github.com/ninadmhatre/rupy/tree/main/pq&lt;/a&gt;). It works but problem is the binary size. Its massive 56 MB! I wanted to see how much reduction can be done on the binary size with this optimization/flags.&lt;/p&gt;

&lt;h3&gt;
  
  
  Default
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Compilation Time: 2m 10s
Binary Size (MB): 56
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Reduce codegen-units
&lt;/h3&gt;

&lt;p&gt;For faster compilation code units are split, default is 256 (incremental) and 16. Higher the number quick the build but may produce slower code. Lets set it 1.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Docs:&lt;/strong&gt; &lt;a href="https://doc.rust-lang.org/rustc/codegen-options/index.html#codegen-units" rel="noopener noreferrer"&gt;Here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Flags:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;codegen-units=1&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Compilation Time: 3m 10s
Binary Size (MB): 40 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Change lto
&lt;/h3&gt;

&lt;p&gt;Defers LTO optimizations to linker. Default is &lt;code&gt;no&lt;/code&gt; or &lt;code&gt;off&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Docs:&lt;/strong&gt; &lt;a href="https://doc.rust-lang.org/rustc/codegen-options/index.html#linker-plugin-lto" rel="noopener noreferrer"&gt;Here&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Flags:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;codegen-units=1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;lto= true&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Compilation Time: 5m 16s
Binary Size (MB): 38
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Change opt-level
&lt;/h3&gt;

&lt;p&gt;Controls optimization levels. Default is no optiomization.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Docs:&lt;/strong&gt; &lt;a href="https://doc.rust-lang.org/rustc/codegen-options/index.html#linker-plugin-lto" rel="noopener noreferrer"&gt;Here&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Flags:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;codegen-units=1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;lto= true&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;opt-level = "s"&lt;/code&gt;  // optimize for size
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Compilation Time: 4m 35s
Binary Size (MB): 28
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Rest of the flags
&lt;/h3&gt;

&lt;p&gt;Below flags are about debug and controlling behaviour, so instead of checking 1 by 1, I applied them together.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;panic&lt;/strong&gt;: &lt;code&gt;abort&lt;/code&gt; or &lt;code&gt;unwind&lt;/code&gt; on panic?&lt;br&gt;
&lt;strong&gt;strip&lt;/strong&gt;: Controlles stripping of debuginfo and other data from binary.&lt;br&gt;
&lt;strong&gt;split-debuginfo&lt;/strong&gt;: emitting debuginfo into separate file&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Flags:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;codegen-units=1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;lto= true&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;opt-level = "s"&lt;/code&gt;  // optimize for size&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;panic=abort&lt;/code&gt;      // do not unwind on panic&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;strip="symbols"&lt;/code&gt;  // if you want crash reporting, then not recommended&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;split-debuginfo="packed"&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Compilation Time: 3m 56s
Binary Size (MB): 20 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;My repository is very small but depends on Polars. In conclusion, with codegen options/release flags, my compilation time increased to 3m 56s from 2m 10s -&amp;gt; +81% but my binary size reduced from 56M -&amp;gt; 20M -&amp;gt; -65%. You can play around with these options to figure out what works for you.&lt;/p&gt;

&lt;p&gt;You can read more about all &lt;a href="https://doc.rust-lang.org/rustc/codegen-options/index.html#codegen-options" rel="noopener noreferrer"&gt;codegen options&lt;/a&gt;&lt;/p&gt;

</description>
      <category>rust</category>
      <category>cargo</category>
      <category>release</category>
      <category>newbie</category>
    </item>
    <item>
      <title>Python to Rust - Some early thoughts</title>
      <dc:creator>Ninad Mhatre</dc:creator>
      <pubDate>Thu, 01 May 2025 08:14:05 +0000</pubDate>
      <link>https://dev.to/ninadmhatre/python-to-rust-some-early-thoughts-k09</link>
      <guid>https://dev.to/ninadmhatre/python-to-rust-some-early-thoughts-k09</guid>
      <description>&lt;p&gt;I have been following Rust for very long time, I tried to learn Rust at least 3 times in the past 5 years. Last time I started learning rust, v1.36 was just released. &lt;/p&gt;

&lt;p&gt;I always started to learn from the online rust book (which is very nice), In last 3 attempts I could only reach till chapter 9. This time i.e. about 8 months back, I decided to learn Rust completely and slowly. So I got myself a Udemy course (pre-recorded) and just followed it. I can say, I know basic and can do non-vibe coding.&lt;/p&gt;

&lt;p&gt;Now to the topic of the post, but, before starting the post, a couple of quick disclaimers&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;I used Python for 10+ years and Rust for very short time, so this is based on very limited Rust knowledge.&lt;/li&gt;
&lt;li&gt;Python is 30+ years old vs. Rust is ~10 year old, So new things often seem shiny!&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;1. Which packaging tool do you use?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In Python&lt;/strong&gt;, there are multiple packaging tools. You have, basic &lt;code&gt;pip&lt;/code&gt; to latest &lt;code&gt;uv&lt;/code&gt;, and in between you have &lt;code&gt;poetry&lt;/code&gt;, &lt;code&gt;hatch&lt;/code&gt; etc. &lt;/p&gt;

&lt;p&gt;I am personally comfortable with &lt;code&gt;poetry&lt;/code&gt; but it's personal preference. As a team, It's not easy to agree on one tool when you have many options.&lt;/p&gt;

&lt;p&gt;On top of this, you need formatting, linting, test runners. Agreeing on tools sometimes can be daunting. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It's hard to justify, in a 40K LOC project, which formatter to use &lt;code&gt;ruff&lt;/code&gt; or &lt;code&gt;black&lt;/code&gt;, unless you care about sub-second delay with black.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;In Rust&lt;/strong&gt;, there is only one, Cargo! It does everything. (For good or bad)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Libraries and separation of concern&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In Python&lt;/strong&gt;, I love &lt;code&gt;pathlib&lt;/code&gt; library. It does everything, you can create &lt;code&gt;path&lt;/code&gt; and then manipulate it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pl&lt;/span&gt;

&lt;span class="n"&gt;tmp_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/tmp/this/is/new/dir/a.txt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;tmp_file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_file&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;   &lt;span class="c1"&gt;# False
&lt;/span&gt;&lt;span class="n"&gt;tmp_file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parents&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mkdir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parents&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;tmp_file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;w&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;this is test file&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# How do you delete it?
# maybe, tmp_file.parents.rmdir() # nope, no option to delete dir-tree
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With one module,&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;I created directory structure&lt;/li&gt;
&lt;li&gt;I created file and wrote text in it.&lt;/li&gt;
&lt;li&gt;It made it so simple.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;But, then in order to delete tree you need another module. also inverse of &lt;code&gt;mkdir&lt;/code&gt;, i.e, &lt;code&gt;rmdir&lt;/code&gt; they don't work in similar manner.&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="n"&gt;shutil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rmtree&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tmp_file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;In Rust&lt;/strong&gt;, I did the same exercise and it required 2 different modules.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// file-system&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;path&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/tmp/this/is/new/dir/b.txt"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{:?}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="nf"&gt;.is_file&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;  &lt;span class="c1"&gt;// same as python&lt;/span&gt;

    &lt;span class="cm"&gt;/* 
    Creating file and dir is handled by fs module (it can create and delete entire dir tree
    */&lt;/span&gt;

    &lt;span class="nn"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;create_dir_all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="nf"&gt;.parent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nn"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"this is a test file"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// fs::remove_dir_all(path.parent().unwrap()).unwrap()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Oh boy, but if you want to append to a file in Rust, it is not intuitive at all. also, I am not using &lt;code&gt;fs::write&lt;/code&gt; to append to a file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;append&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;OpenOptions&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="nf"&gt;.write_all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;b"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt; and this is another line"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Another example of library&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Python&lt;/strong&gt;, In order put a thread to sleep/pause it, you would do&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I never questioned "why &lt;code&gt;time&lt;/code&gt; lib that deals with time, is putting a thread to sleep?", until I did it in Rust&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rust&lt;/strong&gt;, In order put a thread to sleep, you would do&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;time&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_sec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;  &lt;span class="c1"&gt;// you have from_millis/micro/nano API to sleep for even shorter duration.   &lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As thread will be put to sleep, sleep is in &lt;code&gt;thread&lt;/code&gt; module. and you have to use &lt;code&gt;Duration&lt;/code&gt; object from time to specify how long to sleep?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. import this&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In Python&lt;/strong&gt;, you have Zen of python, Its a philosophy that you can follow to write code. It was written in 1999!&lt;/p&gt;

&lt;p&gt;You look at the current python ecosystem and wonder if those are even followed during python development. Lets look at them,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: I agree with those, just that they are sometimes hard to follow, also, since they are no concrete they are open to interpretation.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I have some use cases where I wonder,&lt;/p&gt;

&lt;h4&gt;
  
  
  Case 1
&lt;/h4&gt;

&lt;p&gt;Lets look at,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;tmp_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/tmp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;joinpath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;a.txt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# /tmp/a.txt
&lt;/span&gt;
&lt;span class="c1"&gt;# but same library also allows this,
&lt;/span&gt;&lt;span class="n"&gt;tmp_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/tmp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;a.txt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;          &lt;span class="c1"&gt;# /tmp/a.txt
&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Its achieved by overridding &lt;code&gt;__truediv__&lt;/code&gt;, good example of polymorphism, but is it "explicit"?&lt;/p&gt;

&lt;p&gt;Breaks:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Explicit is better than implicit.&lt;/li&gt;
&lt;li&gt;Readability counts.&lt;/li&gt;
&lt;li&gt;Special cases aren't special enough to break the rules.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Case 2
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;
&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;  &lt;span class="c1"&gt;# is same as &amp;lt;set1&amp;gt;.is_subset(&amp;lt;set2&amp;gt;)
&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why is this allowed? Some AI tool generated this code with "greater than operator", which I could only understand by reading docs. If readability counts why have such options built in the language?&lt;/p&gt;

&lt;p&gt;Breaks:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Explicit is better than implicit.&lt;/li&gt;
&lt;li&gt;Readability counts.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Case 3
&lt;/h3&gt;

&lt;p&gt;The following examples exist mostly for legacy reasons, but they are still part of the language.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. os.path.joinpath or pl.Path? 
2. glob.glob or pl.Path.glob?
3. 
   - "a %s", val 
   - "a {}".format(val) 
   - f"a {val}"? 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Having multiple ways of doing same thing?&lt;/p&gt;

&lt;p&gt;Breaks:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;There should be one-- and preferably only one --obvious way to do it.&lt;/li&gt;
&lt;li&gt;Although that way may not be obvious at first unless you're Dutch.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I don't have anything related to Rust like this, maybe due to my limited exp. or language is new compared to Python.&lt;/p&gt;

&lt;p&gt;Now, coming to purpose of this post, I might never have questioned some of the implementation in my &lt;em&gt;favorite&lt;/em&gt; language if I never tried same thing in another language.&lt;/p&gt;

&lt;p&gt;It's good idea to learn a new language with a different philosophy every few years.  &lt;/p&gt;

</description>
      <category>python</category>
      <category>rust</category>
      <category>corelib</category>
    </item>
    <item>
      <title>Python Caching mutable values</title>
      <dc:creator>Ninad Mhatre</dc:creator>
      <pubDate>Sun, 26 Jan 2025 07:36:31 +0000</pubDate>
      <link>https://dev.to/ninadmhatre/python-caching-mutable-values-213f</link>
      <guid>https://dev.to/ninadmhatre/python-caching-mutable-values-213f</guid>
      <description>&lt;p&gt;Caching is used everywhere in order to speed up processing. Its used right from CPU level to a layer in front of databases. Cache invalidation or when to remove something from cache, is very interesting and complex problem to solve. I am going to talk about something simple than that.&lt;/p&gt;

&lt;p&gt;Issue am mentioning in this post is very simple, yet it took almost 1.5 years to come to the surface. It was hidden because of how the other parts of the code were written. It came to surface as more users started using they tried something apart from recommended approach. I will explain what it was later in the post.&lt;/p&gt;

&lt;p&gt;Some background, I created custom ML Framework (sklearn based) within my current organization. It's a ML framework so as you guessed it, there are multiple data sources which are accessed frequently. I decided to add a layer of cache to speed up things, initially I started with &lt;code&gt;lru_cache&lt;/code&gt; inbuilt module. Soon, I realized that we need some persistent caching as we fetch same data over and over (atleast while development) and all of that data is static data. &lt;/p&gt;

&lt;p&gt;This layer of caching was needed as we use Bigquery, even though I have turned on caching on bigquery side, fetching data takes some time and you still pay for egress. Caching in my case is not only speeding up things but reduces the cost as well. &lt;/p&gt;

&lt;p&gt;I looked at Redis &amp;amp; Memcache, but I didn't have clarity on how those services will be deployed with our production setup. Also, I wanted to try out the idea first, so I decided to go with "DiskCache" an amazing python module. It uses SQLite to store the content on local file-system. I ran it with 32 processes, and Pandas DataFrames up to 500MB, and It worked without any issues. Data is fetched and put into Diskcace i.e. sqlite and then added a layer of &lt;code&gt;lru_cache&lt;/code&gt; on top of that, so during execution same data is served from memory.&lt;/p&gt;

&lt;p&gt;Now you have some idea about my caching setup, lets talk about the issue I had and how it came to surface. &lt;/p&gt;

&lt;p&gt;In 1.5 years, Framework was mostly used for training 1000s of small models (of similar type, changing target, estimator etc.). Caching was used to store the pandas DFs and some other kinds of objects which were only accessed for reading. As more users started playing around with the tool to try out their ideas and few users complained about randomly getting wrong results. It was not easy to reproduce as on consecutive runs everything worked fine. Till, we found the problem.&lt;/p&gt;

&lt;p&gt;As a coding standard in framework, whenever we fetched data (i.e. Pandas DF) and did any kind of processing (transformations) we always saved in a new dataframe. Some users started doing &lt;code&gt;inplace=True&lt;/code&gt; out of habit and this not only changed the current result but also the result in the cache. Lets dive deeper into why this happened?&lt;/p&gt;

&lt;p&gt;I am going to mimic the issue with dict instead of data frame.&lt;/p&gt;

&lt;p&gt;I have a decorator that wraps the function/method with cache. Something like below,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;functools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;lru_cache&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;

&lt;span class="nd"&gt;@lru_cache&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;expensive_func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vals&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vals&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;e1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;expensive_func&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;c&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Now, we have e1 in cache, so fetching it again should be instant
&lt;/span&gt;    &lt;span class="n"&gt;e2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;expensive_func&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;c&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Since we store a dict or DF object in the caching what should happen if i change 
&lt;/span&gt;    &lt;span class="c1"&gt;# the fetched value?
&lt;/span&gt;
    &lt;span class="n"&gt;e2&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;d&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;amazing&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;  &lt;span class="c1"&gt;# should it change anything in cached value?
&lt;/span&gt;
    &lt;span class="c1"&gt;# If you answered it no, then you are in for surprise...
&lt;/span&gt;    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;e3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;expensive_func&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;c&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# you will see that e3 also has a "d" a new key added.
&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://programiz.pro/ide/python/CTFHTFZPMX?utm_medium=playground&amp;amp;utm_source=python_playground-shared-project-link" rel="noopener noreferrer"&gt;Try it in playground&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Why do see this behaviour? Because &lt;code&gt;lru_cache&lt;/code&gt; gives you a reference to cached variable, and when you modify, it modifies the actual value referenced by the pointer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Since we know that issues is due to working with reference of a cached value and I have no control over how it will be used downstream. easy (&amp;amp; simple) solution I implemented was to return a copy every time you are returning a result. Since you are working with a copy of data user can change it or do anything with it. This results in data duplication, you might have multiple copies of same data, it was not a problem for us.&lt;/p&gt;

&lt;p&gt;I am going to mention couple of points from some architecture books I am currently reading,&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;No architecture is good or bad, it's how expensive (time-wise) is to make a change.&lt;/li&gt;
&lt;li&gt;Architecture is about making decisions with least amount of bad things (based on known-knows, known-unknowns).&lt;/li&gt;
&lt;li&gt;It's always a compromise, if you think your solution has no compromises then there is a chance that you have not understood the problem fully or thought about all scenarios (or not yet surfaced - unknown-unknowns).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now, getting back to solution, all we need is a small decorator which decorates the &lt;code&gt;lru_cache&lt;/code&gt; and returns a &lt;code&gt;deepcopy&lt;/code&gt; of the cached object every time its accessed&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;custom_cache&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;cached_func&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# evaluated only once!
&lt;/span&gt;
    &lt;span class="nd"&gt;@wraps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_wrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;deepcopy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;cached_func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  &lt;span class="c1"&gt;# gets called every time
&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;_wrapper&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Lessons Learned&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Understood &lt;code&gt;lru_cache&lt;/code&gt; in bit more detail.&lt;/li&gt;
&lt;li&gt;Your recommended approach can prevent bugs.&lt;/li&gt;
&lt;li&gt;Users are not going to listen / follow same coding practices like developers do, so try to fix the implementation whenever you can.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>python</category>
      <category>caching</category>
      <category>lru</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Python: Interesting Code Patterns</title>
      <dc:creator>Ninad Mhatre</dc:creator>
      <pubDate>Sat, 07 Sep 2024 18:11:01 +0000</pubDate>
      <link>https://dev.to/ninadmhatre/python-interesting-code-patterns-dh3</link>
      <guid>https://dev.to/ninadmhatre/python-interesting-code-patterns-dh3</guid>
      <description>&lt;p&gt;I work mostly with Python and review code on almost daily basis. In our code base formatting &amp;amp; linting is handled by CI jobs using black &amp;amp; mypy. So, we focus only on changes.&lt;/p&gt;

&lt;p&gt;When working in a team, you already know what kind of code to expect from a certain team member. Code reviews become interesting when a new person joins the team. I say interesting, as everyone has some coding style that they use it unconsciously; for good or bad! Like I have some,&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Setting the value of &lt;code&gt;Optional&lt;/code&gt;type.
&lt;em&gt;Usually these variables are part of the signature&lt;/em&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# I used (long back) to do
&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
       &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
       &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="c1"&gt;# Instead I do
&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Handling Simple &lt;code&gt;if..elif..else&lt;/code&gt; (up to 3-4) statements with &lt;code&gt;dict&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;This is simple use case where you return a string or call a func based on some value&lt;/em&gt; &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: from 3.10 you should use &lt;code&gt;match&lt;/code&gt; instead of this.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Instead of doing,
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_number_of_wheels&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vehicle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;vehicle&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;car&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;wheels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;vehicle&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bus&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;wheels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;vehicle&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bicycle&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;wheels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="bp"&gt;...&lt;/span&gt;

&lt;span class="c1"&gt;# I prefer doing, 
&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_number_of_wheels&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vehicle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;car&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bus&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bicycle&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="p"&gt;}[&lt;/span&gt;&lt;span class="n"&gt;vehicle&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;       &lt;span class="c1"&gt;# Raise is now KeyError
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Above are couple of examples, people who review my code will have more examples.&lt;/p&gt;

&lt;p&gt;Recently, A new developer joined my team and i noticed a pattern which I loved but I asked to change it to simple &lt;code&gt;if..else&lt;/code&gt; case. I will show you the pattern first then give my reason for asking for change.&lt;/p&gt;

&lt;p&gt;The code is a decorator which does something to parameters. Lets write a simple (useless) decorator which will print number of args &amp;amp; kwargs with which function/method was called.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;is_cls_method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt; print number of args &amp;amp; kwargs for func/method &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;outer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;inner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;args_cnt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;kwargs_cnt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; called with &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;args_cnt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &amp;amp; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;kwargs_cnt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;inner&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;outer&lt;/span&gt;

&lt;span class="nd"&gt;@counter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;pass&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;A&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nd"&gt;@counter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;is_cls_method&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;pass&lt;/span&gt;


&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;function&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;test1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;test1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;method&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;A&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On running this code, you should see&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;function
&lt;/span&gt;test1 called with &lt;span class="nv"&gt;args_cnt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2 &amp;amp; &lt;span class="nv"&gt;kwargs_cnt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1
test1 called with &lt;span class="nv"&gt;args_cnt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0 &amp;amp; &lt;span class="nv"&gt;kwargs_cnt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;3

method
test1 called with &lt;span class="nv"&gt;args_cnt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;4 &amp;amp; &lt;span class="nv"&gt;kwargs_cnt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0
test1 called with &lt;span class="nv"&gt;args_cnt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2 &amp;amp; &lt;span class="nv"&gt;kwargs_cnt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Its working fine but for methods, its also counting &lt;code&gt;self&lt;/code&gt;. so lets fix that!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;is_cls_method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;outer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;inner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;args_cnt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;is_cls_method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="c1"&gt;# Check added
&lt;/span&gt;               &lt;span class="n"&gt;args_cnt&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;    &lt;span class="c1"&gt;# Reduced count by 1
&lt;/span&gt;
            &lt;span class="n"&gt;kwargs_cnt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; called with &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;args_cnt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &amp;amp; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;kwargs_cnt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;inner&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;outer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a simple &lt;code&gt;if&lt;/code&gt; clause, but new developer did something else which was interesting use of boolean.&lt;/p&gt;

&lt;p&gt;I am showing only the changed code...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;   &lt;span class="n"&gt;args_cnt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;is_cls_method&lt;/span&gt;&lt;span class="p"&gt;:])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Solution is lot better than using &lt;code&gt;if&lt;/code&gt;, as bool in python is just int. Original code was bit longer and noticing this small change is not obvious, also code base used by users who are basic python users. And, if you have to guess what a line is doing, i think you should change to make it obvious.&lt;/p&gt;

&lt;p&gt;What is your thought on this, Do you use boolean as index? &lt;br&gt;
Do you have any more python patterns like this?&lt;/p&gt;

</description>
      <category>python</category>
      <category>codereview</category>
      <category>codestyle</category>
    </item>
    <item>
      <title>Python Environment Setup</title>
      <dc:creator>Ninad Mhatre</dc:creator>
      <pubDate>Mon, 12 Aug 2024 19:33:25 +0000</pubDate>
      <link>https://dev.to/ninadmhatre/python-environment-setup-i3b</link>
      <guid>https://dev.to/ninadmhatre/python-environment-setup-i3b</guid>
      <description>&lt;p&gt;I am a python developer and usually work with multiple repositories at any time. Most of these projects have different dependencies so I create a virtual environment in every project. I prefer creating virtual env right next to code. Pycharm also detects it when repository is opened in Pycharm. &lt;/p&gt;

&lt;p&gt;This setup worked most of the time but sometimes, I activate venv of one repository and then change it another repository without changing activating correct environment. I usually spotted this when code execution used to fail and never lost more than a minute on this but, this always made me think what if there is a shell that could run something when you enter a directory?&lt;/p&gt;

&lt;p&gt;I decided to implement something simple in shell script temporarily. I ended up with creating small function, aliased with &lt;code&gt;cd&lt;/code&gt; and added in my .bashrc.&lt;/p&gt;

&lt;p&gt;It's a simple function and all I ever needed. It does,&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Loads the &lt;code&gt;.venv&lt;/code&gt; from that repository&lt;/li&gt;
&lt;li&gt;Additionally, sources &lt;code&gt;.cdenv&lt;/code&gt;, i usually set env variable but you can do anything in there.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I was okay with not deactivating/resetting environment when i exited the directory.&lt;/p&gt;

&lt;p&gt;Add below function in &lt;code&gt;.bashrc&lt;/code&gt; and you should be able to use it. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: If you create your virtual environment with different name then please change the name in code below.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;function &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;# Run a shell `cd` command or error&lt;/span&gt;
  &lt;span class="nb"&gt;command cd&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$@&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;

  &lt;span class="c"&gt;# If .venv exists in the directory&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; .venv &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
    &lt;span class="c"&gt;# Deactivate any initialized virtual env, ignore error&lt;/span&gt;
    deactivate &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /dev/null 2&amp;gt;&amp;amp;1

    &lt;span class="c"&gt;# activate .venv&lt;/span&gt;
    &lt;span class="nb"&gt;source&lt;/span&gt; .venv/bin/activate
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"deactivate prev venv and activate current venv"&lt;/span&gt;
  &lt;span class="k"&gt;fi&lt;/span&gt;

  &lt;span class="c"&gt;# Load a .cdenv file&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; .cdenv &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
      &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"loading .cdenv"&lt;/span&gt;
      &lt;span class="nb"&gt;source&lt;/span&gt; ./.cdenv
  &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>python</category>
      <category>bash</category>
      <category>linux</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Estimating Coding Tasks: What Could Go Wrong?</title>
      <dc:creator>Ninad Mhatre</dc:creator>
      <pubDate>Sat, 10 Aug 2024 10:27:47 +0000</pubDate>
      <link>https://dev.to/ninadmhatre/estimating-coding-tasks-what-could-go-wrong-1hhh</link>
      <guid>https://dev.to/ninadmhatre/estimating-coding-tasks-what-could-go-wrong-1hhh</guid>
      <description>&lt;p&gt;Here is how the task of “adding a hash to an existing DataFrame” went from taking a couple of days to consuming almost an entire sprint.&lt;/p&gt;

&lt;p&gt;In Q2 of 2022, I started working on a data pipeline that fetches market data from a REST service and stores it in a BigQuery table. This is a high-level explanation of the pipeline. The interesting part is how the data is queried data, converting it to DataFrame and then uploading it BigQuery tables using &lt;strong&gt;&lt;em&gt;GCSToBigQueryOperator&lt;/em&gt;&lt;/strong&gt; of AirFlow.&lt;/p&gt;

&lt;p&gt;Initially, it seemed simple to write, but  Airflow’s “idempotent” principle added it bit of challenge. What to fetch from this REST service was decided by another table and even if JOB is idempotent the table it used as reference could change between 2 runs. After spending additional time, talking to Data Engineers pipelines was ready By the end of Q3 of 2022.&lt;/p&gt;

&lt;p&gt;Fast forward to Q1 of 2024. By this time, we had more users accessing the data, and we realized our query pattern was not using partitions properly. Or, rather, we wanted to access the data based on a string column, but it’s not possible to partition on a string column in BigQuery. This led to scanning large amounts of data and frequently hitting the daily quota.&lt;/p&gt;

&lt;p&gt;This led us to consider how to partition data based on string columns. Our data engineer suggested converting that string column into an integer using FarmHash with an additional modulo operation. In the proof of concept, this reduced scanning by almost 90%, and query performance increased by 3-5x. We decided to proceed with this as the final solution. All we needed was to: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a table with Farmhash fingerprint&lt;/li&gt;
&lt;li&gt;Change pipeline to compute the fingerprint&lt;/li&gt;
&lt;li&gt;Upload the data.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To compute FarmHash fingerprints in Python, there is a &lt;a href="https://pypi.org/project/pyfarmhash/" rel="noopener noreferrer"&gt;pyfarmhash&lt;/a&gt; module. I installed the module and used the code below to compute the hash, and locally it all worked as desired.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;additonal_logic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pyfarmhash&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fingerprint64&lt;/span&gt;&lt;span class="p"&gt;(...))&lt;/span&gt;

&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="nb"&gt;hash&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="n"&gt;Col&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_hash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With all the tests passing, it was now time to push the code to Airflow and run it. I was not expecting anything to go wrong at this stage. In fact, I was happy that everything worked as planned and within the estimated time. &lt;/p&gt;

&lt;p&gt;With a happy mind and full of confidence, I pushed my changes, started the job, and then waited for 10-15 minutes for it to finish. Meanwhile, I switched to another task. Soon, I received an unexpected failure email from Airflow. I looked at the logs and was surprised to see that it failed while installing the &lt;code&gt;pyfarmhash&lt;/code&gt; module!&lt;/p&gt;

&lt;p&gt;To help you understand the problem, I need to explain the structure of the job. The job has the following steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Download the data in parquet format&lt;/li&gt;
&lt;li&gt;Upload to GCS bucket&lt;/li&gt;
&lt;li&gt;Delete existing data; if any. (avoid duplicate data)&lt;/li&gt;
&lt;li&gt;Upload the data to BQ tables.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In this process, task-1, which downloads the data, is a separate Python module. To run it, I used the &lt;strong&gt;&lt;em&gt;PythonVirtualenvOperator&lt;/em&gt;&lt;/strong&gt; from Airflow. This operator allows you to specify packages as requirements and then installs them in a newly created virtual environment. Once the package is installed, all its dependencies are also installed, and you are ready to roll.&lt;/p&gt;

&lt;p&gt;I added &lt;strong&gt;&lt;em&gt;pyfarmhash&lt;/em&gt;&lt;/strong&gt; as a dependency to the module that downloads the data, and everything else remained unchanged. And it failed! Why?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;pyfarmhash&lt;/em&gt;&lt;/strong&gt; is a hashing library implemented in C/C++. Upon installation, it requires GCC to compile the package, and that was not present on the Airflow host. It made sense not to have GCC on the Airflow host, but unfortunately, this was a blocker for me.&lt;/p&gt;

&lt;p&gt;I looked for a pure Python implementation of the pyfarmhash package, but there were none. Then, I looked for wheel packages, but again, there were none. I considered building wheel packages and pushing them, but that would have led to a long-term responsibility of providing wheel packages internally. I wanted to avoid additional, workaround-like steps. I explored all the options and discussed them with the team maintaining Airflow. They suggested creating a Docker image and running it in &lt;strong&gt;&lt;em&gt;KubernetesPodOperator&lt;/em&gt;&lt;/strong&gt;. This was a good option, as I could control the environment and include whatever was required without relying on an external environment. Additionally, this solution had no workarounds. The only short-term drawback was that it needed more time to implement.&lt;/p&gt;

&lt;p&gt;Before starting with a Docker-based solution, I had already spent about 16-20 hours on this task. For the Docker-based solution, I additionally needed to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Change the Python package to have entry points to start download and purging logic. &lt;/li&gt;
&lt;li&gt;Create a Docker package and test it (this was my second Docker image). &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Since I was no longer going to use PythonVirtualEnvOperator in Airflow, I decided to remove it completely also improve the workflow. I had to change the python package to have entry points to start download &amp;amp; purging logic&lt;/p&gt;

&lt;p&gt;It took me an additional 30-36 hours to have a final solution with the Docker image ready, which is 6-7 working days and, with initial 2 days included, it became a sprint long task.&lt;/p&gt;

&lt;p&gt;I look back on this and wonder, I had to throw away working solution, change the module structure, create a docker image, change 10+ AirFlow jobs to use Docker image for tasks, dealing with this reality and overcoming initial frustration. All of this only because, "A single python module  required “gcc” to compile!"&lt;/p&gt;

</description>
      <category>python</category>
      <category>estimation</category>
      <category>airflow</category>
      <category>learning</category>
    </item>
    <item>
      <title>Towards cloud native dev...</title>
      <dc:creator>Ninad Mhatre</dc:creator>
      <pubDate>Sun, 25 Sep 2022 11:22:04 +0000</pubDate>
      <link>https://dev.to/ninadmhatre/towards-cloud-native-dev-36d8</link>
      <guid>https://dev.to/ninadmhatre/towards-cloud-native-dev-36d8</guid>
      <description>&lt;p&gt;I am a Python developer with 15+ years of experience. I was working as automation QA engineer (created custom testing framework, modifying it and doing functionality testing) for 4+ years and as you would have guessed it, working on something for 4 years surely does take out charm / challenge out of it. So i was looking for new things and at the start of 2022 there was email about Python developer role in some other team. I jumped onto it and got it just based on recommendation.&lt;/p&gt;

&lt;p&gt;So, this new role was with Quantitative research team, just to give my background, I am not good at math, specially math which only has letters in their equation :). One thing i was sure about my skills and i knew that i would learn anything for the task i am working on and produce result and improve them as i get more experience / knowledge.&lt;/p&gt;

&lt;p&gt;I was happy that i will work with Scientific side of Python libraries (numpy, scipy etc.) and then with GCP (Google Cloud Platform). First task i started with was creating Pipeline to load data into bigquery for our ML Pipeline. I faced some design decision issues just because i was not following cloud native approach. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Get requests to data server timing out after first 1000 requests.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I created fully functional local Airflow pipeline but it started timing out on GCP. Why? cause i was opening new socket for every request to save host! This would have worked fine only any VM or server but not on cloud. Though, i think i should have used Session from the start. &lt;strong&gt;Learned why to use sessions&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Re-running airflow job&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I must confess that choosing BigQuery (BQ) was not my decision. As BQ has no concept of duplicate / unique row concept, we needed to make sure that if we re-run job for some day it needs to first clean the data from BQ. So I was forced to think in a different way of how to structure the data, partition on column and then in case of re-run just drop the partition. But how to decide which partition to drop? all these decisions impacted my conventional developer thinking and helped me to think like &lt;strong&gt;Cloud-Native developer&lt;/strong&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Do the backfill with starting date going back to 6 years back.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This i must confess was the hardest part of the whole pipeline. How would you one-off back-fill for past 6 years and then do it periodically if some data is corrupt for specific IDs. &lt;/p&gt;

&lt;p&gt;When i started with this development, I was very sure that this whole thing can be completed in 1 month but in reality, I had to learn about Airflow, Bigquery, GCP limitations and access rights! In the end, i spent close to 2.5 months to get this pipeline running in production. In the end, i was very happy that my first pipeline is working fine for 3+ months without having any issues.&lt;/p&gt;

</description>
      <category>python</category>
      <category>gcp</category>
      <category>airflow</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Good enough is fine...</title>
      <dc:creator>Ninad Mhatre</dc:creator>
      <pubDate>Sun, 03 Jan 2021 14:35:46 +0000</pubDate>
      <link>https://dev.to/ninadmhatre/good-enough-is-fine-2jh6</link>
      <guid>https://dev.to/ninadmhatre/good-enough-is-fine-2jh6</guid>
      <description>&lt;p&gt;Still remember vividly, myself coding for some resume creation site in hospital's waiting room while my wife was doing her prenatal exercise. I was working on this site for 6 months by then but it was no where close to being ready for release in the wild! And unfortunately i was responsible for keeping it that way, like working on Jira like site so that i can create new bugs/improvement tickets easily and wasting one week behind it or pushing to create better UI and kept on delaying the release till Feb 2017, when my son was born and i don't remember working on this site for next 2 years. In 2 years,  I not only lost the momentum but also the interest to continue! Its been 4.5 years since i first started with this idea and this site is lying somewhere on my private repository. I no longer even wish to publish it!&lt;/p&gt;

&lt;p&gt;Fast forward to Nov 2020, saw my wife who is very active on Instagram managing her hashtags in keep by creating multiple notes and then copy pasting it. There i got the idea of save tags. A website where you can categorize tags and then select them based on your post. Main reason for creating was just to create something but i still wanted it to be prefect but i learnt from last experience, so this time i just created site, wrote some tests for back-end, decent UI (i am back-end dev so i just used Bootstap and google), use only google oauth (last time i setup google, facebook, twitter and github) and good to go. I sent it to couple of friends but no one gave any feedback ☹️ something to keep in mind for next time. This site is created just for fun and not with intention on making business out of it so give it a try and share your feedback. &lt;/p&gt;

&lt;p&gt;Perfect product do not exist! Close to perfection takes time and good enough is okay for the most and you get valuable feedback which helps to shape product. In case you have half baked product try to release it as soon as possible. &lt;/p&gt;

&lt;p&gt;Updated:&lt;br&gt;
&lt;del&gt;Lastly, please checkout &lt;a href="https://save-tags.com" rel="noopener noreferrer"&gt;https://save-tags.com&lt;/a&gt;&lt;/del&gt;&lt;/p&gt;

&lt;p&gt;I have taken down the site after running it for 3-4 months. But point of the post was, If you create something release it once you think it's good enough! You might never achieve the perfection you are looking for.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>python</category>
    </item>
    <item>
      <title>software testing, assertions</title>
      <dc:creator>Ninad Mhatre</dc:creator>
      <pubDate>Sat, 11 Jul 2020 15:16:43 +0000</pubDate>
      <link>https://dev.to/ninadmhatre/software-testing-assertions-2i8</link>
      <guid>https://dev.to/ninadmhatre/software-testing-assertions-2i8</guid>
      <description>&lt;p&gt;I work on a testing framework which validates application by sending and receiving messages with the proprietary protocol. And certainly, there are a lot of assertions with most of them checking the value of the field, some checks the type of message received and some ordering of messages. All of these assertions are grouped by functionality in multiple functions across multiple files. Having a lot of assertions is not a problem but not showing a clear message is certainly a problem. Imaging test being failed with something like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="nb"&gt;long&lt;/span&gt; &lt;span class="n"&gt;stack&lt;/span&gt; &lt;span class="n"&gt;trace&lt;/span&gt; &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;span class="n"&gt;AssetionError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;looking at it just gives a basic idea that something should have been &lt;code&gt;True&lt;/code&gt; but was not! If you read stack trace you can figure out where the assertion failed, but there is a big "if you read" Nobody reads it! Then we get a lot of links to failed jobs with a sweet message, "tests are failing". &lt;/p&gt;

&lt;p&gt;This is due to having lot of bare &lt;code&gt;asserts&lt;/code&gt;, when we started developing the tests our the main focus was converting manual tests to automated and that's why we have lot of asserts lying around in our code base.&lt;/p&gt;

&lt;p&gt;The second pain point was not that big deal, but surely good to address is, when we check new message structure and values, its fails one by one. If message has 20 fileds then you can imagine how long it will take to figure out all wrongly populated fields. I wanted to report all failures at once so that I can ask a developer to take a look at all in one go. There is already a solution to this, &lt;code&gt;delayed_assert&lt;/code&gt; module in python, but that is a wrapper around assert which stores stack trace and dumps in the end and it also meant that i need to replace all assets.&lt;/p&gt;

&lt;p&gt;I decided to solve both the problems in one go, I searched and found few assertion libraries in python, one particular I liked was &lt;code&gt;assertpy&lt;/code&gt; because it has clean API and it has &lt;code&gt;assert_warn&lt;/code&gt; function which would just report the errors (without stack trace) but won't stop the execution. My idea was, write a wrapper which would return &lt;code&gt;assert_that&lt;/code&gt; or &lt;code&gt;assert_warn&lt;/code&gt; depending upon a certain condition.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# some wrapper file
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;assertpy&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;assert_that&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;assert_warn&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_assertor&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ERRORS_AS_WARN&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;assert_warn&lt;/span&gt;
   &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;assert_that&lt;/span&gt;

&lt;span class="n"&gt;assert_that&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_assertor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;also the API os &lt;code&gt;assertpy&lt;/code&gt; is just brilliant&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;assertpy&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;assert_that&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;nose.tools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;assert_equal&lt;/span&gt;

&lt;span class="c1"&gt;# not very easy to understand
&lt;/span&gt;&lt;span class="nf"&gt;assert_equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;4 is not equal to 2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# its like reading a sentance
&lt;/span&gt;&lt;span class="nf"&gt;assert_that&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;addition&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;is_equal_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I decided I will use &lt;code&gt;assertpy&lt;/code&gt; but then I started implementing and I realized,&lt;/p&gt;

&lt;p&gt;1) we only use a handful of assertions and regular ones that we use are not in &lt;code&gt;assertpy&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;2) though assertion methods can be easily plugged in &lt;code&gt;assertpy&lt;/code&gt;, requirement of such function is the first argument named as &lt;code&gt;self&lt;/code&gt;, which felt bit odd&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;is_in_between&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; 
   &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;so I checked the code and realized that for every assert_that, a new instance of the class is created and extensions are added on every initialization, I thought its extra work for little gain.&lt;/p&gt;

&lt;p&gt;3) my dynamic error to the warning was working but it was printing the wrong location of the source as it was looking for &lt;code&gt;assert_warn&lt;/code&gt; in stack trace but I was referring it to as &lt;code&gt;assert_that&lt;/code&gt;, in short it was only working partially.&lt;/p&gt;

&lt;p&gt;Adding PR to &lt;code&gt;assertpy&lt;/code&gt; seemed worthless as all solutions felt like a hack and then I decided to write one which is based on &lt;code&gt;assertpy&lt;/code&gt; but has very basic functionality but easy to extend.&lt;/p&gt;

&lt;p&gt;I created &lt;code&gt;simple-assertions&lt;/code&gt;, after thinking many times whether to re-invent the wheel or not...&lt;/p&gt;

&lt;h1&gt;
  
  
  how I solved the above issues?
&lt;/h1&gt;

&lt;p&gt;1) I created a class with a handful of common assertions, the class was picked as you can easily inherit to extend the functionality.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;simple_assertions&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;SimpleAssertions&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Union&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;YourAssertions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SimpleAssertions&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;as_warn&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;super&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;as_warn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;is_greater_than&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Union&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;val_to_chk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate_err_msg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;to be greater than&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;YourTestClass&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assert_that&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;YourAssertions&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;assert_that&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_something&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assert_that&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;is_greater_than&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;is_equal_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assert_that&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;is_instance_of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assert_that&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lucky_num&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;as_warn&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;is_equal_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;      
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2) With composition, an instance of assertion class can be created and then that single instance can be reused. IDE can also help me code completion.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyTests&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;unittest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Testcase&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;setUp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assert_that&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SimpleAssert&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;assert_that&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;3) I changed the API of &lt;code&gt;assert_that&lt;/code&gt; and instead of 2 functions, 1 for error and 1 for the warning, I added an optional parameter to create warnings, also added an environment variable which if set will convert all error to warnings. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Use of environment variable to change the behaviour is topic for discussion but for my needs, it was a perfect solution!&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;
&lt;span class="c1"&gt;# instead of, assert_warn(10).is_equal_to(9)
&lt;/span&gt;
&lt;span class="nf"&gt;assert_that&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;as_warn&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;is_equal_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I am planning to add a few more assertions so that it can be used without need to adding anything. If you want to give it a try, all you have to do is&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install simple-assertions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and you can check the source here please check here &lt;a href="https://github.com/ninadmhatre/simple-assertions" rel="noopener noreferrer"&gt;https://github.com/ninadmhatre/simple-assertions&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>testing</category>
      <category>sideprojects</category>
    </item>
    <item>
      <title>rusty start...</title>
      <dc:creator>Ninad Mhatre</dc:creator>
      <pubDate>Sun, 21 Jun 2020 21:56:38 +0000</pubDate>
      <link>https://dev.to/ninadmhatre/rusty-start-7di</link>
      <guid>https://dev.to/ninadmhatre/rusty-start-7di</guid>
      <description>&lt;p&gt;I heard about rust somewhere in 2017 but that time i picked Go over rust and started reading about it. Go syntax was simple compared to rust and Go seemed natural choice for someone who is coming from Python.&lt;/p&gt;

&lt;p&gt;I liked Go but never loved it, that was the reason i could not keep up the momentum to learn it for a long time. Eventually i gave up and just focused on current job and getting used to new country (i moved to new country for job). Once things settled and decided to look for new challenges there were 2 options, Data Science and Some compiled language!&lt;/p&gt;

&lt;p&gt;As any sane person with Python Exp. would do, i picked DS and started reading about it but this decision was more from job point of view and not something i wanted to learn so then i was back to square one, which language to pick? Go or Rust or something else? I decided to give rust another chance somewhere towards the start of 2019 and seemed like i read "rust" for the first time, i didn't find it difficult (to read), compiler was nice and official site has nice website explaining entire language. so as you guessed i picked "rust". After reading about some informational material i decided to jump directly into coding. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You never learn driving by reading a book or for that matter you learn nothing just by reading about it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I decided to convert one small shell script which is a wrapper to start/stop/check 2 binaries. Shellscript was perfect for this but this was better task than solving some coding challenge questions. i learned a lot about the language, specially compiler is amazing, errors are clear also it says how you could correct them! I wrote something which worked fine and got it reviewed by putting it on rust community and guess what, ppl actually reviewed the code and gave me inputs. There i actually fell in love with this entire setup then fast forward to 1 year to Feb 2020. In this last 1 year i could never reach beyong chapter 9 of "rust by example" something or other used to come in between and i had to refresh everything due to gap of month or so.&lt;/p&gt;

&lt;p&gt;2020 was the year i was looking forward to as i had made some plans but Corona had another plans and my plan was pretty selfish so it didn't work out! that gave me opportunity to go back to learning things, now i am on chapter 14! :). Slowly &amp;amp; steadily i am moving but there is a progress which is important. &lt;/p&gt;

&lt;p&gt;While coding it's important to have a nice setup where things just works and that was my problem, due to Corona, i was using my laptop to connect to office and since Webex has no Linux client and to avoid many setup issues i decided to boot into windows 10 since March and it will stay like that till i don't join office back. This was a issue, i dont really like windows for developing anything (C# was only exception!). I spin my virtual machine and code in that or use WSL but for rust i was not able to find the setup i could work with. Swithing to linux disto was not an option (my grub does not work and i have to change BIOS everytime) so i downloaded Lubuntu but it was painfully slow with 2.5GB ram as a last resort i decided to pick WSL and VS Code which connects to WSL. I have autocomplete for now and i compile manually with Cargo but it's lot better than other setup i tried.&lt;/p&gt;

&lt;p&gt;Once i am done with all the chapters maybe in a month, i will write some code around client-server architecture and improve on that iteratively to learn the language, but till then i have to go on with steady pace... &lt;/p&gt;

</description>
      <category>rust</category>
      <category>beginners</category>
      <category>environment</category>
    </item>
    <item>
      <title>this should be a separate PR!!</title>
      <dc:creator>Ninad Mhatre</dc:creator>
      <pubDate>Tue, 07 Apr 2020 21:39:18 +0000</pubDate>
      <link>https://dev.to/ninadmhatre/this-should-be-a-separate-pr-41l3</link>
      <guid>https://dev.to/ninadmhatre/this-should-be-a-separate-pr-41l3</guid>
      <description>&lt;p&gt;Recently while working on some task I had to write some hacky code, and by hacky,  I mean code with lot &lt;code&gt;if..else&lt;/code&gt;. There are a lot of places in the code base with such random &lt;code&gt;if..else&lt;/code&gt; changing the flow of based on some environment variable. Hence I was initially okay with adding all these &lt;code&gt;ifs&lt;/code&gt; but once I finished with the functionality and looked back to refactor so that I can send it for review, no matter how I refactored it, it turned out to be messy code which I just couldn't push for a review! &lt;/p&gt;

&lt;p&gt;Then I took a decision to refactor whole functionality so that I can later remove all the &lt;code&gt;ifs&lt;/code&gt; placed at multiple places in code. When I decided to refactor it was good from a long term perspective just that I decided to take such a decision without discussing it with anyone in the team. Before you get me wrong, this refactoring was already done to new parts of the code to solve this exact problem just that it was not applied to the old part of the codebase due to not having enough time or not the correct opportunity. &lt;/p&gt;

&lt;p&gt;Once I pushed it for review, the first comment I got was "this should be put in separate PR!". Well, in all honesty, that was expected and also true! but in reality, due to 1 QA per 5 devs, my team is usually bottleneck for releases and hence we hardly get any time to work on old code or a new feature in our test framework. If I had left the refactoring for later stage I would have never got another opportunity to work on that part of the code but the part I really wanted to avoid was leaving the code with &lt;code&gt;if..else&lt;/code&gt; which is really hard to understand after some time like for e.g. why was this different? why I am converting variable to &lt;code&gt;int&lt;/code&gt; and sometimes to &lt;code&gt;float&lt;/code&gt;? or some similar questions. Of course, I can add comments but how many such comments one can add?&lt;/p&gt;

&lt;p&gt;From a regular development environment, I should have raised separate PR but while working in a QA, with stringent timelines I think going ahead with single PR with "unplanned" changes was the right call! &lt;/p&gt;

&lt;p&gt;Just snippet of what code looked like (all are made up fields), and what I refactored it into... &lt;/p&gt;

&lt;h3&gt;
  
  
  Old Way
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# checking request against response or some constants
&lt;/span&gt;
&lt;span class="nf"&gt;assert_equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;assert_equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;assert_equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;checksum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;get_checksum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DEV&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;assert_true&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;respone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;assert_ts_in_range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tolerance_in_sec&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  New way
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;assertor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_msg_assertor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# class based
&lt;/span&gt;
&lt;span class="n"&gt;assertor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;assertor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;assertor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;checksum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;get_checksum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;assertor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  &lt;span class="c1"&gt;# DEV will just check for presence and UAT will check for tolerance
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>developer</category>
      <category>pr</category>
      <category>developersitch</category>
    </item>
  </channel>
</rss>
