<?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: Igor Vorobiov</title>
    <description>The latest articles on DEV Community by Igor Vorobiov (@ivorobioff).</description>
    <link>https://dev.to/ivorobioff</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%2F162004%2F5947b850-6bb5-4095-bde0-b3e4f4449546.jpg</url>
      <title>DEV Community: Igor Vorobiov</title>
      <link>https://dev.to/ivorobioff</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ivorobioff"/>
    <language>en</language>
    <item>
      <title>How I Migrated a Monolith Cron Job to a Serverless Architecture</title>
      <dc:creator>Igor Vorobiov</dc:creator>
      <pubDate>Mon, 09 Jun 2025 20:35:08 +0000</pubDate>
      <link>https://dev.to/ivorobioff/how-i-migrated-a-monolith-cron-job-to-a-serverless-architecture-5d1a</link>
      <guid>https://dev.to/ivorobioff/how-i-migrated-a-monolith-cron-job-to-a-serverless-architecture-5d1a</guid>
      <description>&lt;h2&gt;
  
  
  A brief background about the app
&lt;/h2&gt;

&lt;p&gt;It’s an app where users upload their data into categories. The app processes that data, runs some additional calculations and aggregations, and stores everything in a database. After that, users can view the resulting data in charts and grids on the website.&lt;/p&gt;

&lt;p&gt;There’s also a requirement to capture that data and upload it as CSV files to an S3 bucket — daily, per account and per category.&lt;/p&gt;

&lt;p&gt;There are around 20 categories and 10,000 accounts. So in total, the app needs to upload about 200,000 CSV files to S3 every day.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it was
&lt;/h2&gt;

&lt;p&gt;It all started with a simple cron job that ran a script every day at 5 AM.&lt;/p&gt;

&lt;p&gt;The script did 3 things per account and category:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Loaded data from the MySQL database&lt;/li&gt;
&lt;li&gt;Prepared the CSV file&lt;/li&gt;
&lt;li&gt;Uploaded it to S3&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here’s what it looked like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg75sg24v4vou8qyp1dyy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg75sg24v4vou8qyp1dyy.png" alt="cron job diagram" width="800" height="669"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Problems 🙄&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It’s &lt;strong&gt;not scalable&lt;/strong&gt; — any increase in categories or accounts would linearly increase execution time&lt;/li&gt;
&lt;li&gt;It’s &lt;strong&gt;not fault tolerant&lt;/strong&gt; — no built-in retry mechanism or partial success tracking could cause permanent export loss for an entire day&lt;/li&gt;
&lt;li&gt;It has &lt;strong&gt;a single point of failure&lt;/strong&gt; — if the machine dies or script crashes mid-way, there’s no recovery or continuation&lt;/li&gt;
&lt;li&gt;There’s &lt;strong&gt;no proper monitoring&lt;/strong&gt; — no visibility into what succeeded, failed, or how long it took&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How it’s now
&lt;/h2&gt;

&lt;p&gt;Obviously, the previous solution didn’t scale well and needed a fix — fast.&lt;/p&gt;

&lt;p&gt;Since we were already using AWS services, I decided to stay within that ecosystem.&lt;/p&gt;

&lt;p&gt;I realized that to get the best scalability and fault tolerance, each CSV file had to be prepared and exported separately.&lt;/p&gt;

