<?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: András Tóth</title>
    <description>The latest articles on DEV Community by András Tóth (@latobibor).</description>
    <link>https://dev.to/latobibor</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%2F368510%2F0e824261-6d1a-471b-8cc1-87f40e18f34e.jpeg</url>
      <title>DEV Community: András Tóth</title>
      <link>https://dev.to/latobibor</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/latobibor"/>
    <language>en</language>
    <item>
      <title>Tech Zen Wisdom: Abstraction</title>
      <dc:creator>András Tóth</dc:creator>
      <pubDate>Tue, 01 Jul 2025 03:12:54 +0000</pubDate>
      <link>https://dev.to/latobibor/tech-zen-wisdom-abstraction-22po</link>
      <guid>https://dev.to/latobibor/tech-zen-wisdom-abstraction-22po</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;One cannot be angry at reality, one can only be angry at one's own abstractions.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>programming</category>
      <category>zen</category>
    </item>
    <item>
      <title>The Anatomy of a Software Engineer</title>
      <dc:creator>András Tóth</dc:creator>
      <pubDate>Sat, 26 Apr 2025 23:52:22 +0000</pubDate>
      <link>https://dev.to/latobibor/the-anatomy-of-a-software-engineer-58ma</link>
      <guid>https://dev.to/latobibor/the-anatomy-of-a-software-engineer-58ma</guid>
      <description>&lt;p&gt;Software development is a lot more than knowing a couple of programming languages, popular libraries or to be able to traverse a &lt;em&gt;binary tree&lt;/em&gt; in a job interview. It's crucial for product managers, team leads, engineering managers, and basically anyone making decision over engineers, to know how to mix and match expertise inside a company to unlock true productivity.&lt;/p&gt;

&lt;p&gt;I dedicate this article to both product managers and software engineers in hope that we get to understand each other better and we can be more productive simply by strategically utilizing knowledge and expertise and avoid blunders like &lt;a href="https://dev.to/latobibor/impostor-syndrome-burn-out-interview-with-an-ex-faang-employee-2dha"&gt;keeping talented people perpetually inexperienced&lt;/a&gt; by making them constantly switch languages/tech/teams and products.&lt;/p&gt;

&lt;p&gt;As there is &lt;strong&gt;reusable&lt;/strong&gt; and &lt;strong&gt;non-reusable code&lt;/strong&gt;, I will classify engineering knowledge into &lt;strong&gt;reusable&lt;/strong&gt; and &lt;strong&gt;non-reusable&lt;/strong&gt; categories. &lt;/p&gt;

&lt;p&gt;By &lt;strong&gt;reusable&lt;/strong&gt; I mean the normal definition everyday definition it: if you learn how to cook in a country most likely you'll figure it out in another country.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Non-Reusable Knowledge
&lt;/h2&gt;

&lt;p&gt;Let's start with what I consider "non-reusable" as these categories are all about detail and gotchas. The quirks of Linux won't transfer when you work with IIS (Internet Information Services) of the Windows ecosystem for example. Let's get to the details!&lt;/p&gt;

&lt;h3&gt;
  
  
  Knowing a Programming Language
&lt;/h3&gt;

&lt;p&gt;I consider the details of a programming language "non-reusable" as the &lt;em&gt;syntax&lt;/em&gt; of a language cannot really be used again - unless the other language is almost the same. It's much easier to jump from &lt;code&gt;Java&lt;/code&gt; to &lt;code&gt;C#&lt;/code&gt; than from &lt;code&gt;JavaScript&lt;/code&gt; to &lt;code&gt;Rust&lt;/code&gt;. In the latter case you need to relearn keywords, rules, gotchas, and indentation, best practices, anti-patterns... Not to mention package managers and the strengths and weaknesses in the ecosystem (e.g. which input validation library to choose).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 When moving around engineers for a project, consider that lhe less similar two languages are, the more time they will need to write intelligent code.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For instance ixn &lt;code&gt;JavaScript&lt;/code&gt;, the idea that the &lt;code&gt;this&lt;/code&gt; keyword of a &lt;code&gt;function&lt;/code&gt; is a freely attachable context, and not a pointer to the object containing said &lt;code&gt;function&lt;/code&gt;, cannot really be reused in another language; it's a one-time quirk. Once you abandon &lt;code&gt;JavaScript&lt;/code&gt; that knowledge will be lost (or you can bore young colleagues in the future about it).&lt;/p&gt;

&lt;p&gt;However, the more familiar you become with the deep features of a language, you'll know what to search/ask for when you learn a new language and can get productive a lot quicker as opposed to be a newbie. It took me little time to refactor and low-key optimize the code of data analysts when I had a Python assignment; they knew how to crunch the data, I knew how to avoid typical coding mistakes. See more about this in the next section!&lt;/p&gt;

&lt;h3&gt;
  
  
  The Ecosystem of a Language
&lt;/h3&gt;

&lt;p&gt;The ecosystem of a language refers to the modules or packages available — like &lt;code&gt;react&lt;/code&gt;, &lt;code&gt;express.js&lt;/code&gt;, or &lt;code&gt;SQLAlchemy&lt;/code&gt; for &lt;code&gt;Python&lt;/code&gt; — that are typically accessible through a package management system, such as &lt;code&gt;npm&lt;/code&gt;, &lt;code&gt;pip&lt;/code&gt;, or &lt;code&gt;NuGet&lt;/code&gt; for &lt;code&gt;.NET&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This knowledge accumulates slowly through years of trial and error, getting lucky or getting burnt with someone else's code. In some ecosystems you absolutely should not reinvent the wheel by reimplementing what's out there; in others you might encounter abandoned projects or missing important libraries and you'll have to roll your sleaves up. &lt;/p&gt;

&lt;p&gt;Even if you're not changing languages during your career, frameworks change often as well: libraries like &lt;code&gt;Angular&lt;/code&gt; or &lt;code&gt;firebase&lt;/code&gt; get rewritten with a new design goal, so this type of knowledge also tend to get lost with version changes.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Consider the ecosystem when moving people around in a company! This knowledge cannot be externally obtained through search engine queries or asking one of the LLMs.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Going back to my Python assignment, while I was getting their code cleaner, I needed lots of help for all the things that were unique to Python, like setting up &lt;code&gt;pip&lt;/code&gt;, the package manager and development environment. The analysts colleagues who had significant amount of experience with the basics were very helpful dealing with this.&lt;/p&gt;

&lt;h3&gt;
  
  
  Platform-specific Gotchas
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Languages and ecosystems do not exist in a vacuum&lt;/strong&gt;. There is an operating system or sandbox around them (for example, &lt;code&gt;MacOS&lt;/code&gt;, &lt;code&gt;Firefox&lt;/code&gt;, or a particular &lt;code&gt;Android&lt;/code&gt; version). The medium our code runs in dictates how we write things. Here are a few examples of these type of gotchas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Some older browsers won't be able to process certain newer &lt;code&gt;UTF&lt;/code&gt; encodings and completely drop rendering the page.&lt;/li&gt;
&lt;li&gt;Working on a &lt;code&gt;react-native&lt;/code&gt; project chasing mysterious Android crashes, I needed to get familiar using  &lt;code&gt;logcat&lt;/code&gt; from &lt;code&gt;Android Studio&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;I had horrible, non-reproducible failures for timeout related tests. Turned out that the virtual machine had its internal clock &lt;em&gt;out of sync&lt;/em&gt; with real world time. It took me 2 days of bug hunting figuring this out.&lt;/li&gt;
&lt;li&gt;Running two tasks in series with &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; is the standard on a Mac, but it won't work on &lt;code&gt;Windows&lt;/code&gt;; hence the existence of &lt;a href="https://dev.tonpm-run-all"&gt;https://github.com/mysticatea/npm-run-all&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These can only be learned by paying the &lt;strong&gt;"iron price"&lt;/strong&gt;: struggling through mysteries, scrolling through &lt;strong&gt;GitHub&lt;/strong&gt; issues, and asking for help. You can be stuck debugging these for days from time to time!&lt;/p&gt;

&lt;p&gt;Therefore, this experience is a very important part of engineering and crucial for having real productivity! Sadly much of this knowledge starts from zero whenever engineers are reassigned across platforms.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Platform-specific knowledge can make or break releases!&lt;/strong&gt; Make sure you not only have enough engineers but to have experts on the platform you're building for.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The cross-platform framework &lt;code&gt;react-native&lt;/code&gt; is a great example to illustrate this point. You can't just grab 5 JavaScript engineers and put them on a &lt;code&gt;react-native&lt;/code&gt; project if none of them have mobile development experience.&lt;/p&gt;

&lt;p&gt;Having a &lt;strong&gt;team member&lt;/strong&gt; who scores high on &lt;code&gt;platform-specific experience&lt;/code&gt; is able to defuse future landmines that others would not even know to look for. It's much cheaper if way before release that expert engineer exclaims in a meeting that something won't work than pulling back an embarassing failure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Invaluable Product/Domain Knowledge
&lt;/h3&gt;

&lt;p&gt;When working at one company and one product for years engineers get to know the user base, their needs, the problems they face. They would also know the code inside-out.&lt;/p&gt;

&lt;p&gt;There is of course more general and more concrete domain knowledge. For example once you fixed your first internet reconnection bug in single page application you would expect the same to be a problem in mobile apps as well, while you can't really transfer your intricate knowledge about the details of GDPR regulations to your new job in car manufacturing.&lt;/p&gt;

&lt;p&gt;Engineers that spend significant amount of time on one product, one aspect, usually become living encyclopedias of both the product and how it works. They become the "go-to" people when someone has a hunch but not unsure and they can know more about certain topics than the product manager of the team.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Therefore, the domain and product knowledge of engineers is crucial for company success! This &lt;em&gt;local expertise&lt;/em&gt; can be easily &lt;strong&gt;lost&lt;/strong&gt; with arbitrary layoffs, denied salary raises or moving team members frequently around.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can be a senior in a programming language but an absolute junior on a new product.&lt;/p&gt;

&lt;p&gt;Internal tools, special configurations, rules coming from your special group of users are contributing to a local knowledge that is really hard to get external help for.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;👆 Let me emphasize this a bit more: you cannot ask ChatGPT or from online forums about how your product and codebase works!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Personal example
&lt;/h3&gt;

&lt;p&gt;I've had a &lt;a href="https://dev.to/latobibor/tech-stories-make-me-a-microservice-architecture-but-whats-the-product-54dh"&gt;project&lt;/a&gt; where the company selected around 60 C# professionals familiar with support and remote connection to an IoT project and then changed the project to be node.js microservice one because of appeal to investors. This is where we lost all language knowledge, we weren't familiar with the node.js ecosystem, we had no experience with internet enabled devices and their quirks, we had new teams so interpersonal knowledge was also lost.&lt;/p&gt;

&lt;p&gt;The product this many people built for a year got scrapped (and then again I heard) and rewritten from scratch when relevant pieces of experience both from product and engineering side got there.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reusable Knowledge
&lt;/h2&gt;

&lt;p&gt;Now let's focus on the good things: what an engineer can bring from one assignment to another.&lt;/p&gt;

&lt;h3&gt;
  
  
  Engineering Principles and Instinct
&lt;/h3&gt;

&lt;p&gt;Luckily, most of the principles of popular paradigms are quite reusable: &lt;strong&gt;clean coding&lt;/strong&gt;, the &lt;code&gt;SOLID&lt;/code&gt; principles, design patterns and anti-patterns, the test pyramid, the art of discarding unnecessary layers (in other words: avoiding overengineering)... All help you to be critical during your work. &lt;/p&gt;

&lt;p&gt;There's also what I call &lt;em&gt;pure instinct&lt;/em&gt;, the ability to play around with a bit of code and tell if it needs more work or not. You develop your subconscious skills by working with both elegant and terrible codebases, and after a while you will just see when something is overcomplicated or off.&lt;/p&gt;

&lt;p&gt;It is also knowing what to &lt;em&gt;reuse&lt;/em&gt; and what &lt;em&gt;not to reuse&lt;/em&gt;, what code to repeat and what code to move into its own module. It's your ability to &lt;a href="https://martinfowler.com/bliki/CodeSmell.html" rel="noopener noreferrer"&gt;smell the code&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;To give another personal example, when I had to fix a data engineer's Python code, even as a Python newbie, I immediately searched for a better way to replace variables in a string than positional &lt;code&gt;%s&lt;/code&gt; signs that are prone to silly mistakes (like putting &lt;code&gt;address&lt;/code&gt; in place of &lt;code&gt;firstName&lt;/code&gt; when the amount of data passed changes):&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;# original version was something like this
&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;SELECT %s FROM %s WHERE id = %s&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="o"&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;my_table&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# versus
&lt;/span&gt;
&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;SELECT {column_name} FROM {table_name} WHERE id = {id}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;table_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;my_table&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;column_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;name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Did you notice that in the first version the order 
# of the arguments passed is wrong? Not likely to happen in
# the second version - it would look odd immediately
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As it turned out, there was already a syntax for &lt;code&gt;named placeholders&lt;/code&gt;, which is superior with its clear indication of what each property means, therefore changing the order of parameters will not have consequences.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This is the most reusable knowledge.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It also helps you with the adoption of a new language: you know what to put into the search bar to find exactly what you need.&lt;/p&gt;

