<?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: Brandon Gautama</title>
    <description>The latest articles on DEV Community by Brandon Gautama (@brandongautama).</description>
    <link>https://dev.to/brandongautama</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%2F1809111%2Faaf6b4d7-45f5-421b-9d2e-d30ea02562a0.jpeg</url>
      <title>DEV Community: Brandon Gautama</title>
      <link>https://dev.to/brandongautama</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/brandongautama"/>
    <language>en</language>
    <item>
      <title>Building Software with Clean Architecture</title>
      <dc:creator>Brandon Gautama</dc:creator>
      <pubDate>Wed, 04 Sep 2024 06:07:36 +0000</pubDate>
      <link>https://dev.to/brandongautama/building-software-with-clean-architecture-4h2g</link>
      <guid>https://dev.to/brandongautama/building-software-with-clean-architecture-4h2g</guid>
      <description>&lt;h2&gt;
  
  
  What is software architecture?
&lt;/h2&gt;

&lt;p&gt;It is the shape given to a software system. A software system is made up of individual components. What those components are, how they are arranged and the way they communicate with each other makes up its architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why clean architecture matters?
&lt;/h2&gt;

&lt;p&gt;The Only Constant is Change! There are two types of values of a software system: functionality (behavior) and architecture (structure). Its functionality value comes from the features it supports, while its architectural value comes from its ability to evolve and adapt to change. That flexibility depends critically on the shape of the system, the arrangement of its components, and the way those components are interconnected.&lt;/p&gt;

&lt;p&gt;A clean architecture facilitates the development, deployment, operation, and maintenance of the software system to support its lifecycle. A software system can work perfectly fine today and a good software architecture makes it easy to change if a new requirement comes in tomorrow. It is easy to develop, easy to maintain, and easy to deploy. On the other hand, a messy architecture is very resistant to change. &lt;/p&gt;

&lt;p&gt;The ultimate goal is to minimize the lifetime cost of the system and to maximize programmer productivity. If you hold change as a constant, you will learn to adapt and manage its complexities well. Your software should reflect this principle and allow itself to evolve and adapt.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to build software with clean architecture?
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;The strategy is to leave as many options open as possible, for as long as possible.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;What are the options that we need to leave open? They are the details that don’t matter.&lt;/p&gt;

&lt;p&gt;Software systems are made up of two major elements: policy and details. The policy encapsulates all the business rules and procedures. It is where the true value of the system lives. While the details are things that enable humans, other systems, and programmers to communicate with the policy, but do not impact the behavior of the policy. Examples of details are IO devices, databases, web systems, servers, frameworks, communication protocols, etc.&lt;/p&gt;

&lt;p&gt;The goal of the architect is to create a shape for the system that recognizes policy as the most essential element of the system while making the details &lt;em&gt;irrelevant&lt;/em&gt; to that policy. This allows decisions about those details to be &lt;em&gt;delayed&lt;/em&gt; and &lt;em&gt;deferred&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;A clean software architecture produces software systems that have the following characteristics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Independent of frameworks&lt;/em&gt; - The architecture does not depend on the existence of some library external libraries/frameworks. They are just tools and you should not force your system to the constraints of the specific frameworks.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Testable&lt;/em&gt; - The business rules can be tested without the UI, database, web server, or any other external element that are details.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Independent of the UI&lt;/em&gt; - The UI can change easily, without changing the rest of the system. A web UI could be substituted with a console UI without changing the business rules.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Independent of the database&lt;/em&gt; - You can swap out Oracle or SQL Server for Mongo, BigTable, CouchDB, etc. Your business rules are not bound to the database.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Independent of any external agency&lt;/em&gt; - Your business rules shouldn't know about the interfaces to the outside world.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh58k0ttj0hft8gboz53n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh58k0ttj0hft8gboz53n.png" alt="Software Architecture" width="800" height="570"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The concentric circles above represent different areas of software. The further in you go, the higher level the software becomes. The outer circles are mechanisms. The inner circles are policies.&lt;/p&gt;

&lt;p&gt;The overriding rule that makes this architecture work is the &lt;em&gt;Dependency Rule&lt;/em&gt;: &lt;em&gt;Source code dependencies must point only inward, toward higher-level policies.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Inner circles should never know anything the outer circles. Specifically, the name of something declared in an outer circle must not be mentioned by the code in an inner circle. That includes functions, classes, variables, or any other named software entity.&lt;/p&gt;

&lt;p&gt;By the same token, data formats declared in an outer circle should not be used by an inner circle, especially if those formats are generated by a framework in an outer circle. We don’t want anything in an outer circle to impact the inner circles.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Entities&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Entities are where the enterprise-wide Critical Business Rules lives. They can be used by many different applications in the enterprise, or they can just be the business objects of an application. They encapsulate the most general and high-level rules. They are the least likely to change when something external changes. For example, you would not expect these objects to be affected by a change to page navigation or security. No operational change to any particular application should affect the entity layer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Use Cases&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The software in the use cases layer contains &lt;em&gt;application-specific&lt;/em&gt; business rules. They orchestrate the flow of data to and from the entities, and direct those entities to use their Critical Business Rules to achieve the goals of the use case.&lt;/p&gt;