&lt;p&gt;So, I broke the system down into three core components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Export Scheduler&lt;/strong&gt; — handles everything related to scheduling&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Export Trigger&lt;/strong&gt; — kicks off the export process for each file&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Export Runner&lt;/strong&gt; — does the actual work: loads the data, prepares the CSV, and uploads it to S3&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here’s what I came up with:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdkydc6hu6thb0okm7fyx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdkydc6hu6thb0okm7fyx.png" alt="aws serverless diagram" width="800" height="736"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here’s how the new system works, end to end:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;EventBridge&lt;/strong&gt; kicks things off by emitting a &lt;strong&gt;daily export event&lt;/strong&gt; — this is the trigger that starts the whole export flow.&lt;/li&gt;
&lt;li&gt;That event is picked up by the &lt;strong&gt;Export Trigger&lt;/strong&gt; lambda, which is responsible for fetching relevant &lt;strong&gt;application data&lt;/strong&gt; from the database and generating &lt;strong&gt;export requests&lt;/strong&gt; — one for each account and category.&lt;/li&gt;
&lt;li&gt;These requests are sent to a queue (or stream), which acts as a buffer and decouples the trigger from the actual export logic.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;Export Runner&lt;/strong&gt; lambda then processes each export request: it loads the data, prepares the CSV file, and uploads it directly to the &lt;strong&gt;S3 bucket&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Meanwhile, &lt;strong&gt;logs, metrics, and alarms&lt;/strong&gt; are pushed to CloudWatch, giving us visibility into what’s happening at every step — useful for monitoring and debugging.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What’s solved 🙂&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It’s &lt;strong&gt;scalable&lt;/strong&gt; — each file is handled separately, so the system can easily grow with more categories or accounts without slowing down.&lt;/li&gt;
&lt;li&gt;It’s &lt;strong&gt;fault tolerant&lt;/strong&gt; — if a single export fails, it won’t stop the others; failures are isolated and can be retried.&lt;/li&gt;
&lt;li&gt;It has &lt;strong&gt;no single point of failure&lt;/strong&gt; — the whole process runs on distributed, managed services, so there’s no risk of a script crashing and killing the job.&lt;/li&gt;
&lt;li&gt;It has &lt;strong&gt;proper monitoring&lt;/strong&gt; — with logs, metrics, and alarms, you can track what succeeded, what failed, and how long everything took.&lt;/li&gt;
&lt;li&gt;It’s built on &lt;strong&gt;AWS-native tools&lt;/strong&gt; — everything runs on managed services like Lambda, EventBridge, and S3, so there’s no infrastructure to manage or maintain.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Thanks for reading! If you want to stay updated with future posts, hit that follow button. And don’t hesitate to share your ideas or questions in the comments — I’m eager to hear from you!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>serverless</category>
      <category>lambda</category>
      <category>systemdesign</category>
    </item>
    <item>
      <title>Dependency Injection vs Service Locator</title>
      <dc:creator>Igor Vorobiov</dc:creator>
      <pubDate>Mon, 09 Jun 2025 14:17:42 +0000</pubDate>
      <link>https://dev.to/ivorobioff/dependency-injection-vs-service-locator-4keb</link>
      <guid>https://dev.to/ivorobioff/dependency-injection-vs-service-locator-4keb</guid>
      <description>&lt;p&gt;Many developers out there don’t see the difference between the dependency injection and the service locator design patterns. Yes, both of them are trying to solve the same problem — increase decoupling. We all know what benefits this give us when it comes to scaling, testing or simply reading the code.&lt;/p&gt;

&lt;p&gt;However, &lt;strong&gt;how do I know when to use dependency injection and when to use service locator?&lt;/strong&gt; I would say we should use both of them when appropriate.&lt;/p&gt;

&lt;p&gt;If I was asked to choose a single verb that best describes the dependency injection pattern I would choose “to give”. If you think about it, that’s exactly what we achieve with dependency injection after all. We simply give objects to an object.&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;const&lt;/span&gt; &lt;span class="nb"&gt;window&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;Window&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;door&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;Door&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;house&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;House&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;door&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, we give the window object and the door object to the house object.&lt;/p&gt;

&lt;p&gt;On the other hand, if I was asked to describe the service locator pattern with a single verb I would say “to take”. Just think about it. That’s what we do when we use a service locator. We take objects from an object.&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;const&lt;/span&gt; &lt;span class="nx"&gt;house&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;House&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 can see, we take the house object from the service locator.&lt;/p&gt;

&lt;p&gt;In many cases, the dependency injection and the service locator work as a single unit. We might not see it when the things are injected automagically but behind the scene the implementations of dependency injection rely on service locators in order to retrieve actual dependencies.&lt;/p&gt;

