<?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: Mihai-Alexandru Soare</title>
    <description>The latest articles on DEV Community by Mihai-Alexandru Soare (@atomicul).</description>
    <link>https://dev.to/atomicul</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4132993%2F6c5a4615-060a-4b54-adbe-bb2350f32192.jpg</url>
      <title>DEV Community: Mihai-Alexandru Soare</title>
      <link>https://dev.to/atomicul</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/atomicul"/>
    <language>en</language>
    <item>
      <title>Is the joy of programming dead? We debate losing jobs, but we are definitely losing satisfaction.</title>
      <dc:creator>Mihai-Alexandru Soare</dc:creator>
      <pubDate>Sat, 19 Sep 2026 14:28:36 +0000</pubDate>
      <link>https://dev.to/atomicul/is-the-joy-of-programming-dead-we-debate-losing-jobs-but-we-are-definitely-losing-satisfaction-mai</link>
      <guid>https://dev.to/atomicul/is-the-joy-of-programming-dead-we-debate-losing-jobs-but-we-are-definitely-losing-satisfaction-mai</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;The practice of typing out code at the keyboard is losing popularity. In today's&lt;br&gt;
era, we rarely write a feature from scratch, but rather generate functions and&lt;br&gt;
modules and the like, then iterate over that, either by hand or through more&lt;br&gt;
prompting. Regardless of whether you touch up on the code manually or end up&lt;br&gt;
getting a good enough result only by prompting, you lose the capacity to style&lt;br&gt;
the code with the granularity you would have had had you written the code on&lt;br&gt;
your own. This matters less in routine features like a CRUD endpoint in a&lt;br&gt;
project where the overall code style is established, but I argue that for small&lt;br&gt;
scope implementations, like a single function or class, there is some joy in&lt;br&gt;
bootstrapping them like the old times, a practice that is no longer justified in&lt;br&gt;
the current market.&lt;/p&gt;

&lt;p&gt;In the coming paragraphs, I will present a DSA problem I overengineered on&lt;br&gt;
accident, the strong points that the implementation had over the book approach,&lt;br&gt;
and why it makes even less sense in the present day to ship an implementation&lt;br&gt;
like that (at least from the business perspective), now that we have AI tools.&lt;/p&gt;

&lt;p&gt;Before getting to the next section, I would like to present myself in order to&lt;br&gt;
give some context about my background and interests. I am a computer science&lt;br&gt;
student in my 2nd year of university. I worked for a short 6 months at a&lt;br&gt;
consulting company + some 4-week internships at that very same company. I got&lt;br&gt;
into programming at the young age of 12 because I was and remain passionate&lt;br&gt;
about creating things, but I have always felt a stronger connection to the&lt;br&gt;
practice of building and the craft itself than to the finished product.&lt;/p&gt;
&lt;h2&gt;
  
  
  Unconventional solution I got to
&lt;/h2&gt;

&lt;p&gt;As I was preparing for coding interviews, I was using the 'select random'&lt;br&gt;
feature on LeetCode and stumbled over this basic string problem: Find the&lt;br&gt;
longest substring without duplicated characters.&lt;/p&gt;

&lt;p&gt;One approach to this problem is to keep two pointers of a sliding window, and&lt;br&gt;
also a hash set of the characters in that window in order to check for&lt;br&gt;
duplicates in O(1) time when advancing a pointer. In plain English, the&lt;br&gt;
algorithm works as follows. Take two indices left, right = 0, and a hash set s =&lt;br&gt;
{}. While the window is in bounds of the string, increment the right pointer. If&lt;br&gt;
the letter that joined the window is a duplicate, you then start to increment&lt;br&gt;
the left pointer until its duplicate is no longer part of the window. The&lt;br&gt;
solution is the maximum width the window had during the slide. The only little&lt;br&gt;
caveat is you had to keep the set in sync with the pointers.&lt;/p&gt;

&lt;p&gt;Here is the first thing I typed on LeetCode:&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;Solution&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;lengthOfLongestSubstring&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;s&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="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="c1"&gt;# non inclusive
&lt;/span&gt;        &lt;span class="n"&gt;letters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;set&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;eject_letter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;letter&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="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;letter&lt;/span&gt;&lt;span class="p"&gt;)&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="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&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;letter&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;letters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt;

            &lt;span class="k"&gt;nonlocal&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;
            &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;lt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                &lt;span class="n"&gt;letters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;lt&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;letter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="k"&gt;break&lt;/span&gt;

        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;expand_window&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="k"&gt;nonlocal&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;&amp;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;s&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;StopIteration&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

            &lt;span class="n"&gt;lt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="nf"&gt;eject_letter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;letters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sizes&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;while&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;yield&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;letters&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="nf"&gt;expand_window&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;StopIteration&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;return&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sizes&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is influenced by the OOP idea of encapsulating the state and implementing an&lt;br&gt;
API that protects the invariants of the enclosed state (I will explain this in&lt;br&gt;
detail later). The only thing is that instead of a class in the same namespace,&lt;br&gt;
I use closures.&lt;/p&gt;

&lt;p&gt;This is the most direct way that I could turn the semantics of the algorithm&lt;br&gt;
described above into Python syntax.&lt;/p&gt;

&lt;p&gt;I also asked Gemini to generate a solution to the problem:&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;Solution&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;lengthOfLongestSubstring&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;s&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="n"&gt;seen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="n"&gt;max_len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;char&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;char&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;seen&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;seen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
                &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
            &lt;span class="n"&gt;seen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;char&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;max_len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;left&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;max_len&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I am not a fool, alright? I knew that my solution is on the higher end when it&lt;br&gt;