&lt;p&gt;Any change in this layer should not affect the entities. We do not expect this layer to be affected by changes to externalities such as the database, the UI, or any of the common frameworks. However, we do expect that changes to the operation of the application will affect the use cases and, therefore, the software in this layer. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Interface Adapters&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This layer contains adapters that convert data from the format most convenient for the use cases and entities, to the format most convenient for some external components such as the database or the web. It is this layer, for example, that contain the MVC architecture of a GUI. The presenters, views, and controllers all belong in this layer. The models are likely just data structures that are passed from the controllers to the use cases, and then back from the use cases to the presenters and views.&lt;/p&gt;

&lt;p&gt;No code inward of this circle should know anything at all about the database. If the database is a SQL database, then all SQL should be restricted to this layer.&lt;/p&gt;

&lt;p&gt;This layer also contain any other adapter necessary to convert data from some external form, such as an external service, to the internal form used by the use cases and entities.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Frameworks and Drivers&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The outermost layer of the model is generally composed of frameworks and tools such as the database and the web framework. Generally you don’t write much code in this layer, other than glue code that communicates to the next circle inward.&lt;/p&gt;

&lt;p&gt;The frameworks and drivers layer is where all the details go. The web is a detail. The database is a detail. We keep these things on the outside where they can do little harm.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Conforming to these rules allow you to build a flexible system. By separating the software into layers and conforming to the Dependency Rule, you will create a system that is intrinsically testable and adaptable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;References&lt;/strong&gt;: The content of this article is referencing concepts/ideas from the book Clean Architecture by uncle Bob (Robert C. Martin). It is a really great book that I recommend to further if you're interested about software architecture.&lt;/p&gt;

&lt;p&gt;Clean Architecture: A Craftsman's Guide to Software Structure and Design (Robert C. Martin Series). Buy it here: &lt;a href="https://amzn.to/3SJguhf" rel="noopener noreferrer"&gt;https://amzn.to/3SJguhf&lt;/a&gt;&lt;/p&gt;

</description>
      <category>softwareengineering</category>
      <category>architecture</category>
      <category>softwaredevelopment</category>
      <category>software</category>
    </item>
    <item>
      <title>Software Component Design Principles</title>
      <dc:creator>Brandon Gautama</dc:creator>
      <pubDate>Thu, 22 Aug 2024 04:56:34 +0000</pubDate>
      <link>https://dev.to/brandongautama/software-component-design-principles-2g2c</link>
      <guid>https://dev.to/brandongautama/software-component-design-principles-2g2c</guid>
      <description>&lt;p&gt;In my last &lt;a href="https://dev.to/brandongautama/the-solid-design-principles-319f"&gt;post&lt;/a&gt;, I wrote about SOLID design principles that guides us on how to arrange/create modules from functions and data. Combining these modules together, we get a deployable component. In this article, we will look at some component cohesion principles and component coupling principles.&lt;/p&gt;

&lt;p&gt;What is a Component?&lt;br&gt;
Components are units of deployment. They are the smallest entities that can be deployed as part of a system. In Java, they are jar files.&lt;/p&gt;

&lt;h2&gt;
  
  
  A. Component Cohesion Principles.
&lt;/h2&gt;

&lt;p&gt;Let's take a look at the 3 principles of component cohesion, which gives us guidance on which classes belong in which components. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A1. REP: The Reuse/Release Equivalence Principle&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;The granule of reuse is the granule of release.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Dependency management tools have become very important due to the vast number of reusable components and component libraries that have been created. Whenever we write a software, it is very likely that we depend on multiple external dependencies. &lt;/p&gt;

&lt;p&gt;The Reuse/Release Equivalence Principle states that people who want to reuse software components cannot, and will not, do so unless those components are tracked through a release process and are given release numbers. This is to ensure that all the reused components are compatible with each other and for software developers to know what each new releases will bring.&lt;/p&gt;

&lt;p&gt;From a software design and architecture point of view, this principle means that the classes and modules that are formed into a component must belong to a cohesive group and they should be releasable together. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why is this important?&lt;/strong&gt; Reusability - Group classes into a component for reusability.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A2. CCP: The Common Closure Principle&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;Gather into components those classes that change for the same reasons and at the same times. Separate into different components those classes that change at different times and for different reasons.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This is the Single Responsibility Principle restated for components. The CCP gathers together all the classes that are likely to change for the same reasons into the same component. This minimizes the workload related to releasing, revalidating, and redeploying the software.&lt;/p&gt;

&lt;p&gt;For most applications, maintainability is more important than reusability. If the code in an application must change, you would rather make those changes in just one component, rather than making changes across many components, so that we only have to redeploy one component.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why is this important?&lt;/strong&gt; Developability/Maintainability - Group classes into a component so changes will be done in just one component, thus easier to release.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A3. CRP: The Common Reuse Principle&lt;/strong&gt; &lt;br&gt;
&lt;em&gt;Don’t force users of a component to depend on things they don’t need.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The CRP states that classes and modules that tend to be reused together belong in the same component. For example, a component contains both the container class and its associated iterators as they are tightly coupled to each other. &lt;/p&gt;