&lt;p&gt;This is how it might look like somewhere in the code:&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;const&lt;/span&gt; &lt;span class="nx"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dependencyTypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&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="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&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;resolvedInstance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;resolveInstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dependencies&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A service locator is pretty easy to implement. All you need is to have ability to get a requested instance by name or id and ability to check whether the requested instance actually exists. Worth to note that a service locator is often called a container. Both things are the same. Both of them are meant to provide instances or services however you prefer to call them. Of course, there’s a difference between a service and an instance when speaking about terms and purposes, but from the technical point of view they are all instances of certain classes.&lt;/p&gt;

&lt;p&gt;Here’s a primitive version of a service locator (aka container):&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;Container&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;instances&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&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;unknown&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="kd"&gt;get&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="nx"&gt;id&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;T&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="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;instances&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;instances&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&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="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&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;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;instances&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;register&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="nx"&gt;id&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;instance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&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;instances&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;instance&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;container&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;Container&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;house&lt;/span&gt;&lt;span class="dl"&gt;'&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;House&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="c1"&gt;// somewhere 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;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;house&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;house&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;house&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;p&gt;Additionally, I have provided the way to register services.&lt;/p&gt;

&lt;p&gt;The implementations of dependency injection usually inject dependencies into objects automatically. All you need is to provide a bit of configuration and that’s all. That’s pretty convenient in many cases, but there are cases when you have to use service locator to avoid the deadlock. This could happen when two instances are depended on each other via constructor. Here’s an example:&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;A&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;b&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="c1"&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;class&lt;/span&gt; &lt;span class="nc"&gt;B&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;a&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="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&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;a&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;A&lt;/span&gt;&lt;span class="p"&gt;(...);&lt;/span&gt; &lt;span class="c1"&gt;// We need B!&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;b&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;B&lt;/span&gt;&lt;span class="p"&gt;(...);&lt;/span&gt; &lt;span class="c1"&gt;// We need A!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, we cannot resolve any of the services because they are depended on each other. We cannot resolve the service A because it requires the service B, and we cannot resolve the service B because it requires the service A. To solve this, we need to retrieve one of the services in lazy-loading way. Meaning that, we should take one of the services from the service locator at the point when the service is actually needed and not in the constructor.&lt;/p&gt;

&lt;h2&gt;
  
  
  All in all
&lt;/h2&gt;

&lt;p&gt;Hope this article cleared some things up for you and you enjoyed reading it. &lt;br&gt;
You can also check out my service locator &lt;a href="https://www.npmjs.com/package/@ivorobioff/ioc-container" rel="noopener noreferrer"&gt;@ivorobioff/ioc-container&lt;/a&gt; on npm.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>bestpractices</category>
      <category>cleancode</category>
      <category>architecture</category>
    </item>
    <item>
      <title>The 5 Most Popular Ways APIs Communicate Today</title>
      <dc:creator>Igor Vorobiov</dc:creator>
      <pubDate>Mon, 09 Jun 2025 13:43:57 +0000</pubDate>
      <link>https://dev.to/ivorobioff/the-5-most-popular-ways-apis-communicate-today-1koe</link>
      <guid>https://dev.to/ivorobioff/the-5-most-popular-ways-apis-communicate-today-1koe</guid>
      <description>&lt;p&gt;APIs are essential for enabling communication between software systems. Over time, several popular methods have emerged — each with its own strengths and trade-offs. From the well-established SOAP protocol to modern approaches like GraphQL and gRPC, understanding these popular API communication styles helps developers choose the right tool for their needs. Let’s take a quick look at the five most popular ways APIs communicate today.&lt;/p&gt;

&lt;h2&gt;
  
  
  SOAP
&lt;/h2&gt;

&lt;p&gt;In short, it’s a protocol that enables developers to invoke methods on remote objects or services. It’s a pretty old dinosaur, both in terms of age and weight. It’s based on XML, which means it carries a lot of text — much more than REST or GraphQL.&lt;/p&gt;