&lt;p&gt;💡 Tip of the day: &lt;a href="https://www.amazon.com/Head-First-Design-Patterns-Brain-Friendly/dp/0596007124" rel="noopener noreferrer"&gt;Head First Design Patterns&lt;/a&gt; is a book seemingly about &lt;code&gt;Java&lt;/code&gt;, but in reality, it gives you the &lt;em&gt;why&lt;/em&gt; of every pattern and you can learn a lot about principles that are useful in other languages. It's not just for object-oriented programmers!&lt;/p&gt;

&lt;h3&gt;
  
  
  Problem Solving Skills and Engineering Instinct
&lt;/h3&gt;

&lt;p&gt;One of the distinguishing feature of a truly senior developer is to look holistically at feature requests. It's no longer &lt;em&gt;"just another button in the menu"&lt;/em&gt;. The experienced eye would look for potential clashes, think about small monitors, mental load of the user, consider UX practices and anti-patterns. &lt;/p&gt;

&lt;p&gt;There are also ways of how to approach nasty problems, like tracking down a crash without any useful clues by progressively commenting out parts of the codebase. Or engineers can develop an eye of spotting scaling issues like &lt;em&gt;"Well, with a 100 users this is not a problem, but we're going to be stuck when we have 10000!"&lt;/em&gt;. Or tricks, like inverting the problem statement, brainstorming hacks, and so on.&lt;/p&gt;

&lt;p&gt;Finally they would know what requirements to implement to the letter and what requirements need more investigation. Or where and how to look up data to support or disprove assumptions.&lt;/p&gt;

&lt;p&gt;For example a story can be making a sizable chunk of the knowledge base available for non-registered users. If the task requires significant changes, it might worth looking into the data; if it turns out that 99% of the users are logged in, then maybe you can skip an unnecessary and expensive feature.&lt;/p&gt;

&lt;p&gt;This is readily reusable knowledge, and to some extent can be enhanced with special training sessions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Personal Productivity Management
&lt;/h3&gt;

&lt;p&gt;This ranges from getting the most out of your &lt;code&gt;IDE&lt;/code&gt; to organizing your day effectively. It also includes knowing when to push through a problem regardless of time versus when to go home when you're mentally done for the day. Or when to politely decline meetings to stay in flow! This is also knowing your own limits, understanding the resting requirements of your body, to have rituals to reset your brain.&lt;/p&gt;

&lt;h3&gt;
  
  
  Growing Lasting Knowledge
&lt;/h3&gt;

&lt;p&gt;Alongside classics like algorithms, object-oriented programming, design patterns and so on I have learnt &lt;code&gt;SQL&lt;/code&gt;, &lt;code&gt;HTML&lt;/code&gt; and &lt;code&gt;CSS&lt;/code&gt; at the university. I still use these languages to this day while I have learnt and forgotten popular libraries like &lt;code&gt;Angular&lt;/code&gt; for the frontend or &lt;code&gt;Prisma&lt;/code&gt; ORM for the backend. &lt;/p&gt;

&lt;p&gt;The important takeaway is to spend time on the basics and not to skipping them just because you have that trendy framework that hides that from you. Otherwise you are setting yourself up for a bitter loss of knowledge in a couple of years.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Having only trending tech in a team is a red-flag and vulnerability!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Therefore any reasonable engineer/manager should think about investing into the lasting knowledge.&lt;/p&gt;

&lt;h3&gt;
  
  
  Communication Skills and Solving the Problem at the Right Level
&lt;/h3&gt;

&lt;p&gt;Let's not forget about soft skills! &lt;/p&gt;

&lt;p&gt;A well-versed senior software engineer have experienced different methodologies, problem solving tricks. Hopefully by this time in their career they became excellent team players: hard stance where it matters, agreeable where it doesn't.&lt;/p&gt;

&lt;p&gt;Let's say you are having a heated argument over the way IMEI number from the phone is to be collected in the application. One way possibly takes 2 weeks to implement. However, someone raises their hand and says: &lt;em&gt;"Hey, let's ask legal team if we can actually collect that information from a user!"&lt;/em&gt;. This is yet another engineering instinct that comes from being exposed to multi-faceted problems.&lt;/p&gt;

&lt;p&gt;On the communication side, learning to be context aware, know when and how to explain technical concepts to non-technical people and so on. Or learning that the loudest people are not always right and you have to ask each team member one by one to get the full picture.&lt;/p&gt;

&lt;p&gt;Then there's considering the entire team from business owners to data analysts. You can vibe-code refactor the entire codebase in a caffeine fuelled late night sprint, however if the new code completely replaces analytical event names and properties then your data analysts and your business team will get absolutely understandably angry.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;I hope that this article was enjoyable and helpful for managing teams or your own future career in engineering! During my career I have encountered many cases where &lt;a href="https://dev.to/latobibor/tech-stories-make-me-a-microservice-architecture-but-whats-the-product-54dh"&gt;leadership had very naive expectations over productivity&lt;/a&gt;, coming from not knowing how engineering and engineers worked.&lt;/p&gt;

&lt;p&gt;I also hope that I nudge existing or prospecting team leads, product managers and CTOs to map out differen types of expertise in their teams and to be strategic about nurturing local knowledge. Check this interview I did with a friend about &lt;a href="https://dev.to/latobibor/impostor-syndrome-burn-out-interview-with-an-ex-faang-employee-2dha"&gt;what happens when someone can never reach a deep expertise&lt;/a&gt; while she was always doing what was requested.&lt;/p&gt;

</description>
      <category>management</category>
      <category>leadership</category>
      <category>programming</category>
    </item>
    <item>
      <title>Refactoring Towards Pure Functions</title>
      <dc:creator>András Tóth</dc:creator>
      <pubDate>Fri, 11 Apr 2025 10:46:22 +0000</pubDate>
      <link>https://dev.to/latobibor/refactoring-towards-pure-functions-4cjc</link>
      <guid>https://dev.to/latobibor/refactoring-towards-pure-functions-4cjc</guid>
      <description>&lt;p&gt;In one of my articles a commenter wrote that he was &lt;em&gt;"in general, refactoring towards pure functions"&lt;/em&gt;. Now, usually the word "towards" does not lend itself to bold statements, but I grew fond of the expression because it expresses &lt;em&gt;precisely&lt;/em&gt; a couple of things that I rarely read or hear about.&lt;/p&gt;

&lt;h2&gt;
  
  
  Black and White Thinking
&lt;/h2&gt;

&lt;p&gt;Before I get into specifics, this article has a message: black-and-white thinking about paradigms is costing us code quality. In other words forcing &lt;em&gt;one&lt;/em&gt; paradigm onto a varied set of problems will result in over- or underengineering.&lt;/p&gt;

&lt;p&gt;As I wrote in my previous article &lt;a href="https://dev.to/latobibor/do-you-need-classes-in-jsts-2025-version-j46"&gt;Do you need classes in JS/TS?&lt;/a&gt;, when you have state to persist between calls and it's not trivial to manage that, using a &lt;code&gt;class&lt;/code&gt; (or an equivalent object + scope combo) is the right way. It's akin to serving your dish with the appropriate cutlery (note that in JavaScript people can eat with their hands regardless of your attempts to neatly tuck things away - see also &lt;em&gt;"monkey patching"&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;I maintain that even in a mostly functional codebase, if you encounter this particular problem, you're better off using a &lt;code&gt;class&lt;/code&gt; than creating convoluted functional workarounds.&lt;/p&gt;

&lt;p&gt;That's why I like the term &lt;em&gt;"refactoring towards pure functions"&lt;/em&gt;! We try to convert everything into a &lt;strong&gt;pure function&lt;/strong&gt;, but if that results in something awkward or it just complicates the code, we keep what we have - or even rewrite it in OO-style!&lt;/p&gt;

&lt;h2&gt;
  
  
  Spotting a Useless Class
&lt;/h2&gt;

&lt;p&gt;With the mindset of turning everything into &lt;strong&gt;pure functions&lt;/strong&gt;, I began finding patterns of useless &lt;code&gt;classes&lt;/code&gt; - ones that just complicate things without leveraging what a &lt;code&gt;class&lt;/code&gt; could offer.&lt;/p&gt;

&lt;p&gt;Here is my simple algorithm to spot and remove such classes, hopefully resulting in a cleaner code base!&lt;/p&gt;

&lt;h3&gt;
  
  
  A &lt;code&gt;class&lt;/code&gt; Without Methods
&lt;/h3&gt;

&lt;p&gt;If a &lt;code&gt;class&lt;/code&gt; has no &lt;code&gt;methods&lt;/code&gt; then, it's just you a POD (plain-old-data) structure. You can simply use your everyday JS object: &lt;code&gt;{}&lt;/code&gt; (of course you should define its &lt;code&gt;type&lt;/code&gt; in &lt;code&gt;TypeScript&lt;/code&gt;).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;occupation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;firstName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lastName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;occupation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;occupation&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// we have no methods here&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;onePerson&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Edward&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Elric&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Alchemist&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Instead, simply:&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;SimplerPerson&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;occupation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;otherPerson&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SimplerPerson&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Alphonse&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Elric&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;occupation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Alchemist&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Notice that the second solution is more descriptive!&lt;/span&gt;
&lt;span class="c1"&gt;// If you make a mistake and pass "Alchemist" to "firstName",&lt;/span&gt;
&lt;span class="c1"&gt;// seeing the label "firstName" will alert you or the reviewer&lt;/span&gt;
&lt;span class="c1"&gt;// that something is off.&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;(You might have a special case where you may want to use a &lt;code&gt;class&lt;/code&gt; for relying on &lt;code&gt;instanceof&lt;/code&gt;, but I can provide an alternative for that in TypeScript - would you rise up for the challenge in the comments? 😉).&lt;/p&gt;

&lt;h3&gt;
  
  
  A &lt;code&gt;class&lt;/code&gt; Without (Serious) Members
&lt;/h3&gt;

&lt;p&gt;Any &lt;code&gt;method&lt;/code&gt; of the &lt;code&gt;class&lt;/code&gt; that doesn't use &lt;code&gt;this&lt;/code&gt; (or doesn't us this &lt;em&gt;seriously&lt;/em&gt;) can be moved into a standalone &lt;code&gt;function&lt;/code&gt;. By "seriously", I mean the members on &lt;code&gt;this&lt;/code&gt; are not just there to "avoid taking arguments" (see below to get what I mean!).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Operations&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// These methods never access `this` — they’re just pure functions!&lt;/span&gt;
  &lt;span class="nf"&gt;multiply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;multiply&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// While I usually dislike using _named_ unnamed functions,&lt;/span&gt;
&lt;span class="c1"&gt;// they're perfect for 1-liners!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While this one was trivial, often this pattern appears in a more concealed way. See this variety: arguments are shoveled into the &lt;code&gt;constructor&lt;/code&gt; and we dig them back out in the methods - without ever changing them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;StringValidator&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;sanitizeString&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;+/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;isEmpty&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;boolean&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// This class has no real internal state!&lt;/span&gt;
&lt;span class="c1"&gt;// We don't modify its internal state ever!&lt;/span&gt;
&lt;span class="c1"&gt;// The constructor just passes a value, and the methods act on it.&lt;/span&gt;
&lt;span class="c1"&gt;// Moreover, there's low cohesion — the methods don't rely on each other.&lt;/span&gt;

&lt;span class="c1"&gt;// Instead you can replace them with two pure functions:&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;sanitizeString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;+/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;isEmptyString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Observing the Result
&lt;/h3&gt;

&lt;p&gt;Now, take a look at what's left of the original &lt;code&gt;class&lt;/code&gt;! If you see either of the patterns shows up, continue pulling out data or functions.&lt;/p&gt;

&lt;p&gt;Eventually, either your &lt;code&gt;class&lt;/code&gt; disappeared already or it has a tightly-knit set of &lt;code&gt;variables&lt;/code&gt; and &lt;code&gt;methods&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;👆 You may also want to consider splitting large &lt;code&gt;classes&lt;/code&gt; using &lt;a href="https://steven-giesel.com/blogPost/d0784f04-fe7a-4426-bdb7-314d0f9e1b6b" rel="noopener noreferrer"&gt;&lt;code&gt;class&lt;/code&gt; cohesion&lt;/a&gt;: if you have disjunct sets of &lt;code&gt;methods&lt;/code&gt; and &lt;code&gt;variables&lt;/code&gt; they can go into their own classes.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The true benefit a &lt;code&gt;class&lt;/code&gt; provides is access to &lt;code&gt;this&lt;/code&gt;. If a method doesn’t use it, or just passes arguments around, then a function is likely more appropriate.&lt;/p&gt;

&lt;h3&gt;
  
  
  Working Backwards from Usage
&lt;/h3&gt;

&lt;p&gt;You can also spot unnecessary classes by looking at how they're used. A big clue can be &lt;em&gt;one-time usage&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;Here's what I spotted recently:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;transformDataAndSendEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;recipient&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;someData&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SomeData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mailDocument&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;formatSomeData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;someData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Why insantiate an entire that's discarded immediately?&lt;/span&gt;
  &lt;span class="c1"&gt;// Where's the persisting state we need to manage between calls?&lt;/span&gt;
  &lt;span class="k"&gt;await &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MailService&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;sendMail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;recipient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mailDocument&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you see &lt;code&gt;MailService&lt;/code&gt; is not a real "service" waiting in memory to handle further requests. It holds no state. It's just extra steps and bureaucracy to reach one function, and it'll be garbage collected right after.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cleaning Up a Long Component (React)
&lt;/h2&gt;