&lt;p&gt;The CRP also tells us which classes not to keep together in a component. Every time a dependency component is changed, our component will need to be recompiled, revalidated and redeployed. This is true even if our component doesn’t care about the change made in the used components.&lt;/p&gt;

&lt;p&gt;The CRP is the generic version of the ISP. The ISP advises us not to depend on classes that have methods we don’t use. The CRP advises us not to depend on components that have classes we don’t use.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why is this important?&lt;/strong&gt; Separate classes into different components to avoid unnecessary releases for our upstream dependencies (since they may not need every change in the component)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tension between the 3 Component Cohesion Principles:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The three cohesion principles tend to fight with each other. The REP and CCP are inclusive principles (they tend to make components larger), while the CRP is an exclusive principle (driving components to be smaller). It is the tension between these principles that architects seek to resolve. &lt;/p&gt;

&lt;p&gt;Balancing these forces with the needs of the application is always dynamic. That is, the partitioning that is appropriate today might not be appropriate next year. &lt;/p&gt;

&lt;p&gt;Generally, projects tend to sacrifice reuse (developability is more important than reuse). As the project matures, and other projects begin to draw from it, the project will change focus towards reuse. This means that the component structure of a project can vary with time and maturity. &lt;/p&gt;

&lt;h2&gt;
  
  
  B. Component Coupling Principles.
&lt;/h2&gt;

&lt;p&gt;Now that we've looked at how to arrange classes into component, let us take a look at how these components should be related to each other, also known as Component Coupling Principles. There are three of them:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;B1. ADP: The Acyclic Dependencies Principle&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;Allow no cycles in the component dependency graph.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;To release a component, it must be compatible with its dependencies. It is common to create a new component that depends on a bunch of other dependency components. Those dependency components then depend on more components. Every time any of those dependency component change, there is a risk that it might break the dependent component. This problem is aggravated if there is a cycle in the dependency graph. Releasing a component is much more difficult since it must not break its dependents and those dependents happen to be its dependencies too. Additionally, what is the correct build order? There is no correct answer. &lt;/p&gt;

&lt;p&gt;Let's say you have a cycle in the dependency graph, how to fix it? You can apply the Dependency Inversion Principle by inserting interface between those components so they depend on the interface instead.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;B2. SDP: The Stable Dependencies Principle&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;Depend in the direction of stability.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A component is stable if it is hard to change while a component is flexible if it can be changed easily. &lt;/p&gt;

&lt;p&gt;What is hard to change? If a change requires multiple dependent components to recompile.&lt;/p&gt;

&lt;p&gt;This principle states that we must ensure that the modules that are intended to be easy to change are not depended on by modules that are harder to change. In other words, to keep a component flexible, it should not be depended on by a lot of modules. &lt;/p&gt;

&lt;p&gt;For example, DoorDash and Grubhub calls TheRestaurant service. TheRestaurant is stable because it is being depended on by multiple dependents. Any change to TheRestaurant has to ensure it does not break both DoorDash and Grubhub. So TheRestaurant is stable and not flexible. But we want to keep TheRestaurant flexible so that its changeable. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2htdb954yg247xvwba98.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2htdb954yg247xvwba98.png" alt="TheRestaurant depended on by multiple dependents" width="406" height="266"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can fix this by employing the DIP, by creating an interface that DoorDash/Grubhub can call. TheRestaurant itself will implement the interface. These interfaces contains nothing but an interface and this is very common because they are very stable and ideal targets for less stable components to depend on.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5kr4l4dz5kho2k0fcmj0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5kr4l4dz5kho2k0fcmj0.png" alt="TheRestaurant becomes flexible now with the interface in between" width="646" height="266"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;B3. SAP: The Stable Abstractions Principle&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;A component should as abstract as it is stable.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Some software in the system should not change very often. They are high-level architecture and policy decisions. We don’t want these business and architectural decisions to be volatile. But if they are stable, then the source code that represents those policies will be difficult to change and make the overall architecture inflexible. This can be fix using OCP by creating Abstract Classes. &lt;/p&gt;

&lt;p&gt;A stable component should be abstract so that its stability does not prevent it from being extended. On the other hand, an unstable component should be concrete since its instability allows the concrete code within it to be easily changed.&lt;/p&gt;

&lt;p&gt;Thus, if a component is to be stable, it should consist of interfaces and abstract classes so that it can be extended. Stable components that are extensible are flexible and do not overly constrain the architecture. &lt;/p&gt;

&lt;p&gt;Combining SDP and SAP, we can conclude that &lt;em&gt;dependencies run in the direction of abstraction.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;br&gt;
In this article, we have explored Component Cohesion Principles and Component Coupling Principles. Component Cohesion Principles gives us guidance on which classes belong in which components, while Component Coupling Principles gives us guidance on how to arrange these components together.&lt;/p&gt;