&lt;p&gt;It was invented a long time ago and is known for being very secure, strict, and reliable. If you compare them like programming languages, SOAP is like Java, while REST is more like JavaScript.&lt;/p&gt;

&lt;p&gt;Because SOAP has been proven over time it’s still used by banks, enterprises, and governments today. There are still many legacy systems relying on it. However, it’s not recommended for new systems where speed and flexibility are important.&lt;/p&gt;

&lt;p&gt;So, how it works.&lt;/p&gt;

&lt;p&gt;It all starts with WSDL, where all available operations, inputs, outputs, and data types are defined in an XML file. Think of it as a spec for your services. Usually, it’s not written manually but generated from the server-side code.&lt;/p&gt;

&lt;p&gt;The client then uses that spec to generate code stubs, allowing developers to call methods on corresponding class instances to communicate with the server.&lt;/p&gt;

&lt;p&gt;Behind the scenes though, some XML is created and sent to the server via HTTP requests (in rare cases, there can be other means). The server in turn, parses the retrieved XML and maps its content to a corresponding method on the appropriate class instance, invoking it with the extracted parameters.&lt;/p&gt;

&lt;p&gt;The server then serializes the resulting object into XML and sends it back to the client as a response. The client, in turn, deserializes the received XML and continues working with the resulting object.&lt;/p&gt;

&lt;p&gt;Overall, developers on both sides don’t work with XML directly — they work with classes, as if the server and client were talking locally rather than remotely thanks to incredible tools available out there. However, this kind of abstraction can cause performance and reliability issues if not handled carefully.&lt;/p&gt;

&lt;h2&gt;
  
  
  REST
&lt;/h2&gt;

&lt;p&gt;First off, it’s an architectural style, not a protocol or a standard. It leverages the semantics of the HTTP protocol to interact with resources.&lt;/p&gt;

&lt;p&gt;A resource is any object or data entity that can be accessed or manipulated via the RESTful API — such as a user, product, order, file, etc.&lt;/p&gt;

&lt;p&gt;Each resource is identified by an endpoint, and operations on resources are performed using standard HTTP methods such as GET, POST, PUT, PATCH, and DELETE.&lt;/p&gt;

&lt;p&gt;An endpoint is a specific URL path in a RESTful API that clients can send requests to in order to perform actions or retrieve data.&lt;/p&gt;

&lt;p&gt;JSON is the most common format for data exchange, although XML and others are also possible.&lt;/p&gt;

&lt;p&gt;Typical endpoints follow a resource-oriented structure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;/resources&lt;/code&gt; — used to interact with the entire collection of a given resource type (e.g. get all resources, or create a new resource using the HTTP methods such as GET or POST respectively)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/resources/{id}&lt;/code&gt; — used to interact with a specific resource identified by its unique ID (e.g. get, delete, update or replace a specific resource using HTTP methods such as GET, DELETE, PATCH or PUT respectively)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s also possible to define sub-resources, which represent entities related to or dependent on a parent resource. These are typically accessed by extending the parent resource’s endpoint. For example, &lt;code&gt;/resources/{id}/sub-resources&lt;/code&gt; refers to the collection of sub-resources belonging to a specific resource, and &lt;code&gt;/resources/{id}/sub-resources/{sub-id}&lt;/code&gt; targets a specific sub-resource.&lt;br&gt;
This nesting can continue further if needed, but deeply nested structures are generally discouraged, as they can become hard to manage and understand.&lt;/p&gt;

&lt;p&gt;In contrast to SOAP, RESTful APIs are simple, lightweight, and easy to work with. They can be quickly implemented and tested using any HTTP client, such as Postman or curl.&lt;/p&gt;

&lt;p&gt;Thanks to their simplicity, RESTful APIs are widely used on the frontend to fetch data from servers. They are also commonly used for remote communication between backend services.&lt;/p&gt;

&lt;h2&gt;
  
  
  GraphQL
&lt;/h2&gt;