&lt;p&gt;We can extract pure (or purish) functions not only from classes but from any large code block, as long as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We can isolate arguments with a little effort,&lt;/li&gt;
&lt;li&gt;Avoid mutating them,&lt;/li&gt;
&lt;li&gt;Same input yields the same output*,&lt;/li&gt;
&lt;li&gt;With clear output values.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note(*): there are obvious exceptions, for example if you have to use &lt;code&gt;Math.random()&lt;/code&gt;. My advice is: don't fret about theoretical correctness if the logic can be neatly extracted, just know about it when you need it.&lt;/p&gt;

&lt;p&gt;It's ingrained in many React developers that a component must contain &lt;em&gt;everything&lt;/em&gt; for rendering — either via props or hooks. This is an anti-pattern resulting in breaking the Single Responsibility Principle, not to mention the mental load of juggling &lt;em&gt;huge&lt;/em&gt; components.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;parseTimeRange&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;date-lib-of-the-day&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ArticleProps&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;articleId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;PostTime&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;articleId&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;ArticleProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;article&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useArticle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;articleId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;translate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useTranslator&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// other hook calls, etc.&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;ago&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;articleCreationTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;timePassed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;articleCreationTime&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;parsedRange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parseTimeRange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timePassed&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;parsedRange&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;year&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// ay-ay, we have to translate!&lt;/span&gt;
      &lt;span class="c1"&gt;// On top of everything, "translate" function comes from a hook!&lt;/span&gt;
      &lt;span class="c1"&gt;// 🥲 - all hope is lost!&lt;/span&gt;
      &lt;span class="nx"&gt;ago&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;translate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;parsedRange&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;year&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;yearAgo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;parsedRange&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;month&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;ago&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;translate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;parsedRange&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;month&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;monthAgo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// } else if () { ... and so on&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;article&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* imagine here some useful extra markup */&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;article-time&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;ago&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It does look like it cannot be helped, right? Calculation of "ago" seemed like a great candidate, but it seems to be tightly coupled with &lt;code&gt;translate&lt;/code&gt; function coming from a &lt;code&gt;hook&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But is all hope truly lost?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// calculate-ago-from-timestamp.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;parseTimeRange&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;date-lib-of-the-day&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;CalculatedAgo&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;translationKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// I guarantee you that, like this, you'll be more likely to find edge cases!&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;calculateAgoFromTimestamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;CalculatedAgo&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;articleCreationTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;timePassed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;articleCreationTime&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;parsedRange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parseTimeRange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timePassed&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;parsedRange&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;year&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
      &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;parsedRange&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;year&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;translationKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;yearAgo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;parsedRange&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;month&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;parsedRange&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;month&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;translationKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;monthAgo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// if () { ... and so on&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Resulting in a cleaner React component, check this out!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// article.tsx&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;calculateAgoFromTimestamp&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./calculate-ago-from-timestamp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// ... types and interfaces&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;PostTime&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;articleId&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;ArticleProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;article&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useArticle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;articleId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;translate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useTranslator&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// Look how much cleaner this component looks like now!&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;ago&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;processedTimestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;calculateAgoFromTimestamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;// Oops! We've just solved the coupling with a bit of creativity!&lt;/span&gt;
    &lt;span class="nx"&gt;ago&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;translate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;processedTimestamp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;processedTimestamp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;translationKey&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;article&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* ... */&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;article-time&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;ago&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Yeii, 🎉 now we can test this functionality without writing UI tests or without setting up a complicated translation mock! I also guarantee you that the moment you put this in a file and start writing tests you'll get creative finding edge-cases.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;As you can see now, while &lt;em&gt;"refactoring towards pure functions"&lt;/em&gt; is not going to give you the feeling of technical superiority it is an excellent tool to clean up code and make sure testing stays easy!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Easy testing usually means better code coverage!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I hope I have convinced you to look for these patterns and mercilessly cut complexity!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>typescript</category>
      <category>react</category>
    </item>
    <item>
      <title>What's the point of a rockstar developer?</title>
      <dc:creator>András Tóth</dc:creator>
      <pubDate>Wed, 26 Mar 2025 19:25:19 +0000</pubDate>
      <link>https://dev.to/latobibor/whats-the-point-of-a-rockstar-developer-2ifj</link>
      <guid>https://dev.to/latobibor/whats-the-point-of-a-rockstar-developer-2ifj</guid>
      <description>&lt;p&gt;Hi there folks, today this question came to me.&lt;/p&gt;

&lt;p&gt;I understand that it is great that you hire a very capable person and that unblocks certain things, fixes long broken projects and so on.&lt;/p&gt;

&lt;p&gt;But why did these things got blocked and broken in the first place?&lt;/p&gt;

&lt;p&gt;For me, the reliance on "genius" developers, or &lt;a href="https://gundam.fandom.com/wiki/Newtype" rel="noopener noreferrer"&gt;"newtype"&lt;/a&gt; or "10x developer" (even I saw 100x because of AI 🤦) is showing something very disturbing:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The lack of quality company (tech) leadership.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Either they are not capable or they are capable but unable to really influence decisions because of a strong push from business.&lt;/p&gt;

&lt;p&gt;You see, if main stability features, like a comprehensive test suite depends on finding the right candidate who does that job outside of weekly responsibilities (and potentially on their own unpaid free time) then we are talking about serious, serious management issues.&lt;/p&gt;

&lt;p&gt;I heard this idea about Japanese school system, that it's aim to bring all students up to a good average standard. I saw on the streets in Japan what it meant: they were clean and orderly. The bicycles were left in public without any safety on them, because they could trust the good average standard that they won't be stolen.&lt;/p&gt;

&lt;p&gt;So in conclusion, behind the cult of the "rockstar developer" is a company that should invest in hiring at least a capable management who are going to coordinate the important work required for engineering longevity and velocity.&lt;/p&gt;

&lt;p&gt;And if you do hire a "rockstar"... They would make your company fly.&lt;/p&gt;

&lt;p&gt;(Photo: me as a ""rockstar"" about a decade ago.)&lt;/p&gt;

</description>
      <category>programming</category>
      <category>career</category>
      <category>leadership</category>
    </item>
    <item>
      <title>Do you need classes in JS/TS? [2025 version]</title>
      <dc:creator>András Tóth</dc:creator>
      <pubDate>Wed, 19 Mar 2025 05:21:22 +0000</pubDate>
      <link>https://dev.to/latobibor/do-you-need-classes-in-jsts-2025-version-j46</link>
      <guid>https://dev.to/latobibor/do-you-need-classes-in-jsts-2025-version-j46</guid>
      <description>&lt;p&gt;Hi there folks!&lt;/p&gt;

&lt;p&gt;This is a revised version of 2022 article: &lt;a href="https://dev.to/latobibor/do-you-need-classes-in-jsts-4ggd"&gt;Do you need classes in JS/TS?&lt;/a&gt;. (Ethical AI usage notice: no content was generated for the article or the cover image, however I did ask for a grammar check).&lt;/p&gt;

&lt;p&gt;If you are a fresh JavaScript/TypeScript developer, you'll encounter some very vocal opinions on writing code in a &lt;em&gt;"functional style"&lt;/em&gt; (FP, or "functional programming") or an &lt;em&gt;"objectied oriented style"&lt;/em&gt; (OOP, or "object oriented programming").&lt;/p&gt;

&lt;p&gt;You will hear devs saying things like &lt;em&gt;"serious backend work requires a strong command of object oriented patterns"&lt;/em&gt;, or _"On the frontend you must avoid side effects and embrace functional programming!".&lt;/p&gt;

&lt;p&gt;Not coincidentally you will encounter backend frameworks that are fully object-oriented (like NestJS) and frontend ones that embrace immutability and pure functions, like the framework &lt;code&gt;redux&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Personally, I believe that the right technique should be used for the right problem. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The key sign of misusing a particular style is &lt;em&gt;confusion&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you start to feel confused about why such a simple thing as adding a new endpoint to a web service or handling a simple HTML form requires so many steps or files, there is a chance that the wrong paradigm was applied.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Or more likely, &lt;em&gt;black and white thinking&lt;/em&gt; about a particular paradigm resulted in bloat, unnecessarily complicating code.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Note on terminology, that this article focuses on using "classes" to achieve an "object oriented" paradigm: when to use it in JavaScript/TypeScript working on the frontend and webservices. I exclude niche applications like parsers/linters/transpilers/etc. and games.&lt;/p&gt;

&lt;p&gt;I will also exclude from this article principles that people regularly associate with OOP; for instance hiding implementation details, providing a clear and safe interface to interact with a private data store and also microservices. These are extremely valuable principles, however I believe many of these can be achieved without classes in JS/TS. I also feel that &lt;em&gt;tightly coupling&lt;/em&gt; these principles to the custom of using classes for everything and then raising the strawman of attacking the latter means throwing out these great principles hurt code-bases.&lt;/p&gt;

&lt;h2&gt;
  
  
  The point of using a class
&lt;/h2&gt;

&lt;p&gt;Let's roll back time and go back to an old language: &lt;code&gt;C&lt;/code&gt;. The algorithm you are working on requires an implementation of a &lt;strong&gt;stack&lt;/strong&gt; and you have to write one from scratch. You drop elements into the stack, and by using the &lt;code&gt;pop()&lt;/code&gt; function, you retrieve the last element that was dropped into it.&lt;/p&gt;

&lt;p&gt;To implement it you would need the following things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;some kind of storage that holds the &lt;code&gt;items&lt;/code&gt; of the &lt;code&gt;stack&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;some way to deal with memory when you have a lot of &lt;code&gt;items&lt;/code&gt; in your &lt;code&gt;stack&lt;/code&gt;, even expanding the storage behind the scenes if it fills up&lt;/li&gt;
&lt;li&gt;you want to keep a clear front, so the user access only specific methods and properties, giving you room to refactor later&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Therefore you will have the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a &lt;code&gt;private&lt;/code&gt; internal &lt;code&gt;state&lt;/code&gt; that holds values between calls (the stack stays in memory and you can access at your leisure)&lt;/li&gt;
&lt;li&gt;a couple of internal &lt;code&gt;methods&lt;/code&gt; that manages your internal &lt;code&gt;state&lt;/code&gt; properly and a way to hide them from users to avoid code coupled to the &lt;em&gt;implementation of the day&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;on the other hand you do want to show &lt;code&gt;public&lt;/code&gt; methods that lets you interact with the unit&lt;/li&gt;
&lt;li&gt;and optionally have an &lt;code&gt;interface&lt;/code&gt; to further decouple those &lt;code&gt;public&lt;/code&gt; accessors from the implementation, declaring mandatory methods and properties of a &lt;code&gt;stack&lt;/code&gt;, allowing you to interchange different implementations if needed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now imagine when this concept was &lt;code&gt;new&lt;/code&gt; and trending! It was very elegant, very organized. People back then were dealing mostly with desktop applications or very low level data structures like buffers, pointers, etc. and it made sense to tuck all that complexity away and use higher organization by having more of that &lt;code&gt;class&lt;/code&gt; thing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The rise of Object Oriented Programming
&lt;/h2&gt;

&lt;p&gt;As with any trends, the industry got a bit overboard with it. When &lt;strong&gt;C#&lt;/strong&gt; and &lt;strong&gt;Java&lt;/strong&gt; arrived it was no longer possible to just declare a &lt;code&gt;procedure&lt;/code&gt; or &lt;code&gt;function&lt;/code&gt; without having a class; in my opinion it was a way to discourage people from &lt;strong&gt;Procedural Programming&lt;/strong&gt; which was the old paradigm and force people to learn this new way of organizing code. (Not always successfully - I had a Java developer colleague who didn't bother with classes: everything was a &lt;code&gt;Map&amp;lt;string, something&amp;gt;&lt;/code&gt;, essentially reinventing other dynamic languages 😄.)&lt;/p&gt;

&lt;p&gt;I get what they wanted but this paradigm was overly complicating dead simple things, like a humble data transformation code where you process data from &lt;code&gt;type A&lt;/code&gt; to &lt;code&gt;type B&lt;/code&gt; and where you do not need to keep an internal state made of low level building blocks. &lt;/p&gt;

&lt;p&gt;Therefore, while OOP solved great many important problems, it also tighly coupled &lt;code&gt;classes&lt;/code&gt; with the idea of "well organized code". This became ingrained in a generation who uses it, well, for everything.&lt;/p&gt;

&lt;p&gt;Now let's see a pair of contrasting examples to hit my point home.&lt;/p&gt;

&lt;h3&gt;
  
  
  Good example: database connection
&lt;/h3&gt;

&lt;p&gt;Managing access to a database usually requires maintaining some kind of connection pool (reusing a number of connections to a database server). It also needs to track if we have already logged in or not, if the remote server is down and so on. We don't want to know about all of that, just a way to configure DB access and to run queries. These functions will constitute our &lt;code&gt;interface&lt;/code&gt;: a set of functions and properties that do not change frequently (or at all preferably) while keeping the implementation details of the connection and the connection pool hidden (making them &lt;code&gt;private&lt;/code&gt;). We &lt;em&gt;do&lt;/em&gt; want to also persist some &lt;code&gt;state&lt;/code&gt; as well to track, say, if we already gained access to the DB or not yet, or how much of the connection pool is already used up.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// An overly simplified database module&lt;/span&gt;
&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Database&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;configure&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ConfigOptions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="c1"&gt;// I just make this up for a simple example&lt;/span&gt;
  &lt;span class="nl"&gt;isReadyToServeRequests&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PostgresDatabase&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;Database&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Same public methods but maybe very different concrete implementation!&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MySqlDatabase&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;Database&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Bad example: REST handlers
&lt;/h3&gt;