&lt;p&gt;References: The content of this article is referencing concepts/ideas from the book Clean Architecture by uncle Bob (Robert C. Martin). It is a really great book that I recommend to further if you're interested about software architecture.&lt;/p&gt;

&lt;p&gt;Clean Architecture: A Craftsman's Guide to Software Structure and Design (Robert C. Martin Series). Buy it here: &lt;a href="https://amzn.to/3SJguhf" rel="noopener noreferrer"&gt;https://amzn.to/3SJguhf&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The 3 Programming Paradigms&lt;br&gt;
&lt;a href="https://dev.to/brandongautama/the-3-programming-paradigms-34pe"&gt;https://dev.to/brandongautama/the-3-programming-paradigms-34pe&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The SOLID Design Principles&lt;br&gt;
&lt;a href="https://dev.to/brandongautama/the-solid-design-principles-319f"&gt;https://dev.to/brandongautama/the-solid-design-principles-319f&lt;/a&gt;&lt;/p&gt;

</description>
      <category>softwareengineering</category>
      <category>softwaredevelopment</category>
      <category>architecture</category>
      <category>learning</category>
    </item>
    <item>
      <title>The SOLID Design Principles</title>
      <dc:creator>Brandon Gautama</dc:creator>
      <pubDate>Sat, 17 Aug 2024 18:26:01 +0000</pubDate>
      <link>https://dev.to/brandongautama/the-solid-design-principles-319f</link>
      <guid>https://dev.to/brandongautama/the-solid-design-principles-319f</guid>
      <description>&lt;p&gt;In this article, we will explore the SOLID design principles and their architectural implications. &lt;/p&gt;

&lt;p&gt;The SOLID design principles guide us on how to arrange our functions and data structures into classes. Now, what if a programming language does not have the concept of a class? A class is simply a coupled grouping of functions and data, so the principles apply to these logical groupings.&lt;/p&gt;

&lt;p&gt;These principles enable us to create flexible software modules that tolerate change, are easy to understand and are reusable.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. SRP: The Single Responsibility Principle
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;A module should have one, and only one, reason to change.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Note that the principle is not saying that every module should do just one thing, but rather, they have only one reason to 'change'. Software systems are subject to 'change' to satisfy users and stakeholders. In other words, a module should only serve one group of users/stakeholders.&lt;/p&gt;

&lt;p&gt;What is a module? The simplest definition is just a source file and this definition suffice for most purposes. A module is just a cohesive set of functions and data structures.&lt;/p&gt;

&lt;p&gt;As an example, given Employee class with 2 functions: &lt;code&gt;calculatePay()&lt;/code&gt; and &lt;code&gt;reportHours()&lt;/code&gt;. This module serves both the Accounting department and HR department. Accounting department only uses &lt;code&gt;calculatePay()&lt;/code&gt; while HR department only uses &lt;code&gt;reportHours()&lt;/code&gt;. Now, let's say both functions depend on a common method &lt;code&gt;getHoursPerWeek()&lt;/code&gt;. If Accounting department wants to tweak &lt;code&gt;getHoursPerWeek()&lt;/code&gt;, HR department is forced to consume that change too (even when HR do not want this tweak). This is violating SRP since any change requested by Accounting department may accidentally affect the HR department. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What can we learn from this principle?&lt;/strong&gt;&lt;br&gt;
Changeability - The SRP says to separate code that supports different users/stakeholders. This will help us create flexible systems that tolerate changes. We can apply this principle at the architectural level to create appropriate architectural boundaries.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. OCP: The Open-Closed Principle
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;A software artifact should be open for extension but closed for modifications.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Imagine a system that displays a financial summary on a web page. Now we are asked to print the same information on a paper in a different format.&lt;/p&gt;

&lt;p&gt;Clearly, some new code must be written. But how much old code will have to change? Ideally, zero.&lt;/p&gt;

&lt;p&gt;How? By properly separating the modules that change for different reasons (the Single Responsibility Principle), and then properly organizing the dependencies between those modules (the Dependency Inversion Principle).&lt;/p&gt;

&lt;p&gt;Note that generating the report involves two separate responsibilities: data calculation and data presentation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frysbqgnapbs6g7fmtaci.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frysbqgnapbs6g7fmtaci.png" alt="Extending Data Presentation Module" width="571" height="191"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We then  organize the source code dependencies to ensure that changes to data presentation module do not cause changes in the data calculation module. In this way, we have extended a system to support paper-based format without modifying the current system.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What can we learn from this principle?&lt;/strong&gt;&lt;br&gt;
Extendability - The idea is to make the system easy to extend without incurring much change to the existing system. This is accomplished by partitioning the system into components, and arranging those components into a dependency hierarchy that protects higher-level components from changes in lower-level components.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. LSP: The Liskov Substitution Principle
&lt;/h3&gt;