&lt;p&gt;At its core, GraphQL is a query language for APIs that allows clients to request data in precisely the shape they need. The data is always returned in JSON format.&lt;/p&gt;

&lt;p&gt;Unlike REST, which typically exposes multiple endpoints and returns fixed data structures, GraphQL uses a single endpoint (e.g., /graphql) and lets the client specify exactly which fields to include in the response. This approach gives clients greater flexibility and reduces over-fetching or under-fetching of data.&lt;/p&gt;

&lt;p&gt;GraphQL is also strongly typed. It requires a schema to be defined in advance, describing all object types, their fields, and the relationships between them. This schema serves multiple purposes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Validation:&lt;/strong&gt; The server can verify that incoming queries are well-formed and conform to the schema — ensuring correct field names, types, arguments, variables, and fragments before execution.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Introspection:&lt;/strong&gt; Clients can query the schema itself to discover available types and operations. This makes it possible to auto-generate documentation and client code — much like reflection in traditional programming languages.
Strong typing in GraphQL helps catch errors early, provides predictable responses, and enables powerful tooling like IDE autocompletion and static analysis.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While this may seem like a lot of overhead, the good news is you don’t have to build everything from scratch. There are robust GraphQL libraries and frameworks available for most languages that make it easy to set up a GraphQL server. That said, you’ll still need to implement resolvers — the functions that retrieve data for the requested fields.&lt;/p&gt;

&lt;p&gt;Finally, GraphQL is not limited to reading data. It also supports mutations for creating, updating, and deleting data. A mutation is similar to calling a function: you pass in arguments, the server executes the necessary logic (e.g., writing to a database), and a result is returned — often the modified data or a success flag.&lt;/p&gt;

&lt;p&gt;GraphQL is great in theory, but in reality it’s not always the case. I’ve been observing that frontends tend to reuse the same query across different places in an app regardless of whether the requested fields are needed or not, and it brings the entire idea of GraphQL into question.&lt;/p&gt;

&lt;p&gt;Also, it introduces extra complexity on the server side — you need to carefully manage resolvers, handle query depth, and deal with performance concerns.&lt;/p&gt;

&lt;p&gt;On top of that, caching becomes a lot trickier compared to REST, since everything goes through a single endpoint and traditional HTTP caching doesn’t really apply.&lt;/p&gt;

&lt;h2&gt;
  
  
  WebSocket
&lt;/h2&gt;

&lt;p&gt;It’s a communication protocol that creates a single connection between client and server and keeps it open until one of the parties closes it. It’s perfect for real-time applications like chat apps, live notifications, gaming, and collaborative tools.&lt;/p&gt;

&lt;p&gt;It’s quite different from traditional HTTP communication, but it cannot start without HTTP itself. The client and server begin with an HTTP handshake, which is then upgraded to a WebSocket connection.&lt;/p&gt;

&lt;p&gt;WebSocket doesn’t enforce any specific data type. It can be any text or binary data. So you are free to choose your own data format, let it be JSON, XML or some text.&lt;/p&gt;

&lt;p&gt;A WebSocket URL looks similar to an HTTP URL but uses the &lt;code&gt;ws://&lt;/code&gt; or &lt;code&gt;wss://&lt;/code&gt; scheme, where the latter is secure. It’s also possible to include ports and query parameters, like &lt;code&gt;wss://example.com:8080/chat?token=abc123&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;What’s great that WebSocket works over standard ports (80 and 443), so it generally passes through firewalls and proxies. Moreover, it can use existing authentication methods, but it requires custom handling because the protocol does not have built-in support for cookies, headers, or tokens once the connection is established.&lt;/p&gt;

&lt;p&gt;Usually, the client sends a token during the initial HTTP handshake. After that, the connection stays open without built-in ways to re-check authentication, so the server must manage access and security if for example a user’s token expires or his permissions change.&lt;/p&gt;

&lt;p&gt;All in all, WebSocket is not a replacement for HTTP APIs but a complement, designed for interactive, real-time features. It serves specific use cases and often works alongside traditional HTTP communication.&lt;/p&gt;