&lt;p&gt;Let's say you have a dynamic FAQ page on your company website helping users. They want to click on articles in their own language with tailored, relevant information. This can be understood as a simple projection of &lt;code&gt;(userId, articleId, language) =&amp;gt; article&lt;/code&gt;. A simple function with its isolated scope ("the closure") is ideal here since you don’t want to persist state between calls: the article of &lt;code&gt;user A&lt;/code&gt; is unrelated to the article of &lt;code&gt;user B&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I have a little story about this. About 6 years ago we were new to &lt;strong&gt;next.js&lt;/strong&gt; when we ran into this problem - in fact 2 teams separately made the same mistake: persisting a &lt;code&gt;state&lt;/code&gt; between calls unwittingly. The bug we ran into with my team was serving articles in a random language, depending on who called last - if 2 users were making concurrent calls and had different languages the articles showed up all mixed. We accidentally stored &lt;code&gt;language&lt;/code&gt; in a local &lt;code&gt;state&lt;/code&gt; - the request handler was finding this &lt;code&gt;state&lt;/code&gt; and used that. &lt;/p&gt;

&lt;p&gt;The other team had it worse: unlike us they didn't catch it in QA and they managed to deploy a bug to production where users could see other users' private data...&lt;/p&gt;

&lt;p&gt;The solution was to load up the &lt;code&gt;user&lt;/code&gt; in both cases and scope it to the request handler, which became a simple function. Now each call was isolated from the other.&lt;/p&gt;