&lt;p&gt;Another way to think of the LSP is the "Plugin Architecture" that polymorphism provides in object-oriented programming. (&lt;a href="https://dev.to/brandongautama/the-3-programming-paradigms-34pe"&gt;Read more here&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;In this architecture, modules can be substituted for one another as long as they adhere to the same interface.&lt;/p&gt;

&lt;p&gt;The world of web is surrounded with interfaces in the form of REST APIs. Consider a food ordering service where a user can order from different restaurants in the same app. Internally, this food ordering service makes a &lt;code&gt;GET&lt;/code&gt; call to &lt;code&gt;/order&lt;/code&gt; URL. Each restaurant has different implementations for the order but they all expose the same &lt;code&gt;/order&lt;/code&gt; URL for the food ordering service to call. Food ordering service do not need to have restaurant-specific logic because of the well-defined interface. This is a good application of LSP where an interface enable substitutions of implementations.&lt;/p&gt;

&lt;p&gt;Another example is when we write code to read from &lt;code&gt;STDIN&lt;/code&gt;, we are programming to the interface &lt;code&gt;STDIN&lt;/code&gt;. &lt;code&gt;STDIN&lt;/code&gt; can can be swapped with multiple device drivers implementations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What can we learn from this principle?&lt;/strong&gt;&lt;br&gt;
Substitutability -  LSP is applicable because there are users who depend on well-defined interfaces, and on the substitutability of the implementations of those interfaces.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. ISP: The Interface Segregation Principle
&lt;/h3&gt;

&lt;p&gt;The ISP states that we should avoid depending on things that we don’t use.&lt;/p&gt;

&lt;p&gt;Going back to the Employee class example with 2 functions: &lt;code&gt;calculatePay()&lt;/code&gt; and &lt;code&gt;reportHours()&lt;/code&gt;. Let's say both the AccountingDepartment class and HRDepartment class imports and calls the same Employee class. Any change to one of the methods forces both caller to be recompiled and redeployed. Although AccountingDepartment class only uses &lt;code&gt;calculatePay()&lt;/code&gt;, it inadvertently depend on &lt;code&gt;reportHours()&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ddbuaguo9n446svf1ch.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ddbuaguo9n446svf1ch.png" alt="Before applying ISP" width="336" height="181"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This can be fixed by creating 2 interfaces, one for each function and AccountingDepartment only interface with the one containing &lt;code&gt;calculatePay()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhj895l78vl1b2mk9n03x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhj895l78vl1b2mk9n03x.png" alt="After applying ISP" width="336" height="241"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What can we learn from this principle?&lt;/strong&gt;&lt;br&gt;
Avoid unnecessary dependencies to not overcomplicate system.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. DIP: The Dependency Inversion Principle
&lt;/h3&gt;

&lt;p&gt;The Dependency Inversion Principle (DIP) tells us that the most flexible systems are those in which source code dependencies refer only to abstractions, not to concrete implementations.&lt;/p&gt;

&lt;p&gt;In Java, this means that we only &lt;code&gt;import&lt;/code&gt; modules that are interfaces or abstract classes.&lt;/p&gt;

&lt;p&gt;You might ask, what about String (&lt;code&gt;java.lang.string&lt;/code&gt;) class? String class is very stable with rare changes, so we do not have to worry about frequent and capricious changes to String. It is the volatile concrete elements of our system that we want to avoid depending on. Those are the modules that we are actively developing, and that are undergoing frequent change.&lt;/p&gt;

&lt;p&gt;Interfaces are less volatile than implementations. Indeed, good software designers and architects work hard to reduce the volatility of interfaces. They try to find ways to add functionality to implementations without making changes to the interfaces. This is Software Design 101.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What can we learn from this principle?&lt;/strong&gt;&lt;br&gt;
Stable software architectures are those that avoid depending on volatile concretions, and that favor the use of stable abstract interfaces.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Interface! By creating well-defined interfaces that has only one reason to change and programming to those interfaces, it enables us to create appropriate architectural boundaries that allow our systems to change flexibly. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;References&lt;/strong&gt;: The content of this article is referencing concepts/ideas from the book Clean Architecture by uncle Bob (Robert C. Martin). It is a really great book that I recommend to further if you're interested about software architecture.&lt;/p&gt;

&lt;p&gt;Clean Architecture: A Craftsman's Guide to Software Structure and Design (Robert C. Martin Series). Buy it here: &lt;a href="https://amzn.to/3SJguhf" rel="noopener noreferrer"&gt;https://amzn.to/3SJguhf&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The 3 Programming Paradigms&lt;br&gt;
&lt;a href="https://dev.to/brandongautama/the-3-programming-paradigms-34pe"&gt;https://dev.to/brandongautama/the-3-programming-paradigms-34pe&lt;/a&gt;&lt;/p&gt;

</description>
      <category>designpatterns</category>
      <category>solidprinciples</category>
      <category>learning</category>
      <category>systemdesign</category>
    </item>
    <item>
      <title>The 3 Programming Paradigms</title>
      <dc:creator>Brandon Gautama</dc:creator>
      <pubDate>Mon, 12 Aug 2024 05:32:38 +0000</pubDate>
      <link>https://dev.to/brandongautama/the-3-programming-paradigms-34pe</link>
      <guid>https://dev.to/brandongautama/the-3-programming-paradigms-34pe</guid>
      <description>&lt;p&gt;In this article, we will explore the 3 programming paradigms and what we can learn from them. As we go through each paradigm, we will see that each tells us what not to do, more than they tell us what to do.&lt;/p&gt;

&lt;p&gt;Paradigms are ways of programming that tells you which programming structures to use, and when to use them. There are 3 main paradigms: &lt;em&gt;structured programming&lt;/em&gt;, &lt;em&gt;object-oriented programming&lt;/em&gt; and &lt;em&gt;functional programming&lt;/em&gt;. These paradigms are not programming languages, but rather, programming languages have evolved to cater to the paradigms they target. Java and C++ are examples of object-oriented programming languages, while Lisp and Haskell are examples of functional programming languages.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Structured Programming
&lt;/h3&gt;

&lt;p&gt;This is probably the first paradigm that we were taught when we first learned programming. This is also the first paradigm ever to be adopted. It was formalized by Edsger Dijkstra in 1968, where he discovered that all programs can be constructed from just three structures: sequence, selection (&lt;code&gt;if/else&lt;/code&gt;) and iteration (&lt;code&gt;do/while&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Structured programming allows modules that used simple selection and iteration control structures to be recursively subdivided into "provable" units over and over, ad infinitum. &lt;/p&gt;

&lt;p&gt;Dijkstra once said, “Testing shows the presence, not the absence, of bugs.” A program can be proven incorrect by a test, but it cannot be proven correct. The implications of this fact are stunning. Software development is not a mathematical endeavor, rather, it is science. In Mathematics, we try to prove statements/formulas to be true while in science, we show correctness by not being able to prove its incorrectness. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What can we learn from this paradigm?&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Functional Decomposition&lt;/strong&gt; - structured programming forces us to recursively decompose a program into into smaller functions using divide-and-conquer. We then use tests to try to prove these small provable functions are correct enough for our purposes. &lt;/p&gt;

&lt;h3&gt;
  
  
  2. Object-oriented Programming (OOP)
&lt;/h3&gt;

&lt;p&gt;What is OO? Encapsulation, inheritance and polymorphism. It provides a way to model the real world by combining data and function using "objects", thus the name object-oriented programming. &lt;/p&gt;

&lt;p&gt;In OOP, we use polymorphism extensively along with dependency inversion. They enable us to program to interfaces, rather than specific implementations. This flexibility gives rise to the "plugin architecture" - where specific implementations can be substituted as long as they adhere to the interface contract. As an example, when we write code to read from STDIN, we are programming to the interface STDIN. STDIN can can be swapped with multiple device drivers implementations and the best thing is, our program does not have to change to use the specific implementations (even if they are written in the future).&lt;/p&gt;

&lt;p&gt;With this approach, software architects have control over the direction of source code dependencies in the system. They are not constrained to align those dependencies with the flow of control.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What can we learn from this paradigm?&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Plugin Architecture&lt;/strong&gt; - OO provides the ability (through polymorphism) to gain control over source code dependency in the system. It allows architect to create a plugin architecture, where modules containing high-level policies are independent of modules containing low-level details. These modules can then developed and deployed independently from each other. &lt;/p&gt;

&lt;h3&gt;
  
  
  3. Functional Programming
&lt;/h3&gt;

&lt;p&gt;Functional programming puts emphasis on data immutability. Why does immutability matter? Because race conditions, deadlock and concurrent update problems exist due to mutable variables. &lt;/p&gt;

&lt;p&gt;This becomes important as an application scales out, especially in distributed systems, since it will require multiple threads and processors, which can give rise to the concurrency issues above. &lt;/p&gt;

&lt;p&gt;Is this practical? Yes, if certain compromises are made. By segregating mutable components from immutable components, we can use disciplines like transactional memory to protect the mutable components from concurrent updates and race conditions. Another way is by keeping track of running transactions instead of mutating values directly, we can calculate the supposedly mutated value from those transactions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What can we learn from this paradigm?&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Immutability&lt;/strong&gt; - architects should design systems that is robust in the distributed world which require multiple threads and processors.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;What do these programming paradigms teach us about software architecture?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Functional Decomposition - structured programming is the algorithmic foundation of our modules&lt;/li&gt;
&lt;li&gt;Plugin Architecture - polymorphism is the mechanism to cross architectural boundaries while ensuring separation of components&lt;/li&gt;
&lt;li&gt;Immutability - impose discipline on the location and access of data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;References: The content of this article is referencing concepts/ideas from the book Clean Architecture by uncle Bob (Robert C. Martin). It is a really great book that I recommend to further if you're interested about software architecture.&lt;/p&gt;

&lt;p&gt;Buy it here: &lt;a href="https://amzn.to/3SJguhf" rel="noopener noreferrer"&gt;https://amzn.to/3SJguhf&lt;/a&gt;&lt;/p&gt;

</description>
      <category>softwareengineering</category>
      <category>programming</category>
      <category>learning</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Exploring React JS. Where to Start?</title>
      <dc:creator>Brandon Gautama</dc:creator>
      <pubDate>Mon, 29 Jul 2024 21:50:34 +0000</pubDate>
      <link>https://dev.to/brandongautama/exploring-react-js-where-to-start-4k6n</link>
      <guid>https://dev.to/brandongautama/exploring-react-js-where-to-start-4k6n</guid>
      <description>&lt;p&gt;Hearing React almost everywhere, I can't help but to explore it too! Although I don't need React as a backend engineer, I feel it could be a great way to get exposure to the front-end world and help me understand the big picture (it did!). I get to learn the  perspectives/challenges of front-end development, and keep them in mind when designing back-end systems. More importantly, its just satisfying to learn how things work end-to-end.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But where to start?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you have basic knowledge of JavaScript, here are (free!) resources that I would recommend:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Learn React by Scrimba&lt;/strong&gt; (&lt;a href="https://v2.scrimba.com/learn-react-c0e" rel="noopener noreferrer"&gt;https://v2.scrimba.com/learn-react-c0e&lt;/a&gt;)&lt;br&gt;
A really great resource to start writing React. &lt;/p&gt;

&lt;p&gt;Learning a new technology is not easy. Given the amount of abstractions we see these days, sometimes it can get frustrating to ignore stuffs you don't really understand and told to just accept that it works. &lt;em&gt;(Questions like "What is going on behind the scenes in this line of code?")&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The instructor at Scrimba did great at explaining what every line of React code means, leaving no mysteries behind. He explained the motivation behind choosing React by showing what a line in React means in Vanilla JS. It really clears a lot of doubts and terms, especially when you first start to learn a new technology.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Full Stack Open&lt;/strong&gt; (&lt;a href="https://fullstackopen.com/en/" rel="noopener noreferrer"&gt;https://fullstackopen.com/en/&lt;/a&gt;)&lt;br&gt;
An awesome resource that I can't recommend enough. Note that this course is not just about React, but it gives you an 'end-to-end' experience of developing a full-stack software using React for front-end. Even though it's not a React-only course, the React part is very comprehensive (covering even Redux). You can choose to only learn the React part of the course but I would really recommend completing the whole thing.&lt;/p&gt;

&lt;p&gt;Here are why I really liked the course:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Full picture&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It first goes into the Fundamental of web applications before introducing React as the front-end and NodeJS as the back-end for creating REST APIs. It then gives you a feel of how testing works in the web. It then helps you setup a deployment pipeline using Github Actions (CI/CD) and helps you familiarize with Docker containerization. It goes all the way from developing to deploying both front and back-end application to production. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Industry standard&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I am a backend software engineer myself and I can relate to how much the course prepares you to work in the industry. It touches on a lot of aspects that makes a projects more realistic. For example, unit testing front and back-end, integration testing and end-to-end testing. These testings are very valuable in an actual production projects and yet, a lot of online classes missed them. It teaches you how to setup a CI/CD pipeline, manage configs separately for security reasons, containerize your applications, etc. There are a lot of best practices in this course!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Practice!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each module comes with its own set of exercises and I highly recommend that you complete those exercises. &lt;strong&gt;Learn programming by doing&lt;/strong&gt; - only then the concepts, syntax and ideas can materialize in your mind. I always believed that the best way to learn is to practice it! &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Modern and up-to-date"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Besides the fact that it is teaching React (one of the most popular front-end framework used in the industry), it also teaches NodeJS (another popular back-end framework) and uses Github Actions (for CI/CD) and Docker (containerization). In addition, this course is actively maintained and revised (you can see sections of the course that says its updated because of the ever-changing nature of software).&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>react</category>
      <category>learning</category>
    </item>
    <item>
      <title>Message Delivery System using AWS Step Functions</title>
      <dc:creator>Brandon Gautama</dc:creator>
      <pubDate>Sat, 20 Jul 2024 06:23:11 +0000</pubDate>
      <link>https://dev.to/brandongautama/message-delivery-system-using-aws-step-functions-jda</link>
      <guid>https://dev.to/brandongautama/message-delivery-system-using-aws-step-functions-jda</guid>
      <description>&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;My team owns a cloud microservice that orchestrates the collection of content from other microservices and delivers them to customer-facing devices.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem
&lt;/h2&gt;

&lt;p&gt;Recently, I was tasked to design a cloud system that can ensure delivery of a given message to any target device. A delivery is successful if the target device sends back an ACK (acknowledgement) response. &lt;/p&gt;

&lt;p&gt;Normally, this would be an easy task. If the message is dropped in the communication channel or if the target device is offline or behaving incorrectly, the service can just retry until it receives the ACK. Since most programming languages (e.g. Java's built-in HttpClient) supports this out of the box, this retry system can be easily built.&lt;/p&gt;

&lt;p&gt;However, this is only true for synchronous communications where a client opens a connection channel, sends a request and awaits a response through the same channel. If there is no response in that channel or a bad response was received in that channel, the service knows that it has to retry. Things get complicated in an asynchronous system, where the response comes back through a different channel than where the request was sent. &lt;em&gt;(How to schedule the next attempt?)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In addition, the retry has to be attempted with backoffs up to 'seconds' precision. That is, after the first attempt, wait for 15 seconds before the second attempt, then wait for 30 seconds before the third attempt, then additional attempts has to wait for 4 hours.&lt;/p&gt;

&lt;h2&gt;
  
  
  Design
&lt;/h2&gt;

&lt;p&gt;Given the above requirements, we know we needed a scheduler. &lt;/p&gt;

&lt;p&gt;Something similar to CronJob would work so we looked for AWS products that can simulate this 'scheduling' behavior.&lt;/p&gt;

&lt;p&gt;We first looked at AWS EventBridge Scheduler but it could only support up to the 'minute' precision, while we needed something with 'seconds' accuracy. &lt;/p&gt;

&lt;p&gt;We then came across AWS SQS. SQS has a feature called 'message delay' where a message in the queue is only visible after the delayed time set in seconds. So we took advantage of that delay as a way to schedule the next retry. Here is how it works:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiicvweqdzmx8rpn4fo7x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiicvweqdzmx8rpn4fo7x.png" alt="Scheduler System using AWS SQS" width="539" height="271"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The first attempt to deliver the message to device is accompanied with a message to the 15-seconds queue.&lt;/li&gt;
&lt;li&gt;When the message from 15-seconds queue becomes visible (after 15 seconds), we first check whether the message has been ACKed. If it hasn't been ACKed, attempt another message delivery to device while at the same time, enqueue the message into the 30-seconds delay queue. If it has been ACKed, the process stops here.&lt;/li&gt;
&lt;li&gt;When the message from 30-seconds queue becomes visible (after 30 seconds), we first check whether the message has been ACKed. If it hasn't been ACKed, attempt another message delivery to device while at the same time, enqueue the message into the 4-hours delay queue. If it has been ACKed, the process stops here.&lt;/li&gt;
&lt;li&gt;The above repeats until we received the ACK.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Although the above works, note that for every message, there is always one extra traffic. For example, if the message was ACKed at the first attempt, no retry is needed. Yet, the message is already enqueued into the 15-seconds delay queue and when the message becomes visible, we check that the message has been ACKed and therefore, we do not attempt another delivery to device. That is wasted traffic. It felt like SQS may not be the right solution. We were repurposing SQS to force-fix our problem with its 'message delay' feature and its 'seconds' precision. So we decided to keep looking for better alternatives. &lt;/p&gt;

&lt;p&gt;At that time, we recognized that the scheduler has this notion of 'states'. It is behaving differently based on different states, i.e. second attempt has to wait for 15 seconds while third attempt has to wait for 30 seconds. Depending on the number of attempts made, the scheduler has to set different delay values. Thats when we realized the problem can be generalized as a Finite State Machine (FSM). Step Functions to the rescue!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5kt6hq65iqhj8n330hl7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5kt6hq65iqhj8n330hl7.png" alt="Message Delivery Workflow" width="637" height="584"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is how it works:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The machine starts with first message delivery using API Gateway: Invoke&lt;/li&gt;
&lt;li&gt;The machine then goes into a 'Wait' state of 15-seconds&lt;/li&gt;
&lt;li&gt;After 15-seconds timer is up, the machine proceeds to the 'Choice' state and check whether message has been ACKed. If yes, then the machine goes to 'End' state. Else, the machine attempts another message delivery by going back to the API Gateway: Invoke step above.&lt;/li&gt;
&lt;li&gt;Step 2 and 3 repeats with 30-seconds timer&lt;/li&gt;
&lt;li&gt;Step 2 and 3 repeats with 4-hours timer&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Note that we can simplify this further. If we add an additional behavior when we receive the ACK from device to stop this step function execution, we can remove the 'Choice' state. In other words, this execution only exists if we have not received the ACK.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2lj04yxb6qvvl8x96e5a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2lj04yxb6qvvl8x96e5a.png" alt="Simplified Message Delivery Workflow" width="517" height="318"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;AWS Step Functions is a workflow orchestration system.  It can be a very powerful tool, especially when solving problems related to scheduling and state machines workflows. &lt;/p&gt;

&lt;p&gt;It can be used to support both event-driven and schedule-based architectures. Its SDK Integrations to other AWS Services eases development especially if you're already building on AWS infrastructure. &lt;/p&gt;

&lt;p&gt;I encourage you to check their official documentation. (Surprisingly?) they can be used to solve a lot of design problems!&lt;br&gt;
&lt;a href="https://docs.aws.amazon.com/step-functions/latest/dg/connect-to-services.html" rel="noopener noreferrer"&gt;AWS Step Functions&lt;/a&gt;&lt;/p&gt;

</description>
      <category>systemdesign</category>
      <category>aws</category>
      <category>stepfunctions</category>
      <category>awssqs</category>
    </item>
  </channel>
</rss>