&lt;h2&gt;
  
  
  gRPC
&lt;/h2&gt;

&lt;p&gt;Briefly, gRPC solves the same problem as SOAP but does it much more efficiently with faster, smaller messages and modern technology.&lt;/p&gt;

&lt;p&gt;So, what are those technologies?&lt;/p&gt;

&lt;p&gt;gRPC uses Protocol Buffers (protobuf), which is a method to define and serialize structured data into a very small, efficient binary format instead of plain text like JSON or XML. This makes messages much smaller and faster to send.&lt;/p&gt;

&lt;p&gt;Then, gRPC sends these compact messages over HTTP/2, a modern version of the HTTP protocol that allows multiple messages to be sent simultaneously over a single connection (called multiplexing), supports faster data transfer, and enables features like bi-directional streaming between client and server.&lt;/p&gt;

&lt;p&gt;Together, protobuf and HTTP/2 make gRPC communication much faster and more efficient than older approaches.&lt;/p&gt;

&lt;p&gt;gRPC is secure because it automatically encrypts all data using TLS, preventing others from spying on or changing the messages. Since it runs over HTTP/2, it also supports token-based authentication — clients include tokens like JWTs or OAuth tokens with each request to prove their identity and permissions, making access control simple and reliable.&lt;/p&gt;

&lt;p&gt;Finally, just like with SOAP’s WSDL files, developers rarely work directly with raw gRPC .proto files that define data structures and service methods. Instead, they work with automatically generated code, thanks to powerful tools that handle this process seamlessly.&lt;/p&gt;

&lt;p&gt;gRPC is designed with a focus on low latency, scalability, and ease of use, often outperforming traditional REST APIs — especially for internal service-to-service communication — making it ideal for microservices and real-time applications.&lt;/p&gt;

&lt;p&gt;However, keep in mind that gRPC has its strengths but can’t fully replace RESTful APIs in frontend environments or similar use cases.&lt;/p&gt;

&lt;p&gt;First, browsers don’t natively support all the HTTP/2 features gRPC relies on, so workarounds are needed.&lt;/p&gt;

&lt;p&gt;Second, while Protocol Buffers are compact and efficient, they aren’t human-readable, making debugging and manual testing more difficult.&lt;/p&gt;

&lt;p&gt;Finally, learning gRPC means understanding HTTP/2, protobufs, and its unique concepts, which can be challenging, especially when working with strictly typed schemas.&lt;/p&gt;




&lt;p&gt;In short, APIs use different ways to send and receive data, each with its own strengths. SOAP is secure and reliable for older systems, REST is simple and widely used, GraphQL lets you ask for exactly what you need, WebSocket supports real-time connections, and gRPC is fast and efficient for modern services. Choosing the right one depends on what your project needs.&lt;/p&gt;

</description>
      <category>api</category>
      <category>rest</category>
      <category>microservices</category>
      <category>software</category>
    </item>
    <item>
      <title>A Simple Way to Implement Inversion of Control in TypeScript</title>
      <dc:creator>Igor Vorobiov</dc:creator>
      <pubDate>Mon, 09 Jun 2025 13:26:08 +0000</pubDate>
      <link>https://dev.to/ivorobioff/a-simple-way-to-implement-inversion-of-control-in-typescript-156m</link>
      <guid>https://dev.to/ivorobioff/a-simple-way-to-implement-inversion-of-control-in-typescript-156m</guid>
      <description>&lt;p&gt;What is Inversion of Control (IoC) anyway?&lt;/p&gt;

&lt;p&gt;So, practically speaking, it’s when someone else creates and gives me the things I need instead of creating them myself.&lt;/p&gt;

&lt;p&gt;Imagine you are a developer who needs tasks to work on. Instead of going out and choosing tasks yourself, a project manager assigns them to you.&lt;/p&gt;