&lt;p&gt;Summing it up, there was no need to keep a &lt;code&gt;state&lt;/code&gt; between calls, whereas the &lt;code&gt;interface&lt;/code&gt; was also very simple: 1 endpoint matching 1 function. (In real life you might need to create sub functions as you don't want to have 1000 lines functions.)&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion of the examples
&lt;/h3&gt;

&lt;p&gt;As I hopefully demonstrated, while OOP is an excellent pattern for certain problems, it is &lt;em&gt;not a magic bullet&lt;/em&gt; and can add a &lt;em&gt;useless&lt;/em&gt; complexity and even be dangerous when used on the wrong thing. &lt;/p&gt;

&lt;p&gt;I am positive that seeing more examples can help you grasp this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you build a game, all the enemies are little persisted states with things like &lt;code&gt;health&lt;/code&gt;, abilities etc. Perfect sense to go with classes! ✅&lt;/li&gt;
&lt;li&gt;If you implement data structures, components with internal states, complicated algorithms that run for a long time and need to keep tab on a lot of little variables: classes to use! ✅&lt;/li&gt;
&lt;li&gt;Data transformations, projections: you have no internal state, classes are a bad fit! ❌&lt;/li&gt;
&lt;li&gt;API request handlers: you might have millions of concurrent requests, each of them should be isolated from each other: having an internal &lt;code&gt;state&lt;/code&gt; is actually dangerous here, OOP is ❌! (A database service you may need to call is &lt;em&gt;not&lt;/em&gt; an internal state.)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Understanding the clash between OOP and JavaScript's language design
&lt;/h2&gt;

&lt;p&gt;The tension between &lt;strong&gt;Java/C#&lt;/strong&gt; style object-oriented programming and &lt;strong&gt;JavaScript&lt;/strong&gt; lies in the fact that&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Javascript&lt;/strong&gt; (and consequentially &lt;strong&gt;TypeScript&lt;/strong&gt;) is neither strictly &lt;em&gt;functional&lt;/em&gt; nor an &lt;em&gt;object oriented language&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;(Note: &lt;strong&gt;TypeScript&lt;/strong&gt; is not making JS into an object-oriented language! I heard this baffling myth a couple of times from people.)&lt;/p&gt;

&lt;p&gt;It has elements of both but its implementation differs in very important aspects. For example if you used JS for a while you must have encountered curious problems around &lt;code&gt;this&lt;/code&gt;. You passed a &lt;code&gt;method&lt;/code&gt; of a &lt;code&gt;class&lt;/code&gt; to a &lt;code&gt;function&lt;/code&gt; as a &lt;code&gt;callback&lt;/code&gt; and &lt;em&gt;BOOM!&lt;/em&gt; 💥, &lt;code&gt;this.something&lt;/code&gt; was no longer there. In a classic OOP language, &lt;em&gt;this&lt;/em&gt; can never happen because &lt;code&gt;classes&lt;/code&gt; "own" their &lt;code&gt;methods&lt;/code&gt;. In JavaScript &lt;code&gt;classes&lt;/code&gt; are just syntactic sugar on top of this &lt;code&gt;object&lt;/code&gt;-&lt;code&gt;function&lt;/code&gt; soup we have. There is no such thing as grabbing an object's &lt;code&gt;method&lt;/code&gt; and &lt;code&gt;binding&lt;/code&gt; it to another object's internal &lt;code&gt;state&lt;/code&gt; in Java or C#.&lt;/p&gt;

&lt;p&gt;One particular anti-pattern I see comes directly from &lt;strong&gt;C#/Java&lt;/strong&gt; where it was unavoidable to use &lt;code&gt;class&lt;/code&gt; even when just needed to define a &lt;code&gt;function&lt;/code&gt; or to store a couple of properties. In JavaScript, I consider this a &lt;strong&gt;design mistake&lt;/strong&gt; as we can create simple &lt;code&gt;functions&lt;/code&gt; and simple &lt;code&gt;objects&lt;/code&gt; without the bells and whistles.&lt;/p&gt;

&lt;p&gt;On the other hand, &lt;strong&gt;JavaScript&lt;/strong&gt; isn't a true functional language either, as it lacks key guarantees like the &lt;strong&gt;immutability of function arguments&lt;/strong&gt; and functions can have &lt;strong&gt;side-effects&lt;/strong&gt;. (Though, I wish we could declare and enforce functions to be &lt;code&gt;pure&lt;/code&gt;!). &lt;/p&gt;

&lt;p&gt;A classic example is the &lt;code&gt;.sort()&lt;/code&gt; method of an &lt;code&gt;array&lt;/code&gt; which modifies the original instance unlike &lt;code&gt;.map&lt;/code&gt; which isn't (note that in 2025 we have now &lt;code&gt;.toSorted()&lt;/code&gt; that does no longer mutate the array! 🎉). This means if you pass the same array to two different functions if the implementation of &lt;code&gt;functionA&lt;/code&gt; sorts the array, it will change what is happening in &lt;code&gt;functionB&lt;/code&gt;!&lt;/p&gt;

&lt;p&gt;(A personal rant: I can't fathom to understand why it is next to impossible to find in the documentation of &lt;strong&gt;Jest&lt;/strong&gt; how to mock named exports of functions. It is clear to me that &lt;strong&gt;Jest&lt;/strong&gt; was designed for OOP in JS and supporting proper JS import/export patterns was an afterthought.)&lt;/p&gt;

&lt;h2&gt;
  
  
  When to refactor a &lt;code&gt;class&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Now that we understand the strengths and weaknesses of a &lt;code&gt;class&lt;/code&gt; let's have some simple rules about when and how to dismantle them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the &lt;code&gt;class&lt;/code&gt; does not contain &lt;code&gt;methods&lt;/code&gt; =&amp;gt; this is POD aka plain-old-data, you need a simple object: &lt;code&gt;{}&lt;/code&gt; (+ a &lt;code&gt;type&lt;/code&gt; in &lt;code&gt;TypeScript&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;any &lt;code&gt;method&lt;/code&gt; of the &lt;code&gt;class&lt;/code&gt; that does not &lt;em&gt;seriously&lt;/em&gt; use &lt;code&gt;this&lt;/code&gt;, can be moved into their own &lt;code&gt;functions&lt;/code&gt;; by "seriously" I mean it doesn't use &lt;code&gt;this&lt;/code&gt; to avoid receiving arguments (see below)&lt;/li&gt;
&lt;li&gt;now check what's left of the &lt;code&gt;class&lt;/code&gt;; if the resulting methods don't need this anymore, move them out&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At this point, either your &lt;code&gt;class&lt;/code&gt; is gone or it has a tightly knit set of &lt;code&gt;variables&lt;/code&gt; and &lt;code&gt;methods&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;👆 I have written an article about: &lt;a href="https://dev.to/latobibor/refactoring-towards-pure-functions-4cjc"&gt;Refactoring towards pure functions&lt;/a&gt;, where I go into the details.&lt;br&gt;
There's also a chance here to split large &lt;code&gt;classes&lt;/code&gt; into smaller ones, by using &lt;a href="https://steven-giesel.com/blogPost/d0784f04-fe7a-4426-bdb7-314d0f9e1b6b" rel="noopener noreferrer"&gt;&lt;code&gt;class&lt;/code&gt; cohesion&lt;/a&gt;: if you have a disjunct set of &lt;code&gt;methods&lt;/code&gt; and &lt;code&gt;variables&lt;/code&gt; they can go into their own &lt;code&gt;class&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The true feature a &lt;code&gt;class&lt;/code&gt; provides is access to &lt;code&gt;this&lt;/code&gt; in its methods. When some or all of them do not access it, as they operate over the arguments passed in then you will need a &lt;code&gt;function&lt;/code&gt; instead. I am going to show you an example next where we seem to use &lt;code&gt;this&lt;/code&gt; properly but we are better off with using the simplest functions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;StringValidator&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;sanitizeString&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;+/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;isEmpty&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;boolean&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// As you can see, the class has no real internal state&lt;/span&gt;
&lt;span class="c1"&gt;// We just use the constructor to pass in an argument.&lt;/span&gt;
&lt;span class="c1"&gt;// Moreover, the cohesion of the class is really low; &lt;/span&gt;
&lt;span class="c1"&gt;// none of the methods depend on each other.&lt;/span&gt;

&lt;span class="c1"&gt;// Instead you can refactor this to two pure functions:&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;sanitizeString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;+/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;isEmptyString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  A useless class: a quick example
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;transformDataAndSendEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;recipient&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;someData&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SomeData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mailDocument&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;formatSomeData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;someData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// why use a class for something that will be thrown away?&lt;/span&gt;
  &lt;span class="k"&gt;await &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MailService&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;sendMail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;recipient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mailDocument&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// In this case, "MailService" is not a real service.&lt;/span&gt;
&lt;span class="c1"&gt;// It is not "waiting somewhere in the memory" to handle requests.&lt;/span&gt;
&lt;span class="c1"&gt;// Nor does it have some meaningful internal state.&lt;/span&gt;
&lt;span class="c1"&gt;// It is just an extra step to get to `sendMail()` function call.&lt;/span&gt;
&lt;span class="c1"&gt;// And it will be garbage collected when we are out of `transformDataAndSendEmail` block.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Working with &lt;strong&gt;JavaScript&lt;/strong&gt; we should use &lt;strong&gt;JavaScript&lt;/strong&gt; patterns. That would yield us the simplest results.&lt;/p&gt;

&lt;p&gt;For getting the "JavaScript way" I really recommend the books of &lt;code&gt;getify&lt;/code&gt; &lt;a href="https://github.com/getify/You-Dont-Know-JS/blob/2nd-ed/objects-classes/ch5.md" rel="noopener noreferrer"&gt;You don't know JS; class alternatives&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Questions, agree or disagree?&lt;/strong&gt; Sharing your edge cases help both of us refining our points of views. 🤝 Let me know in the comments!&lt;/p&gt;

&lt;h2&gt;
  
  
  Note
&lt;/h2&gt;

&lt;p&gt;As a commenter on my first article pointed out, you don't even need to use the &lt;code&gt;class&lt;/code&gt; keyword to encapsulate state and methods that operate over them, just &lt;a href="https://dev.to/peerreynders/comment/1m04m"&gt;use any old function to create a new object&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;makeSomething&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;myPrivateMember&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getMyNumber&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;myPrivateMember&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;randomizeMyNumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;range&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;myPrivateMember&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;range&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;getMyNumber&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;randomizeMyNumber&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>javascript</category>
      <category>typescript</category>
      <category>programming</category>
    </item>
    <item>
      <title>Tech stories: the wrong type of help that made me rage quit a meeting</title>
      <dc:creator>András Tóth</dc:creator>
      <pubDate>Fri, 27 Dec 2024 04:13:14 +0000</pubDate>
      <link>https://dev.to/latobibor/tech-stories-the-wrong-type-of-help-that-made-me-rage-quit-a-meeting-2jl6</link>
      <guid>https://dev.to/latobibor/tech-stories-the-wrong-type-of-help-that-made-me-rage-quit-a-meeting-2jl6</guid>
      <description>&lt;p&gt;When I shut close my laptop and apologized for leaving, it was a big achievement: I hadn't shouted at anybody 🫣. I was just shaking from frustration and anger.&lt;/p&gt;

&lt;p&gt;Hi there, folks. This story is about the right and wrong ways of offering help, respect, experience, processing information, and how attempting to save time can sometimes lead to delays.&lt;/p&gt;

&lt;p&gt;This story is also in my top 5 worst engineering experiences. I rarely get this angry.&lt;/p&gt;

&lt;h2&gt;
  
  
  Great plans for a burning issue
&lt;/h2&gt;

&lt;p&gt;At work customer support issues were piling up. We reached a level that were not sustainable: hiring and training support agents were lagging behind. Responding to emails took 2-3 days on average, users were quite frustrated.&lt;/p&gt;

&lt;p&gt;My talented teammates were getting to the bottom of it absolutely professionally: data analysts crunched customer issues, grouping them with their volume; PMs narrowed them down to ones that were feasible to implement, interviews with the frustrated users were done by UX researchers, copywriters nailed the right tone and UX designers tested out the right self-help "tiles", each with its own clear explanation and actions. I think this was one of the most professionally researched plans I have ever worked on.&lt;/p&gt;

&lt;p&gt;However, there was no patience for its implementation.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;em&gt;"Hey, you need some help?"&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;While our team had design, research, and many helpers, we were only three full-time frontend engineers who could only partially work on the project. We had ongoing projects plus customer and infrastructural issues to handle (for example, the data analyst of my team had left, so as a frontend engineer, I was fixing the data pipeline—not optimal).&lt;/p&gt;

&lt;p&gt;The customer support bottleneck eventually caught the attention of top management. Out of the blue we were offered the help of another team: 6 young engineers.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Brooke's Law states that adding engineers to a late project will only delay the finish of the late project.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Knowing this, I replied that we might not need all six of them. Personally, I needed a data analyst to hand over the fixing of a never-ending data pipeline task in Python, which I was learning as I was fixing a broken database migration. I also thought maybe two more people would be very useful to pair up with, cutting down the coding-pull request-review-fix chains.&lt;/p&gt;

&lt;p&gt;But we got an entire team, and stopped working on the exciting new project to prepare a well documented intro for them. I expected we’d explain the finer details when we start. Well, that didn't happen.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;em&gt;"So, it's a very simple task! I think we're done by tomorrow afternoon."&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;Then came one of the worst meetings of my life: a young (22ish) and inexperienced team lead dominated the entire meeting. He said he’d just glanced at the design slides right before the meeting, and each self-help tile looked very similar to each other: some text and one or two buttons, easy-peasye. He comically underestimated the task at hand and literally said:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Oh, I think this is a very easy task. We're going to be ready by tomorrow afternoon!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This was not a joke. The dysfunction in my team was laid bare in that second. My team lead, who was conflict-avoidant, didn’t say anything. I was looking around in disbelief, trying to see who's gonna react to such an absolutely crazy statement. None did. &lt;/p&gt;

&lt;p&gt;Of course, there's no way a new team can push out something that quickly. By that time I saw 600 million times already how requirements change the moment there is working UI code. You cannot rely on assumptions that "there's gonna be only some text and maybe two buttons", you would need your code to be flexible. (For a bit more info see also Kent C. Dodds’ &lt;a href="https://kentcdodds.com/blog/compound-components-with-react-hooks" rel="noopener noreferrer"&gt;compound component approach&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;I asked if he has read the documentation we had written. &lt;em&gt;"Nope,"&lt;/em&gt; he said without showing any regret whatsoever.&lt;/p&gt;

&lt;p&gt;I was enraged seeing that all the effort we put together was going to waste. From going through with our plan, we were running after people who kinda understood some part of it. Moreover, the impossible deadline of "tomorrow afternoon" filled me with dread.&lt;/p&gt;

&lt;p&gt;In that moment, I reached my boiling point, shut my laptop, and stormed out of the meeting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Inside a raging head
&lt;/h2&gt;

&lt;p&gt;The experience soured my mood for months and still angers me today. I felt betrayed by my team lead for not stepping up for our careful plans, for not calling out reckless promising, for choosing his personal safety over team spirit and lastly, for wasting our work.&lt;/p&gt;

&lt;p&gt;Luckily, apart from the other team lead, nobody took seriously that crazy estimation, and nobody held us accountable for failing it.&lt;/p&gt;

&lt;p&gt;However, I didn’t handle the coming days well, and I’m not proud of it. I was deeply offended, and I would cynically giggle at any setbacks, because I wanted to feel vindicated. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"You can't promise the next day! It's impossible! I told you so!"&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I was right, it wasn’t ready the next day or the day after. We even had to roll back a couple of releases as the code hastily thrown together. It was done exactly two weeks later than tomorrow afternoon - and a work that needed refactoring.&lt;/p&gt;

&lt;p&gt;Without them, it would have taken us 1 month I think. With them it was 2 weeks of hell, failed releases + refactoring later. Not to mention the human fallout, that costed us working relationships: while I lost faith in my team lead, my negative attitude during those days did affect my literally closest colleague (sitting next to me). &lt;/p&gt;

&lt;p&gt;Without me knowing it, that relationship soured to the point that months later, when it was his time to step up for me, he instead jumped on the opportunity to get rid of me. It was a really dark day for me, I couldn't speak to him since.&lt;/p&gt;

&lt;p&gt;Now I always measure &lt;em&gt;what&lt;/em&gt; and &lt;em&gt;how&lt;/em&gt; I say things.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why new people are more than just more cores in a processor
&lt;/h2&gt;

&lt;p&gt;We kinda demonstrated Brooke's Law: though we finished earlier having this "help", the combined time spent on this, including lost team members was huge.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So why is this law so true?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Unlike moving houses, where more hands bring more boxes, the big picture for a software engineering project has many intricate details that must be understood first. Some of it even must be processed during sleep (have you ever woke up or came out of the shower just having come up with the &lt;em&gt;right approach&lt;/em&gt;?)! Not to mention grasping the coding style of the team, or the gotchas of the codebase. And then the human factor: team dynamics that came to be through spoken and unspoken agreements.&lt;/p&gt;

&lt;p&gt;When new people arrive they have to feel these out.&lt;/p&gt;

&lt;h2&gt;
  
  
  Help done right
&lt;/h2&gt;

&lt;p&gt;Combining everything, these are my suggestions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Trust the devs who are intimately familiar with the problem!&lt;/li&gt;
&lt;li&gt;Let them specify what help they would benefit from!&lt;/li&gt;
&lt;li&gt;Don’t add too many people at once!&lt;/li&gt;
&lt;li&gt;Use the new people to handle distractions, not to create them.&lt;/li&gt;
&lt;li&gt;For live coding sessions pair a new and old member: a second pair of expert eyes, even without domain knowledge can help shortening the feedback cycle, so code review turnarounds would be a lot faster.&lt;/li&gt;
&lt;li&gt;For the love of everything that is holy! &lt;strong&gt;READ THE DOCUMENTATION before promising anything!&lt;/strong&gt; Check out the current codebase, speak with people who worked on it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Exploring and getting familiar with alternatives before committing to a solution is an essential part of the job. Work is not eight hours of pure coding, you should not skip the discussions, otherwise you are going to ship the wrong thing, or at least in the wrong format.&lt;/p&gt;

&lt;p&gt;But let’s get back to what happened afterward!&lt;/p&gt;

&lt;h2&gt;
  
  
  Somewhat of a success story...?
&lt;/h2&gt;

&lt;p&gt;hanks to solid planning and company-wide efforts, the customer support bottleneck disappeared. Response times dropped from 2–3 days to just a few hours.&lt;/p&gt;

&lt;p&gt;There was a secondary benefit to that: people did not write a second or a third email begging for a response. So not only the cases got resolved faster, also the volume of the work went down.&lt;/p&gt;

&lt;p&gt;It could have been done just so much easier...&lt;/p&gt;

</description>
      <category>story</category>
      <category>programming</category>
      <category>watercooler</category>
    </item>
    <item>
      <title>7+ Years of Experience Converting JavaScript to TypeScript: My Caring Opinions</title>
      <dc:creator>András Tóth</dc:creator>
      <pubDate>Sun, 29 Sep 2024 22:14:57 +0000</pubDate>
      <link>https://dev.to/latobibor/7-years-of-experience-converting-javascript-to-typescript-my-caring-opinions-36ci</link>
      <guid>https://dev.to/latobibor/7-years-of-experience-converting-javascript-to-typescript-my-caring-opinions-36ci</guid>
      <description>&lt;p&gt;I started my JS career in 2015, spent a year working exclusively with it, and then transitioned to TypeScript. I’d love to say &lt;em&gt;'And never looked back again!'&lt;/em&gt;, but I can’t; since 2016 there’s a chore I have to do basically at every company I worked for: converting existing codebases from Javascript to TypeScript. These are going to be my subjective, sometimes scolding opinions.&lt;/p&gt;

&lt;h3&gt;
  
  
  In a hurry? Here’s the tl;dr:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The False Sense of Velocity:&lt;/strong&gt; skipping to deal with data drifting and edge cases is surely faster than dealing with them, but the price will be paid nonetheless.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Drifting:&lt;/strong&gt; When data schemas evolve without a type system following them, it’s not just migration to TypeScript that gets hard, you will be plagued by support issues. Best way to deal with it is to standardize first your data collections and have strict typing afterwards.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Poisonous Optionals:&lt;/strong&gt; When your data schema lacks uniformity, you would have to deal with handling of undefined properties every time you deal with these. TS is just a reminder, not the cause for it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;any&lt;/code&gt; Means Trouble:&lt;/strong&gt; Using any hides potential issues and makes it harder to track your actual state of TS migration; define first your API types, and type inference will lay out a migration “plan”.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Forgetting about Promises:&lt;/strong&gt; Forgetting to react to promises either with &lt;code&gt;await&lt;/code&gt; or with &lt;code&gt;.then/.catch&lt;/code&gt; happens more often than we think. Failing to do so might cause you long hours of investigating weird bugs like an entry created for a missing photo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Undefined Variables:&lt;/strong&gt; A classic refactoring mistake in JavaScript when you rename/move out things from scope, but not all references to them get updated; TypeScript helps catch these before runtime.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unsafe Array Operations&lt;/strong&gt;: It’s quite easy to forget about edge cases of arrays; yet another area where TypeScript helps prevent this.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Saga of Magic Code:&lt;/strong&gt; Complex JavaScript patterns can be very hard to type; but do you actually need them, are they good, recognizable patterns? &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The False Sense of Velocity
&lt;/h2&gt;

&lt;p&gt;Every now and then I encounter a JS purist, who sneers at us with their harsh opinion: they simply work way too fast to get slowed down by the extra steps required for TypeScript. Sounds badass, but this confidence usually falls apart when I change the extension from &lt;code&gt;.js&lt;/code&gt; to &lt;code&gt;.ts&lt;/code&gt;, because I get blasted by the following typical errors.&lt;/p&gt;

&lt;h2&gt;
  
  
  Data drifting
&lt;/h2&gt;

&lt;p&gt;I wish to start with this, as I rarely read about it in blogs, but it is, in my opinion, one of the hardest parts of TS conversion: the authors start with data having &lt;code&gt;ShapeA&lt;/code&gt; a couple of years before the conversion. Then &lt;code&gt;ShapeA&lt;/code&gt; changes to &lt;code&gt;ShapeB&lt;/code&gt;, &lt;code&gt;ShapeC&lt;/code&gt;, then there are competing versions for &lt;code&gt;ShapeD1&lt;/code&gt; and &lt;code&gt;ShapeD2&lt;/code&gt;. In the end you will have all shapes of the data in your (probably NoSQL) database accumulated during many years: &lt;code&gt;[ShapeA, ShapeD1, ShapeD1, ShapeB, ShapeD2, ShapeB, …]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;An example: recently I had sampled from a Firestore collection items of users. The &lt;code&gt;birthday&lt;/code&gt; property had the following types:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// …&lt;/span&gt;
  &lt;span class="nx"&gt;birthday&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Of course if I use this type that accurately describes what is in the database the entire codebase goes up in flames: hundreds of TS compilation errors show up, while the morale goes down. Usually it’s warning me about potentially &lt;code&gt;undefined&lt;/code&gt; values, or missing conversions (e.g. a &lt;code&gt;string&lt;/code&gt; is not a &lt;code&gt;Date&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Not dealing with this &lt;em&gt;toxic variability&lt;/em&gt;, a developer might feel very productive, but these are going to cause a lot of trouble to customers, customer support and data analysts (maybe we should have an annual &lt;em&gt;“Hug and comfort a data analyst, who puts up with your data leniency”&lt;/em&gt; day so we don't forget about these folks?). We waste their time, but us? We’re fast as lightning without the confines of strict types.&lt;/p&gt;

&lt;p&gt;After trying to solve it in through million different ways, I reckon the only way of dealing with this is to...&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;first, &lt;strong&gt;define the ideal type&lt;/strong&gt; you want to work with&lt;/li&gt;
&lt;li&gt;and second: &lt;strong&gt;standardize the data&lt;/strong&gt; you have accordingly (which means backing up and sweaty scripting of long running tasks)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Poisonous optionals
&lt;/h2&gt;

&lt;p&gt;If you have paid attention to how the example type was defined you would see how this a problem directly related to data drifting:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;There can be a million different ways an expected property to be not in an object.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In a JS codebase (especially if you choose a simple text editor over an IDE) you are not going to get warned about these, since really, there is now way for your IDE to tell if an object passed in as a parameter has or hasn’t the expected property. However TS will warn you about these missing optionals (i.e. not just you might not have &lt;code&gt;birthday.__time__&lt;/code&gt; you might not even have a &lt;code&gt;birthday&lt;/code&gt; property) and then you would be forced to cover all these cases (including &lt;code&gt;null&lt;/code&gt; as opposed to &lt;code&gt;undefined&lt;/code&gt; - take a second look at the type above 🫣). This is usually means to do the repetitive task of writing &lt;code&gt;birthday?.time ? birthDay.time : typeof birthDay === ‘string’ ? new Date(birthday) : birthDay, etc.&lt;/code&gt; (of course not in this brainf*** format).&lt;/p&gt;

&lt;p&gt;This often leads to a lot of frustration, and not just to devs new to TS. It &lt;em&gt;does feel like&lt;/em&gt; having types slow us down.&lt;/p&gt;

&lt;p&gt;But in reality this is the &lt;strong&gt;consequence of data drifting&lt;/strong&gt;: whose fault is that you cannot be ever sure whether an object has a birthday property?&lt;/p&gt;

&lt;h2&gt;
  
  
  How &lt;code&gt;any&lt;/code&gt; gets in the way of TS migration
&lt;/h2&gt;

&lt;p&gt;I have a clear preference for where to start in a project to do the TypeScript migration and it is where external data enters; either through fetch or through a form.&lt;/p&gt;

&lt;p&gt;Let's say that for a given piece of data I have 3 relevant files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;fetch-data.js&lt;/code&gt; where the data gets queried from an endpoint&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ParentComponent.js&lt;/code&gt; where data is partially transformed and passed as a prop to the next component&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ChildComponent.js&lt;/code&gt; where the passed data from &lt;code&gt;ParentComponent.js&lt;/code&gt; is used&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now if during migration I choose to convert to &lt;code&gt;ParentComponent.js&lt;/code&gt; &lt;em&gt;and&lt;/em&gt; as I don't know what exact data is fetched in &lt;code&gt;fetch-data.js&lt;/code&gt; I use &lt;code&gt;any&lt;/code&gt; &lt;em&gt;temporarily&lt;/em&gt; to silence the annoying compiler, I might set myself up for failure.&lt;/p&gt;

&lt;p&gt;Of course, if we had these 3 files clearly laid out to us we would not start with &lt;code&gt;ParentComponent.js&lt;/code&gt;, but in real-world we would have hundreds of JS files and when a bug occurs in &lt;code&gt;ParentComponent.js&lt;/code&gt; we feel tempted to convert it to TypeScript.&lt;/p&gt;

&lt;p&gt;In this case the following happens:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;exact shapes of data in &lt;code&gt;fetch-data.js&lt;/code&gt; stays unknown&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ParentComponent.tsx&lt;/code&gt; uses it with &lt;code&gt;any&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ChildComponent.js&lt;/code&gt; receives it and it's going to be an &lt;code&gt;unknown&lt;/code&gt; as well&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now a bit later someone else adds the types to both &lt;code&gt;fetch-data.js&lt;/code&gt; and &lt;code&gt;ChildComponent.js&lt;/code&gt;. Looking at the extension it seems &lt;code&gt;ParentComponent.tsx&lt;/code&gt; got migrated and trusted, but in reality the relevant data for &lt;code&gt;ChildComponent.tsx&lt;/code&gt; would be still &lt;code&gt;unknown&lt;/code&gt; but in this case we would not even know about it. The type inference would break in &lt;code&gt;ParentComponent.tsx&lt;/code&gt; and we are still poking in the darkness in &lt;code&gt;ChildComponent.tsx&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In my opinion this case is worse than having the component completely untyped as I would know to tread more carefully.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;To deal with this, I suggest starting from converting the files where data is originating from, which is going to be where the data is fetched or where it is produced through a form.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;TypeScript is great at inferring these schemas (unless you do the magic code; see below), so when you incrementally change your codebase you can then rely on these sources being correct. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Order grows out from the seeds of well-defined data sowed at the entry of your data flow.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A real world example is when I finally knew what a &lt;code&gt;validationError&lt;/code&gt; object looked like, I could correct a bug of a label for a validation error never showing up, e.g. the component code expected a singular &lt;code&gt;validationErrors.article&lt;/code&gt; property, but the actual property was &lt;code&gt;validationErros.articles&lt;/code&gt;. This is a super easy thing to miss.&lt;/p&gt;

&lt;p&gt;Note, that it was for a reason I have mentioned &lt;strong&gt;data drifting&lt;/strong&gt; and &lt;strong&gt;data standardization&lt;/strong&gt;: if you do these 2 steps correctly, now you are going to deal with robust types with very little ambiguity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Forgetting about Promises
&lt;/h2&gt;

&lt;p&gt;Let’s say your block of code might receive an image, convert it to another image format, save it to storage and create an entry for it. However, saving the image never gets awaited, and the code always goes to the next step, which is saving the data that might point to a non-existent storage location. Local testing does not find it, only some users complain that sometimes their uploaded photos disappear. &lt;/p&gt;

&lt;p&gt;While I haven’t encountered a developer who is fine with this, with JS codebases it happens way more often than people think.&lt;/p&gt;

&lt;h2&gt;
  
  
  Undefined variables, unsafe array or object operations, optional everything
&lt;/h2&gt;

&lt;p&gt;Recently I have found an ironic bug: an error never got reported as the error message used a variable that was defined in a different scope. No errors, no problem!&lt;/p&gt;

&lt;p&gt;As I said, it wastes so much time, because the error might get to you way later when you accidentally stumble upon it in the error logs of your container. Or it’s customers who report it.&lt;/p&gt;

&lt;p&gt;This is, just like “forgetting about promises” is a very frequent issue of JS codebases. It’s not a “developer issue”. It usually happens under certain circumstances, for example during a mentally taxing refactoring step: you move code around a lot, and then a variable like this slips through. (Obviously a good test coverage can spot these; that’s for another time.)&lt;/p&gt;

&lt;p&gt;Even if you work with very disciplined developers, some errors are just very hard to spot by looking at them, therefore people frequently forget about them. For example there are unsafe array operations: for example you want to grab the title of the first item in an array (&lt;code&gt;articles[0].title&lt;/code&gt;) there can be cases when the query returns 0 items, therefore &lt;code&gt;articles[0]&lt;/code&gt; will be &lt;code&gt;undefined&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Again, this is an everyday, average slip, it’s not a “character issue” of an (otherwise great) engineer. But we have a tool to warn us, and that’s TypeScript.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Saga of Magic Code That Could Not Have Been Typed
&lt;/h2&gt;

&lt;p&gt;Finally there is a situation where the “inconvenience of TypeScript” can actually help you write simpler code through making convoluted code painful to write; I will explain what I mean by this later. &lt;/p&gt;

&lt;p&gt;The flexibility of JavaScript allows transformations (e.g. add properties to a &lt;code&gt;function&lt;/code&gt;) that are extremely complicated to accurately type. I remember a magic function transformer that took a function, stapled variables from a redux store onto it binding the parameters and redux actions and the function together.&lt;/p&gt;

&lt;p&gt;The problem was that this custom piece of code was very hard to understand and took a lot of time to for every team member to get it. Contrary to this, working along coding standards saves a lot of time for engineers of an organization: any member from any team is now going to be able to deal with the code without needing to spend time and familiarize themselves with the inner workings of a contraption.&lt;/p&gt;

&lt;p&gt;I want to say &lt;code&gt;redux-saga&lt;/code&gt; is a similar case because of the usage of generator functions: there is an error by design there, I must mention. I have found typing these generator functions to be extremely hard. Try typing a saga (and using it in another TypeScript file) that for every yields might return a different value type. First an &lt;code&gt;undefined&lt;/code&gt; value (as in no explicit returned value), then a &lt;code&gt;Promise&lt;/code&gt; and finally an explicit value (say the third yield returns a sanitized &lt;code&gt;user&lt;/code&gt; object).&lt;/p&gt;

&lt;p&gt;One can argue that typing this and dealing with its ambiguity is just too much effort, therefore TypeScript puts shackles on the brilliant mind of a competent Javascript programmer, but my counter-argument is why do we need this flexibility?&lt;/p&gt;

&lt;p&gt;I mentioned “inconvenience” at the start of this paragraph: since most devs who work with TS are just not that level to be able to type these contraptions, they are not going to write these magic functions; which in my opinion is a very good thing.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Writing an extremely complicated function should be only a last resort anyways, after exhausting all simpler options. If TypeScript makes it harder, that’s even better.&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;p&gt;In my professional experience, &lt;strong&gt;fuzzy, heterogenous sources of data&lt;/strong&gt; and &lt;strong&gt;broken chains of data flow&lt;/strong&gt; cause the most issues in a TypeScript conversion, however I argue that it is not TS being at fault here; it is the toxic flexibility of JavaScript that delays dealing with the consequences of coding mistakes to runtime.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I sometimes call it “HDD”: hope driven development.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You hope that the data would look like how you’d expect it to look like. You hope that the unit tests are describing the data accurately and you won’t have false positives. You hope it will blow up before it blows up at the user.&lt;/p&gt;

&lt;p&gt;While it is exhausting to deal with these errors, it is way cheaper to address these during compile time than waiting until accidents happen to the customers. And for the entire company! &lt;/p&gt;

&lt;p&gt;With a solid TS codebase you will unlock your true velocity because then you can rely on your data and the tooling around it.&lt;/p&gt;

</description>
      <category>hottake</category>
      <category>javascript</category>
      <category>typescript</category>
    </item>
    <item>
      <title>The Challenges of Working in Big Tech: Interview with an ex-employee part 3</title>
      <dc:creator>András Tóth</dc:creator>
      <pubDate>Tue, 20 Aug 2024 05:56:12 +0000</pubDate>
      <link>https://dev.to/latobibor/the-challenges-of-working-in-big-tech-interview-with-an-ex-employee-part-3-21li</link>
      <guid>https://dev.to/latobibor/the-challenges-of-working-in-big-tech-interview-with-an-ex-employee-part-3-21li</guid>
      <description>&lt;p&gt;This is the third and last instalment of the interview with my friend about how big tech companies work and how the bureaucracy in these places can really grind someone down. We share these experiences to call attention to mental health safety issues in the tech industry.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Into Big Tech
&lt;/h2&gt;

&lt;p&gt;After I got fired from my previous workplace for not wanting to work 60+ hours a week, I wanted to show that I still had it in me. That’s why getting this job at one of the Big Tech companies became important. I prepared and practised a lot and finally got the job. &lt;/p&gt;

&lt;p&gt;During this time, my self-confidence was still very low. So low that I went to a therapist to work on it. The therapist listened to me for an hour and then said, &lt;em&gt;“I am very empathetic, and your story affected me: it lowered my own self-esteem as well, so I'm unsure how to help you.”&lt;/em&gt;  and then proceeded to charge me without any takeaways. 😅 It was quite a shock, and I didn’t try going to therapy for many years afterwards.&lt;/p&gt;

&lt;p&gt;But eventually, I arrived at my new team and stayed there for 6 years.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who Owns This Button? The Detective Work. 🔍
&lt;/h2&gt;

&lt;p&gt;At this company not all teams own a codebase. In my team, theoretically, we coded half the time and did consultancy the other half. In my case, I only coded about 10-20% of the time because I enjoyed client work more. (Plus, people tended to chase me for things, while my longer-term coding projects didn’t; they were only important for my own long-term goals…)&lt;/p&gt;

&lt;p&gt;Often, clients would ask a question obvious from their side: &lt;em&gt;“If I turn on these 2 options, why don’t we have the desired result?”&lt;/em&gt;. Those 2 options might be the work of 2 different teams in 2 different repositories with 2 different coding conventions, who might not be aware of each other’s work and might have created incompatible features… It was quite frustrating and time-consuming detective work to dig to the bottom of these requests. &lt;/p&gt;

&lt;p&gt;Another goal of the client-facing work was coming up with ideas for new features or necessary improvements that the product teams missed: so basically keeping an eye out for unmet needs and low-hanging fruit. You then supposedly fleshed out your own projects with a proof-of-concept attitude, then handed over the long-term support to a “real” product team. This sounded excellent in theory, but in reality, it was a constant uphill battle. After figuring out which team owned the feature you wanted to change (if any), you had to convince this much bigger team (consisting of many members from product marketing to data science) to allow us to make these changes while the team had their own - often conflicting - priorities.&lt;/p&gt;

&lt;p&gt;There was a lot of opportunity for friction: either the team was extremely busy with other things and did not have time to help us get familiar with their code base and coding conventions, or, on the contrary, they really liked the idea, but they wanted to do it themselves (but later…). Even if they agreed to let us do the project, they often did not have the capacity or motivation to understand our changes properly and take them over from us for long-term support. So, our new features were often deprecated soon after they shipped. Once, a product team scolded me over a broken feature we shipped for them, but it turned out that it worked great until they made a change and forgot to regression-test our feature. Since nobody has spent real time getting familiar with our work, this was bound to happen.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This huge barrier of entry and the constant struggle for approval was chipping away at me slowly, and I felt bumbling about complying with each team’s definition of high-quality code. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Bureaucracy of a Meritocracy
&lt;/h2&gt;

&lt;p&gt;In this company, we always had to find objective-looking, measurable metrics and KPIs (key performance indicators) to prove our existence, both individually and team-wise. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It was rubbing against my soul stronger and stronger when I instinctively knew what really mattered and what would be of great help to our clients, yet it was impossible to find a good metric to make it measurable. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For example, who wants to invest time in measuring having detailed and up-to-date documentation? Yet, it’s a task I felt was very important to do.&lt;/p&gt;

&lt;p&gt;Therefore, before any action, there was this block we had to overcome; let’s say if the task took an hour to deliver, then finding a relevant metric and justification took over 2-3 hours. Or at least this is how it felt. And abandoning an idea because of a lack of a good metric wasted so much mental and emotional energy. Plus, normally, you couldn’t just come up with a new metric unless we were in a planning phase; you had to ensure that it would positively affect your team's already agreed metrics. &lt;/p&gt;

&lt;p&gt;Disillusionment also crept up when I started doubting our metrics: were they really meaningful? &lt;/p&gt;

&lt;p&gt;The goals and KPIs tended to be very forward-looking, and the features actually used by our real-world users at the present time were often neglected and deprioritised. &lt;/p&gt;

&lt;p&gt;Some other metrics were brainchildren of stressed-out leaders made up during the beginning-of-year planning. I hated participating in brainstorming sessions where we wanted to develop ideas on moving these KPIs; it seemed so forced and selfish. Yet this was what senior team members like me were supposed to do; this was the path towards further promotion. I felt that if I stayed true to my values, I would never get promoted to the next level. &lt;/p&gt;

&lt;p&gt;The same was required individually: there was this very US American end-of-year “ritual” of stepping up and talking about your achievements. Your promotions or just the fact you can stay at the company depended on your “merits” and how you presented them. This was a social game, and &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I am not kidding. People spent &lt;em&gt;weeks&lt;/em&gt; before the end of the year to prepare and collect all their yearly achievements to ensure they were received well!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Writing about successful collaborations and selling our work internally took a lot of time that could have been spent instead during actual work. To me, it felt like there was no real value to the end users in this. And in order not to forget what you have worked on - which I frequently did - you had to take meticulous notes each day so later you would be able to demonstrate your value. I now realise that my bad memory and my inconsistent ability to do this bureaucracy were symptoms of my ADHD as well.&lt;/p&gt;

&lt;p&gt;This also meant that selfish, narcissistic people had a way better chance of moving upward in the ranks, and there were quite a few people like that in management positions. It also heavily favoured people with great communication skills, even in positions which didn’t need communication skills otherwise; for example, being a native speaker gave a huge unfair advantage. &lt;/p&gt;

&lt;h2&gt;
  
  
  The “No Blame Culture”
&lt;/h2&gt;

&lt;p&gt;On the positive side, I actually appreciated that the impact of our work was important and not the circumstances that counted, e.g. how many hours you have spent in the office. I also loved the “No Blame Culture”: whenever something broke, everyone worked side by side to fix the problem and ensure it would not happen again. Punishing the “culprit” was not a goal.&lt;/p&gt;

&lt;p&gt;It felt liberating that everyone always assumed the best of intentions, especially compared to the previous companies I worked at. At the investment bank where I worked previously, if you didn’t reply to an email the next day, they would CC the boss and their boss to make sure you followed up on the email… While here, people understood you might have been busy and only sent a friendly reminder to you instead. I will really miss this solution-oriented culture.&lt;/p&gt;

&lt;h2&gt;
  
  
  And Then… The Burnout
&lt;/h2&gt;

&lt;p&gt;Slowly but surely, this constant fear of “what if I can’t sell our achievements”, combined with the high effort required just to start anything, chipped away at my motivation.&lt;/p&gt;

&lt;p&gt;Looking back, there were signs of the coming crash: for example, I was losing interest and excitement during the above-mentioned KPI brainstorming sessions. I saw excited people around me, but my face gave away that I just could not give a f*** about it, and I could not come up with anything.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Yet another sign was the guilt of procrastination: I had spent a lot of time at the computer, yet I was not working on the important things, and I knew it. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As it was impossible to know the whole feature offering of the company in depth, in my team, we each became experts in 1-2 aspects and helped each other out when relevant client questions popped up. Unfortunately, my speciality eventually got deprioritised within the company and wasn’t actively worked on or even properly supported any more. I wasn’t selfish or wise enough to abandon this sinking ship on time because I truly believed in it. (Plus, I put so much effort into it; I have shipped various projects around it and onboarded some of the biggest clients.) So I was constantly fighting for the importance of this particular product, not just within my team but with the product team as well, which was supposed to own it. The owning team didn’t even properly understand the intricacies of their own product anymore, so I often ended up training their new team members on how it works. This situation was very unmotivating and wasn’t recognised by most people, including my manager (which is understandable as this shouldn’t have been my job). It was a great example of something that didn’t align with the team’s and company’s KPIs any more but was still important for our clients. &lt;/p&gt;

&lt;p&gt;Only positive personal interactions slowed the burnout process: if I could help somebody, if we had a good meeting, etc.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Burnout Kept Me in Harm’s Way
&lt;/h2&gt;

&lt;p&gt;During this time, I had this menacing feeling that “they are about to discover I work very little!”. However, at the last performance review, I received an above-expectations rating, which was quite baffling. Counterintuitively, it became demotivating as I now could not reach out for help and be open internally about the fact that I was struggling because my review praised me. About a year later, it started to become noticeable, unfortunately, just as the economic crisis and layoffs came.&lt;/p&gt;

&lt;p&gt;I knew I had problems, and I knew I really needed a change, yet I did not have the energy to make the change. Changing teams or roles within the company required good performance ratings and internal interviews to the same high standard as for external candidates. Plus, my mood was so low I couldn’t even imagine what change would make me more fulfilled. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It’s hard to think about your future when you are in survival mode! &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Making the decision to pull the plug and leave the company was also hard as some people call BigTech companies the &lt;strong&gt;“Golden Cage”&lt;/strong&gt;: you are paid well, you have great benefits, flexible working arrangements and motivated, bright colleagues. I’ve worked so hard to be here, and I couldn’t imagine where I could be happy if I’m suffering even under such - on the surface, at least - good circumstances. &lt;/p&gt;

&lt;p&gt;Personally, I think I got quite unlucky with the layoffs coming at the worst moment possible. Under normal circumstances, I would have probably eventually gotten the mental health help I needed and gotten out of the hole. It was pretty normal to have a bad performance rating from time to time and given that I had worked there for more than six years, my managers knew what I was capable of when I was not burnt out, so probably they would have given me some leeway. Even if they had put me on a performance improvement plan, that process would have given me months to get my sh*t together, which I probably would have done under pressure. (ADHD people work much better under pressure, at least for a short period of time…)&lt;/p&gt;

&lt;p&gt;But all in all, I think this was a blessing in disguise, so I’m grateful that this happened to me. It gave me the necessary kick in the butt to make the changes I needed. And the severance payout gave me the means to take some time off work and really think about my future. It took about six months for me to figure out that I have a passion for psychology and counselling, which is a much better way of helping people than client-facing tech jobs, so that is probably where my career change is leading me. It’s not a happy end just yet, as I’m still in training and not making a living off it yet, but I see the light at the end of the tunnel. &lt;/p&gt;

&lt;p&gt;— END OF THE LAST INSTALMENT —&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Hi, this is András again. One of the key topics of this interview was “self-surveillance” (I just made this term up): as companies go bigger, it is getting increasingly harder to figure out if things are going in the right direction. The inability to confidently monitor and understand where things go is then pushed as a “tax” onto the teams: time for coding is now converted into time for holding the hand of the management. The metrics are at least pointing to a more scientific method compared to how it was done previously.&lt;/p&gt;

&lt;p&gt;“Weak Ownership” was yet another topic with which I am also personally familiar, and I think it is still in its infancy. Usually, during team formation, a strong sense of “in-group” and “out-group” is formed (see also [“in-group/out-group bias"])(&lt;a href="https://en.wikipedia.org/wiki/In-group_favoritism)" rel="noopener noreferrer"&gt;https://en.wikipedia.org/wiki/In-group_favoritism)&lt;/a&gt;), which means that outsiders’ moves are watched with suspicion. Especially when bonuses or headcount depend on reaching goals. I have yet to see a team that is not incredibly busy with a backlog worthy of years of work, and I also never saw a company where it was OK just to sit and wait to see if anything comes up. (Note on idleness: it is absolutely necessary for, say, transportation, as if all maintenance crew are out doing busy work all the time, and then you have nobody to respond to emergencies. Yes, it’s inherently ineffective, yet it is a requirement if you want a quick response.)&lt;/p&gt;

&lt;p&gt;Thanks for reading the interview! This was the last part. If you have any questions, for me or my friend, just ask away in the comments below!&lt;/p&gt;

</description>
      <category>career</category>
      <category>mentalhealth</category>
      <category>management</category>
      <category>interview</category>
    </item>
    <item>
      <title>Do senior devs use terminal/VIM? Do they type faster?</title>
      <dc:creator>András Tóth</dc:creator>
      <pubDate>Mon, 24 Jun 2024 16:58:27 +0000</pubDate>
      <link>https://dev.to/latobibor/do-senior-devs-use-terminalvim-do-they-type-faster-glf</link>
      <guid>https://dev.to/latobibor/do-senior-devs-use-terminalvim-do-they-type-faster-glf</guid>
      <description>&lt;p&gt;A reply to this &lt;a href="https://dev.to/sotergreco/improve-your-productivity-by-using-more-terminal-and-less-mouse--2o7b"&gt;great post about productivity of console&lt;/a&gt; proved to be quite popular, so I decided to turn it into an article and add a bit of extra.&lt;/p&gt;

&lt;h2&gt;
  
  
  (Skippable) Little Story About DOS and &lt;code&gt;config.sys&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;First a little story. I was a kid in the 90s and my dad had a computer at home. I totally got sucked into it; mostly to play video games. Back in the day we had DOS (Disk Operating System) and it was terminal based. You started Windows 3.1 &lt;em&gt;from&lt;/em&gt; the terminal and not the other way around. 🙂🙃&lt;/p&gt;

&lt;p&gt;To juggle with files and folder, I used Norton Commander. It had two panes for two folders and you used F5 for example to copy (if I still remember correctly) from active pane to the other. I've gotten really-really fast with it, so fast in fact, that one day I have accidentally deleted the important looking &lt;code&gt;config.sys&lt;/code&gt; file. Since there was no "Bin" back then, and I didn't know about the &lt;code&gt;undelete&lt;/code&gt; command, it was a huge trauma to me: ruining dad's computer (which I didn't as I realized later) by being reckless. Later a friend of mine gave me his notes he learnt about DOS configuration in IT class, and I could recreate the file (and go back to playing games that required EMS memory handling instead of XMS).&lt;/p&gt;

&lt;p&gt;So it is safe to say I was growing up not using the mouse and doing everything in the terminal. Yet, I have no particular love for it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Do You Need Serious Terminal/VIM Skills?
&lt;/h2&gt;

&lt;p&gt;I try to use a great IDE as much as possible and the terminal as little as possible.&lt;/p&gt;

&lt;p&gt;Why? Let's say I'm writing and fixing unit tests. The jest integration runs in my Webstorm works as a breeze: I get diff, I can click on the failing test, it jumps to the relevant line in the codebase, I can put in a breakpoint if I want it and so on. Lightning fast, I have everything at my hands, no need to manually scroll, load, struggle with something. 21st century experience.&lt;/p&gt;

&lt;p&gt;I do advocate for learning the keyboard shortcuts while using the IDE and also to learn tricks like multiline cursor editing and so on, because they save so much time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Do you need great typing speed? Is using a mouse an anti-pattern?
&lt;/h2&gt;

&lt;p&gt;Now, about typing speed. When I code, I write a little and then mostly I think for a while, then type out my code, then check the results (either through a unit test or on the frontend). It's more like a quick chess game than a horse race. It's not a typing competition, it's not a copy-paste-modify extravaganza. In case I've written the samish thing multiple times I tend to step back to evaluate what to do with this repetition. Do I need to extract the code or am I expecting them to grow in a different direction very soon, therefore no need to extract the code? It requires stopping and thinking, nonetheless.&lt;/p&gt;

&lt;p&gt;Half of my "coding time" is actually also talking with stakeholders, making agreement with my colleagues on what to work on and what not to work on. Sometimes you do a lot of damage to a codebase if you start solving the problem in the wrong place (e.g. is doing the &lt;code&gt;join&lt;/code&gt; on the &lt;em&gt;frontend&lt;/em&gt; the right place for it or is it better suited in the &lt;em&gt;database&lt;/em&gt;?) and sometimes you have to advocate for an easier path to take.&lt;/p&gt;

&lt;h2&gt;
  
  
  Terminals, CLIs and Mental Mapping
&lt;/h2&gt;

&lt;p&gt;Finally, about CLIs: personally, I hate command line interfaces. They violate the &lt;em&gt;"avoid mental mapping"&lt;/em&gt; principle of clean coding: you have to memorize the flags for each CLI tool, remember if &lt;code&gt;-f&lt;/code&gt; stood for &lt;em&gt;file&lt;/em&gt; or &lt;em&gt;force&lt;/em&gt; or &lt;em&gt;folder&lt;/em&gt; or something completely different. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;There is no "Codex of CLI Conventions", no "Knights of Inter-CLI Consistence". Every CLI is special in its own ways, and to remember the quirks of each is mentally taxing for me.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The only things I do in the terminal are basically "npm start" or "npx something something". Very, very limited instructions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why People Might Prefer Terminal over Full-Fledged IDEs?
&lt;/h2&gt;

&lt;p&gt;This is going to be pure speculation on my side:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;maybe there is this "Coder/Hacker" image which glorifies stream of logs in consoles&lt;/li&gt;
&lt;li&gt;or people are influenced by a famous engineer who uses terminal for everything&lt;/li&gt;
&lt;li&gt;can be a bit of impostor syndrome: the Big Fish uses terminal and VIM therefore if I don't they will think I'm just an impostor; you are not! &lt;/li&gt;
&lt;li&gt;neurodivergency 1: some people have very low tolerance to any type of slowness, they prefer high responsivity; IDEs, since they provide many functions tend to have problems with that time-to-time&lt;/li&gt;
&lt;li&gt;neurodivergency 2: some people have excellent mental mapping abilities (great, reliable memory) like my university math professors; I assume they tend to prefer tools with hardcore mental mapping; since it's a "superability", not the norm, I would not force it on others, personally (I don't have it - I love clean code for this reason)&lt;/li&gt;
&lt;li&gt;using console is a great way to freak out grandma or your parents that you are so intelligent you can speak directly with the CPU&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Do Senior DEVs Use Terminal/VIM then?
&lt;/h2&gt;

&lt;p&gt;I think most of us do not. Personally, I feel there tend to be a lot of friction with the people who push CLIs and bash scripts on others as they increase the mental load on others who are neurologically not that great at mental mapping. If you can keep common projects working without hacking too much in the terminal, without adding magic lines to &lt;code&gt;.bashprofile&lt;/code&gt;, you should do your own thing. Also if you are working alone, you are 100% free to choose the methods that let you stay in the zone.&lt;/p&gt;

&lt;p&gt;Therefore my productivity hack is to get a good IDE and learn it well! The shortcuts, the multiline editing capabilities, the integrations (in my favorite IDE, you can run an SQL statement from a TypeScript to manually test your query; how cool is that?).&lt;/p&gt;

&lt;p&gt;In a team, you have to code and plan your productivity in accordance of the tools available. If you "muscle" your code through by typing quickly and a lot, there is a chance you will ignore very effective coding assistance tools, while you have the illusion of productivity since you type a lot, and press Enter a lot.&lt;/p&gt;

&lt;p&gt;In reality you might be doing double/triple work. Think before you strike!&lt;/p&gt;

</description>
      <category>programming</category>
      <category>console</category>
      <category>terminal</category>
    </item>
    <item>
      <title>Why I (mostly) never write `const fn = () =&gt; {}`</title>
      <dc:creator>András Tóth</dc:creator>
      <pubDate>Fri, 14 Jun 2024 19:16:21 +0000</pubDate>
      <link>https://dev.to/latobibor/why-i-mostly-never-write-const-fn--3j2i</link>
      <guid>https://dev.to/latobibor/why-i-mostly-never-write-const-fn--3j2i</guid>
      <description>&lt;p&gt;A short article here on a subjective/objective manner.&lt;/p&gt;

&lt;p&gt;Compare this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;justAConstant&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1244430&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;conditionalValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;justAConstant&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;13&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;yes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;no&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;updateResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;updateInDb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;conditionalValue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;updateInDb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/url&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;with this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;justAConstant&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1244430&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;conditionalValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;justAConstant&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;13&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;yes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;no&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;updateResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;updateInDb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;conditionalValue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;updateInDb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/url&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's start with the trivial matter: while &lt;code&gt;function&lt;/code&gt; is hoisted and you can declare wherever you want them (I like to define functions that solve partial problems under the function that solves the main problems) the order of constant declarations matter.&lt;/p&gt;

&lt;p&gt;In the above example will throw this error: &lt;code&gt;ReferenceError: can't access lexical declaration 'updateInDb' before initialization&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is, as I said, trivial, very easy to fix. However there's something more appealing to me in the second version:&lt;/p&gt;

&lt;p&gt;Separation of &lt;code&gt;values&lt;/code&gt; and &lt;code&gt;functions that operate over values&lt;/code&gt;. A quick glance at the second example will immediately show me where I can find the business logic, because they look different.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In UX design we plan for the ease of traversing the UI: things that are different must look different.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;While your preference to use &lt;strong&gt;named functions&lt;/strong&gt; vs. &lt;strong&gt;named unanymous functions saved as constants&lt;/strong&gt; is subjective it is good to know that categorization of syntactical elements can be objectively confusing or clear.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>codeux</category>
    </item>
    <item>
      <title>What's worse? `NullPointerException` or `try (error) {...} catch {// do nothing}`?</title>
      <dc:creator>András Tóth</dc:creator>
      <pubDate>Mon, 06 May 2024 19:56:35 +0000</pubDate>
      <link>https://dev.to/latobibor/whats-worse-nullpointerexception-or-try-error-catch-do-nothing-5002</link>
      <guid>https://dev.to/latobibor/whats-worse-nullpointerexception-or-try-error-catch-do-nothing-5002</guid>
      <description>&lt;p&gt;Sir Charles Antony Richard Hoare has an &lt;a href="https://www.youtube.com/watch?v=YYkOWzrO3xg" rel="noopener noreferrer"&gt;excellent presentation&lt;/a&gt; on why &lt;code&gt;null&lt;/code&gt; was a bad idea.&lt;/p&gt;

&lt;p&gt;There are even programming languages that try to eliminate the very problem of receiving a random &lt;code&gt;null&lt;/code&gt; value out of blue: &lt;a href="https://dev.to/marciofrayze/why-is-elm-such-a-delightful-programming-language-2em8#no-null-or-undefined-references"&gt;Elm is such language&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  In practice
&lt;/h2&gt;

&lt;p&gt;Usually when I encounter a &lt;code&gt;null&lt;/code&gt; related error the fix were kinda straightforward:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Check the stack trace&lt;/li&gt;
&lt;li&gt;Read the code in the location&lt;/li&gt;
&lt;li&gt;Either understand it immediately (&lt;em&gt;"Oh, me stupid donkey, I tried the wrong parent property!"&lt;/em&gt;) or put a debug point in.&lt;/li&gt;
&lt;li&gt;Debug the code.&lt;/li&gt;
&lt;li&gt;Fix and cover the error with test cases.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So, on average, I would say these are maybe 20-minute long adventures.&lt;/p&gt;

&lt;h2&gt;
  
  
  When you swallow the error on the other hand...
&lt;/h2&gt;

&lt;p&gt;Let's see this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;apiCall&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;unboxedResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nf"&gt;sendToSomeoneElse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;unboxedResult&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// nothing here!&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now &lt;strong&gt;this&lt;/strong&gt; is way worse! I have no clue why &lt;code&gt;sendToSomeoneElse&lt;/code&gt; was not called. Unless I'm actively developing this particular block of code I would not have any suspicion that there was an error in the first place!&lt;/p&gt;

&lt;h3&gt;
  
  
  The legendarily bad &lt;code&gt;angularjs&lt;/code&gt; template
&lt;/h3&gt;

&lt;p&gt;There was 2 key design mistakes in version 1 of &lt;code&gt;angularjs&lt;/code&gt; that caused countless hours of fruitless, laborious debugging sessions.&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Breaking convention of &lt;code&gt;html&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;When you read this: &lt;code&gt;&amp;lt;div data-something="This is a string!"&amp;gt;something&amp;lt;/div&amp;gt;&lt;/code&gt; you know that the &lt;code&gt;data-something&lt;/code&gt; attribute is now having a &lt;code&gt;"This is a string!"&lt;/code&gt; string.&lt;/p&gt;

&lt;p&gt;In first version of &lt;code&gt;angular&lt;/code&gt; you could write this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;ng-repeat=&lt;/span&gt;&lt;span class="s"&gt;"name in names"&lt;/span&gt; &lt;span class="na"&gt;ng-include&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"'template.html'"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note the moment where the convention is broken: &lt;code&gt;"'template.html'"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Even though we expect the HTML attribute to be parsed automatically to a &lt;code&gt;string&lt;/code&gt; value, the &lt;code&gt;angular&lt;/code&gt; engine differs here: if it is not enclosed in &lt;code&gt;'&lt;/code&gt; single-quotes, it tries to interpret it as an expression or - simply - as a variable.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. All templating errors were swallowed
&lt;/h2&gt;

&lt;p&gt;Now this is where the real problem started. In case you forgot the single-quotes (and &lt;em&gt;many, many&lt;/em&gt; people forgot it), you would now have an invalid expression. However the decision to swallow or templating errors (for whatever reason) meant...&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;you have had these innocent looking templates that just did not work as you expected!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I still remember vividly when my colleague from another team decided to escalate the question of &lt;em&gt;"Why does not this angular snippet work???"&lt;/em&gt; to the "frontend guild". I only answered it immediately: you missed the single-quotes. The mind of my colleagues were blown, how the hell did I know it so quickly?&lt;/p&gt;

&lt;p&gt;The reason was that in my previous workplace, with my previous team I had burnt my fingers with this very thing. We also had no clue what was going on, so:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I wasted many hours alone.&lt;/li&gt;
&lt;li&gt;I wasted then my team members' time to debug the issue.&lt;/li&gt;
&lt;li&gt;We then escalated to a larger group of devs to figure the issue and wasted their time...&lt;/li&gt;
&lt;li&gt;Until someone, just like me later, knew that this is a typical &lt;code&gt;angular&lt;/code&gt; error.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So I conclude swallowing errors is a grievous mistake and according to my anecdotic evidence, wastes more time than the well-established &lt;code&gt;NullPointerException&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>programming</category>
    </item>
    <item>
      <title>My love-hate relationship with JS/TS and CSS</title>
      <dc:creator>András Tóth</dc:creator>
      <pubDate>Thu, 11 Apr 2024 11:13:55 +0000</pubDate>
      <link>https://dev.to/latobibor/my-love-hate-relationship-with-jsts-and-css-14mj</link>
      <guid>https://dev.to/latobibor/my-love-hate-relationship-with-jsts-and-css-14mj</guid>
      <description>&lt;p&gt;&lt;em&gt;INSERT AI GENERATED HEADER IMAGE&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I frequently encounter comments that &lt;em&gt;love&lt;/em&gt; &lt;strong&gt;Javascript&lt;/strong&gt; and &lt;strong&gt;CSS&lt;/strong&gt; dearly. That is fine, but they reply in quite harsh manner when I point out several unmitigated mistakes of these languages.&lt;/p&gt;

&lt;p&gt;So this is how I see the stack as a professional JS/TS developer who worked with them for around 8/12 years (I used CSS for longer than JS).&lt;/p&gt;

&lt;p&gt;In the browser we have a lack of choice: you have &lt;strong&gt;Javascript&lt;/strong&gt;, &lt;strong&gt;CSS&lt;/strong&gt; and &lt;strong&gt;WASM&lt;/strong&gt;. You can't get a more performant language, you can't get a higher level language: whatever you code must boil down to these options. &lt;/p&gt;

&lt;p&gt;I contrast it with any other operating system, where you have a huge array of languages.&lt;/p&gt;

&lt;p&gt;Many years ago, a lot of companies moved their legacy platform-based solutions to the web. I was working once on a project that recreated (with better UX) a chat application running on Windows only. By moving to the web we instantly gained MacOS and Linux users.&lt;/p&gt;

&lt;p&gt;We could do this, because essentially the browser became a &lt;strong&gt;mini operating system&lt;/strong&gt;. If this is the case then we should treat it as such and expect the variety we have when we work with an OS.&lt;/p&gt;

&lt;p&gt;My next point is that...&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;languages (however beloved) in the browser were designed during a much different stage of the internet.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;People who hate &lt;strong&gt;CSS&lt;/strong&gt; usually hate it, because it has so many features and optimizations about how to create pleasing documentation (see also: &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_box_model/Mastering_margin_collapsing" rel="noopener noreferrer"&gt;margin collapse feature&lt;/a&gt;). On the other hand many of us have to deliver large scale applications that have very interactive UI; a thing for which CSS was not built (even though it is getting better at).&lt;/p&gt;

&lt;p&gt;People who hate &lt;strong&gt;JavaScript&lt;/strong&gt; hate it for its quirks and gimmicks (see also: &lt;code&gt;[] + {} === 0&lt;/code&gt; vs &lt;code&gt;{} + [] === [object Object]&lt;/code&gt;) which came from a person tasked to write a language in a week and he chose these and also because of backward compatibility of the language. Yet another reason is that fully dynamic languages suck at scaling: you end up with MDD: &lt;strong&gt;memory driven development&lt;/strong&gt; (in other words: you are cool if you remember &lt;em&gt;everything&lt;/em&gt; you wrote, 'cause the IDE can't help you), which is only not a problem when you code alone.&lt;/p&gt;

&lt;p&gt;Now all these limitations were and are somewhat mitigated by &lt;em&gt;an awesome community&lt;/em&gt;, who adds new elements to languages, like &lt;code&gt;flex&lt;/code&gt; to &lt;strong&gt;CSS&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;But these are &lt;strong&gt;mitigations&lt;/strong&gt; instead of &lt;strong&gt;purpose-building&lt;/strong&gt;. Imagine you want to fix throughput of trucks by chaining together many trucks; but it would be better to transport cargo on rails.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;JavaScript&lt;/strong&gt;, &lt;strong&gt;TypeScript&lt;/strong&gt;, &lt;strong&gt;CSS&lt;/strong&gt; are not bad languages, and I can be very productive working with them. But, and that's a big but, it's quirks and problems are causing constant troubles, especially for junior and mid-level engineers. The former are utterly confused at the quirks, the latter rage-quits problems and brute force patterns, like &lt;strong&gt;TailwindCSS&lt;/strong&gt; or &lt;strong&gt;OOP&lt;/strong&gt; or &lt;strong&gt;FP&lt;/strong&gt; onto languages that will never have the guarantees and optimizations for those approaches.&lt;/p&gt;

&lt;p&gt;As I said, I don't hate the languages of the Internet, but I wish for a bigger dose of healthy criticism and thinking out of the box. After all, we have now a huge amount of &lt;strong&gt;real world use cases&lt;/strong&gt; which we didn't have when CSS and JS were designed; it is normal to time-to-time to rewrite basics to better align with usages.&lt;/p&gt;

&lt;p&gt;It is foolish to think we can predict how tech will be used; it is even more foolish not to react how tech is actually used.&lt;/p&gt;

&lt;p&gt;I don't even dare to suggest things like "Can we have a separate engine for the case when I &lt;em&gt;don't&lt;/em&gt; have a document, but I do have rich UI inputs?", I just want to state the problems here.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>typescript</category>
      <category>css</category>
      <category>watercooler</category>
    </item>
  </channel>
</rss>