comes to line count, but I didn't expect the book solution to be this compact.&lt;br&gt;
And honestly, besides some vertical padding I would add between the shrinking,&lt;br&gt;
growing, and computing of max_len, this is what I would ship in practice.&lt;/p&gt;

&lt;p&gt;All in all, there are still some strong points to my implementation:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The state is mutated by the trivial shrinking and growing closures. Both
implementations make the assumption that the hash set contains the
characters in the window. But in the AI implementation, this is only true
after &lt;code&gt;seen.add(char)&lt;/code&gt; is used. In theory, if you had to modify the code,
you could overlook this caveat and modify a pointer without updating the set
and vice versa. One benefit of encapsulating the state with closures is that
the invariants in the state are preserved in the code that calls those
closures.&lt;/li&gt;
&lt;li&gt;The steps of the algorithm are naturally labeled and isolated.
It is very apparent that we are taking the maximum of the lengths as we grow
the window and preserve the no-duplicate constraint.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now pretend that typing out code was the only way to implement such a simple DSA&lt;br&gt;
problem. The time it takes to implement the two are very close, given that for&lt;br&gt;
the book solution, I would first have to think about how all the logic comes&lt;br&gt;
together in that loop and validate that indeed it works as I originally&lt;br&gt;
expected. Could you justify opening a PR with the more verbose implementation?&lt;br&gt;
Well, you could counter point 1 by arguing that the function is a very small&lt;br&gt;
architectural unit, and you have unit tests at that level anyway, so even if&lt;br&gt;
requirements changed and you had to modify the solution, it would be very&lt;br&gt;
realistic to tear it down fully and start anew. But point 2 is still very much&lt;br&gt;
true. You don't need to be familiar with the sliding window approach to quickly&lt;br&gt;
follow what is happening in the implementation, it makes it easier to spot bugs&lt;br&gt;
and validate conceptually before writing tests that the code does what it is&lt;br&gt;
supposed to.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;ASIDE: raising StopIteration, code smell?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The astute reader will have noticed the unconventional use of &lt;code&gt;StopIteration&lt;/code&gt;&lt;br&gt;
in the &lt;code&gt;expand_window&lt;/code&gt; closure. The exception exists in order for use with&lt;br&gt;
class based iterators and is only meant to be raised inside the &lt;code&gt;__next__&lt;/code&gt;&lt;br&gt;
method. Still, I decided to use it there because the name conveys exactly&lt;br&gt;
what I meant to achieve. This sort of controversial decision is another&lt;br&gt;
sign of human originality that an AI would not make, for better or worse.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  It no longer matters anyway
&lt;/h2&gt;

&lt;p&gt;Now we relax that unrealistic assumption. You prompt the AI and get a solution&lt;br&gt;
that is good enough. In my opinion, the generated solution to this problem is&lt;br&gt;
better than the one I originally wrote because I believe the simplicity of it&lt;br&gt;
beats the benefits of mine that I listed above. Even still, there are cases&lt;br&gt;
where I would have picked the other way around, so pretending that there is a&lt;br&gt;
more optimal code you would have written yourself, you have a good enough&lt;br&gt;
working solution passing acceptance criteria and tests. It is not worth it to&lt;br&gt;
micro-optimize it to fit your expectations.&lt;/p&gt;

&lt;p&gt;And there is another reason to lower the bar when it comes to implementations.&lt;br&gt;
Humans are prone to human error. But AIs don't make the same types of mistakes;&lt;br&gt;
an AI rarely makes a typo or forgets to update a variable. That being said, it&lt;br&gt;
is easier to tolerate code of poor quality. It was shown that after the rise of&lt;br&gt;
LLMs, teams refactor less frequently. [1]&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing thoughts
&lt;/h2&gt;

&lt;p&gt;It's a sad era for creatives, in the world driven by profit and in the presence&lt;br&gt;
of generative AI, it doesn't always sell to be very nitpicky about your craft.&lt;br&gt;
But it is not true for most hobbies that they also make a profitable career, and&lt;br&gt;
I believe that we as software engineers still have it pretty good. After all,&lt;br&gt;
coding is not all there is to software engineering; there is a lot of demand for&lt;br&gt;
elegance in high-level solution architecture and auxiliary automation. While&lt;br&gt;
handwriting is losing appreciation, there is still designing to be done at the&lt;br&gt;
code level, picking which dependencies to use, what interface and how you test&lt;br&gt;
it, etc. And it also may be that I am too pessimistic writing this article;&lt;br&gt;
perhaps there are still contexts in which you really want to be nitpicky about&lt;br&gt;
your implementation, after all, code comprehension is a requirement that isn't&lt;br&gt;
going anywhere in the near future.&lt;/p&gt;

&lt;p&gt;[1] AI Copilot Code Quality: 2025 Look Back at 12 Months of Data -&lt;br&gt;
&lt;a href="https://www.gitclear.com/ai_assistant_code_quality_2025_research" rel="noopener noreferrer"&gt;https://www.gitclear.com/ai_assistant_code_quality_2025_research&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;- Mihai-Alexandru Soare, &lt;a href="https://soare.io/" rel="noopener noreferrer"&gt;soare.io&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>python</category>
      <category>discuss</category>
    </item>
  </channel>
</rss>