&lt;p&gt;This is Inversion of Control in action: You don’t control how the tasks arrive — that responsibility is delegated to someone else. You just focus on doing the work.&lt;/p&gt;

&lt;p&gt;Similarly, in software, IoC means that components don’t create or manage their own dependencies — they get them from elsewhere, such as a container or a framework.&lt;/p&gt;

&lt;p&gt;This makes the system more decoupled, testable, and flexible, because parts of the system don’t need to know how to set up other parts.&lt;/p&gt;

&lt;p&gt;Alright, let’s see it in the code.&lt;/p&gt;

&lt;p&gt;⚠️This is terrible code!&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;TaskRepository&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;db&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MySql&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;findTasks&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="nx"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Task&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;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetchAll&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="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;row&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;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;row&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;class&lt;/span&gt; &lt;span class="nc"&gt;Backlog&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;repository&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TaskRepository&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;db&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MySql&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;repository&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;TaskRepository&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;getTasks&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Task&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;repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findTasks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;onlyEstemated&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;class&lt;/span&gt; &lt;span class="nc"&gt;Developer&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;backlog&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Backlog&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;db&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MySql&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;backlog&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;Backlog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;work&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;backlog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getTasks&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;done&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;developer&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;Developer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MySql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="nx"&gt;developer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;work&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, the database connection is created at the top level and passed manually through every layer. Each component constructs its own dependencies and directly depends on the database. This results in tight coupling and low flexibility — every component is aware of and tied to the database.&lt;/p&gt;

&lt;p&gt;If I ever want to change the source of my tasks (e.g., from MySQL to S3), I’ll need to modify multiple components. That’s brittle and hard to maintain.&lt;/p&gt;

&lt;p&gt;👍This is a much better approach!&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;Container&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;@ivorobioff/ioc-container&lt;/span&gt;&lt;span class="dl"&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;TaskRepository&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;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Source&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;container&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Container&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;source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;source&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;findTasks&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="nx"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Task&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;source&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetchAll&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="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;row&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;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;row&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;class&lt;/span&gt; &lt;span class="nc"&gt;Backlog&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;container&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Container&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;repository&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;TaskRepository&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;getTasks&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Task&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;repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findTasks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;onlyEstemated&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;class&lt;/span&gt; &lt;span class="nc"&gt;Developer&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;backlog&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Backlog&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;container&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Container&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;backlog&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Backlog&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;work&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;backlog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getTasks&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;done&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;container&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;Container&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;registerType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Developer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;registerType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Backlog&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;registerType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;TaskRepository&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;registerFactory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;source&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;MySql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&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;developer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Developer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;developer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;work&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we’ve introduced an IoC (Inversion of Control) container to manage dependencies. Each component depends only on what it truly needs — nothing more, nothing less. Only TaskRepository is aware of the database. All other components remain agnostic to how tasks are fetched.&lt;/p&gt;

&lt;p&gt;This means changing the data source (e.g., switching to S3) requires just one small change during system setup:&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="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;registerFactory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;source&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;S3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: Source is an interface, so any compatible implementation (MySQL, S3, etc.) can be easily swapped in. This decouples your code and makes it far more maintainable and extensible.&lt;/p&gt;




&lt;p&gt;💡If you’re looking for a lightweight and flexible IoC container to bring this pattern into your own projects, check out &lt;a href="https://www.npmjs.com/package/@ivorobioff/ioc-container" rel="noopener noreferrer"&gt;@ivorobioff/ioc-container&lt;/a&gt; on npm.&lt;/p&gt;

&lt;p&gt;It’s minimal, intuitive, and works well in both backend and frontend environments.&lt;/p&gt;

&lt;p&gt;For React developers, there’s also &lt;a href="https://www.npmjs.com/package/@ivorobioff/ioc-react" rel="noopener noreferrer"&gt;@ivorobioff/ioc-react&lt;/a&gt;, a seamless integration that makes dependency injection in React components simple and clean.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>architecture</category>
      <category>cleancode</category>
      <category>ioc</category>
    </item>
  </channel>
</rss>
