<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Anshuman Pattnaik on Medium]]></title>
        <description><![CDATA[Stories by Anshuman Pattnaik on Medium]]></description>
        <link>https://medium.com/@hackbotone?source=rss-14e6e8a4998f------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*CDeSXrYGdJjftpWDdE0wsw.jpeg</url>
            <title>Stories by Anshuman Pattnaik on Medium</title>
            <link>https://medium.com/@hackbotone?source=rss-14e6e8a4998f------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 19 Jul 2026 23:46:48 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@hackbotone/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[A Framework is the foundation for building applications in Software development.]]></title>
            <link>https://hackbotone.medium.com/a-framework-is-the-foundation-for-building-applications-in-software-development-5a0d0897ffe7?source=rss-14e6e8a4998f------2</link>
            <guid isPermaLink="false">https://medium.com/p/5a0d0897ffe7</guid>
            <category><![CDATA[framework]]></category>
            <category><![CDATA[software-architecture]]></category>
            <category><![CDATA[software-engineer]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[software-development]]></category>
            <dc:creator><![CDATA[Anshuman Pattnaik]]></dc:creator>
            <pubDate>Sat, 19 Jul 2025 11:53:26 GMT</pubDate>
            <atom:updated>2025-07-19T22:00:17.727Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*2OwkaqPaMMM-RbKci1E5Fw.png" /></figure><h3><strong>Introduction: Unraveling the “Architecture” Behind Modern Software Development</strong></h3><p>A framework is a term that is everywhere in the fast-paced world of Software development. Frameworks are the invisible architects that empower developers to create sophisticated applications with exceptional efficiency. From building dynamic web applications with Django to developing intuitive mobile apps with React Native and Flutter, frameworks enable developers to have faster development cycles, higher code quality, and easier maintenance. However, we need to understand the underlying architecture that transforms a collection of code files into a cohesive and powerful application.</p><p>This article aims to simplify the internal architecture of software frameworks by exploring three fundamental concepts of Object-Oriented Programming (OOP): Base Classes, the Factory Pattern, and the principle of Inversion of Control (IoC). We will explore how these pillars work in action, examining their structural formation and operational backbone within a modern framework that enables developers to build highly scalable, robust, and customizable applications without having to develop the core implementation from scratch.</p><h4><strong>Understanding the foundation of Frameworks Efficiency</strong></h4><p>In terms of building software applications, the Framework provides a reusable, pre-written set of code that provides a foundational structure at its core, drastically reducing the amount of time required to write boilerplate code. Let’s imagine a real-world scenario: you want to build a car, but you wouldn’t start from scratch every time, designing every nut, bolt, and piece of wiring independently. This methodology is both costly and inefficient, resulting in inconsistent quality. Instead, car manufacturers utilize a framework of established principles, well-defined processes, and standardized components to build cars more quickly and efficiently. A framework provides a clear, predefined structure, like a chassis, which defines where the engine will be placed, where the wheels will attach, how the suspension will be mounted, and where the body parts will sit. All these design decisions are foundational to the structure of a Car framework.</p><p>Similarly, the analogy to Software: A software framework provides libraries of pre-built interfaces and functions, and defines how custom code can interact with the APIs. The developer uses framework-provided functions to connect to the database or authenticate a user; you don’t have to rewrite the same implementation frequently. This is similar to a Software architecture that defines the main components and how they interact (e.g., the Model-View-Controller framework, where there is a ‘Model’ for data, a ‘View’ for display, and a ‘Controller’ to handle logic).</p><h4>What makes frameworks so essential?</h4><ul><li><strong>Increased Productivity: </strong>A framework reduces the time required to write boilerplate code for a common problem, enabling developers to reuse that same piece of code in multiple projects.</li><li><strong>Improved Code Quality: </strong>A framework often implements industry-standard design patterns, well-tested components, leading to more secure and reliable applications.</li><li><strong>Consistency and Maintainability: </strong>A framework code is always separated from the main application and enforces a consistent structure and coding pattern across projects, making it easier to maintain the codebase over time.</li></ul><h3><strong>The Orchestrator: Inversion of Control (IoC)</strong></h3><p>To understand the underlying architecture of a framework, it’s essential to comprehend the Inversion of Control (IoC) characteristics, which represent a fundamental transformation in the programming paradigm.</p><p>In traditional procedural programming, object creation and lifecycle management are handled by the application code, which explicitly calls library codes or utility functions to perform these tasks.</p><h4><strong>Without Inversion of Control (Traditional Approach):</strong></h4><p>Imagine you have a class PaymentProcessor that needs to log messages.</p><pre># Traditional approach - tightly coupled logging<br><br>class ConsoleLogger:<br>    def log(self, message: str):<br>        &quot;&quot;&quot;<br>        Logs a message to the console.<br>        &quot;&quot;&quot;<br>        print(f&quot;[Console Log] {message}&quot;)<br><br>class PaymentProcessor:<br>    def __init__(self):<br>        &quot;&quot;&quot;<br>        Initializes the PaymentProcessor.<br><br>        PaymentProcessor is responsible for creating its own ConsoleLogger, resulting in tight coupling.<br>        &quot;&quot;&quot;<br>        self.logger = ConsoleLogger()<br><br>    def process_payment(self, amount: float):<br>        &quot;&quot;&quot;<br>        Processes a payment and logs messages using the internal ConsoleLogger.<br>        &quot;&quot;&quot;<br>        self.logger.log(f&quot;Processing payment of {amount}&quot;)<br>        print(f&quot;Payment logic for {amount} executed.&quot;)<br>        self.logger.log(f&quot;Payment processed successfully for {amount}.&quot;)<br><br># Example of usage:<br>if __name__ == &quot;__main__&quot;:<br>    print(&quot;--- Demonstrating Traditional Approach (Tight Coupling) ---&quot;)<br><br>    processor = PaymentProcessor()<br>    processor.process_payment(100.00)<br><br>    print(&quot;\n--- Implications ---&quot;)<br>    print(&quot;Notice how &#39;PaymentProcessor&#39; directly creates &#39;ConsoleLogger&#39;.&quot;)<br>    print(&quot;If you wanted to change to a &#39;FileLogger&#39;, you&#39;d have to modify &#39;PaymentProcessor&#39;.&quot;)<br>    print(&quot;This makes testing and reusability harder.&quot;)</pre><h4><strong>Problems with this approach:</strong></h4><ol><li><strong>Tight Coupling: </strong>The PaymentProcessor is tightly coupled to the ConsoleLoggerclass, and modifying the PaymentProcessor class is required to switch to a FileLogger or DatabaseLogger class.</li><li><strong>Test Flexibility: </strong>With the current implementation, it’s hard to test PaymentProcessor without ConsoleLogger (or mock ConsoleLogger directly).</li><li><strong>Duplication: </strong>When the other class implements logging, it instantiates the logger separately, resulting in ConsoleLoggerbeing instantiated independently of the original instance. This leads to code duplication and potential issues if the logger configuration changes.</li></ol><h4><strong>With Inversion of Control (using Dependency Injection)</strong></h4><p>Now, let’s implement IoC using Dependency Injection, which is a common way to achieve IoC. We will introduce an ILoggerinterface and inject the specific logger implementation.</p><pre># 1. Define an interface<br>from abc import ABC, abstractmethod<br><br><br>class ILogger(ABC):<br>    @abstractmethod<br>    def log(self, message: str):<br>        pass<br><br><br># 2. Implement different logging strategies<br>class ConsoleLogger(ILogger):<br>    def log(self, message: str):<br>        print(f&quot;[Console Log] {message}&quot;)<br><br><br>class FileLogger(ILogger):<br>    def __init__(self, file_path: str):<br>        self.file_path = file_path<br><br>    def log(self, message: str):<br>        print(f&quot;[File Log to {self.file_path}] {message}&quot;)<br><br><br>class DatabaseLogger(ILogger):<br>    def __init__(self, db_conn_string: str):<br>        self.db_conn_string = db_conn_string<br><br>    def log(self, message: str):<br>        print(f&quot;[Database Log to {self.db_conn_string}] {message}&quot;)<br><br><br># 3. Modify PaymentProcessor to accept an ILogger through its constructor<br>class PaymentProcessor:<br>    def __init__(self, logger: ILogger):<br>        self.logger = logger<br><br>    def process_payment(self, amount: float):<br>        self.logger.log(f&quot;Processing payment of {amount}&quot;)<br><br><br># 4. The &quot;Inversion of Control&quot; happens in the main application or a framework<br>class Application:<br>    def run(self):<br>        # Control is inverted, instead of PaymentProcessor creating the logger, the Application<br>        # decides which logger to provide to PaymentProcessor.<br><br>        print(&quot;--- Scenario 1: Using ConsoleLogger ---&quot;)<br>        console_logger = ConsoleLogger()<br>        console_payment_processor = PaymentProcessor(console_logger)<br>        console_payment_processor.process_payment(100.00)<br><br>        print(&quot;\n--- Scenario 2: Using FileLogger ---&quot;)<br>        file_logger = FileLogger(&quot;app.log&quot;)<br>        file_payment_processor = PaymentProcessor(file_logger)<br>        file_payment_processor.process_payment(250.50)<br><br><br>if __name__ == &quot;__main__&quot;:<br>    app = Application()<br>    app.run()</pre><h4><strong>How is Inversion of Control achieved in this scenario?</strong></h4><ul><li><strong>Who creates the logger? </strong>Earlier, we saw in the traditional approach that the PaymentProcessor class creates the logger. In the IoC approach, the PaymentProcessor class doesn’t create the logger; instead, it shifts the responsibility of creating and managing the ILogger dependency from PaymentProcessor to an external entity, Application.</li><li><strong>Decoupling: </strong>PaymentProcessor is flexible to switch to a different logging mechanism without alteration, because it’s no longer tightly coupled to a specific logging implementation. It currently only depends on the ILogger interface.</li><li><strong>Testability: </strong>This improves testability for PaymentProcessor, enabling you to test in isolation. You can easily inject a mock that doesn’t write to a console or file.</li><li><strong>Framework Control: </strong>An IoC container handles the creation and injection of these dependencies within a framework, based on the configuration, and enables centralized control.</li></ul><p>In summary, IoC is an orchestrator, and base classes and factories are the instruments through which orchestration is achieved. The application code doesn’t manage the core implementation, such as server management, routing, or HTTP parsing; instead, these are handled by the Framework through inverted control flow.</p><h3>Base Classes: The Blueprint and the Contract</h3><p>In object-oriented programming (OOP), the concept of a Base class serves as the foundation, providing a blueprint (superclass/parent class) from which other derived classes/subclasses/child classes can inherit. This mechanism provides a common interface that enables the reuse of shared attributes and methods defined in the Base class, which are used across all derived classes.</p><h4><strong>The Role and Structure of Base Classes:</strong></h4><ul><li><strong>Shared Attributes and Methods: </strong>In the Base class, the defined attributes and methods are common to all derived classes.</li><li><strong>Abstraction: </strong>Define methods that subclasses must implement to complete a required implementation.</li><li><strong>Default Behaviour: </strong>It’s flexible to provide default implementations of methods that subclasses can implement as-is or override based on the requirements.</li></ul><h4><strong>How Base Classes Serve Frameworks:</strong></h4><p>In the context of a Software Framework, the Base class is the primary class that provides its “<strong>Frozen Spots</strong>” and defines its “<strong>Hot Spots</strong>” for extensibility. These are the fundamental concepts of the Framework’s architecture and how it can be extended or customized.</p><ul><li><strong>Frozen Spots: </strong>These parts of the Framework are invariant, meaning the defined core logic and core architecture remain unchanged (frozen) across applications built using the Framework. These implementation often uses concrete classes, abstract classes with invariant methods, or fixed interfaces that developers interact with but don’t change.</li><li><strong>Hot Spots: </strong>These are the specific areas where developers can add their application code or business logic to customize the functionality for a particular project. Developers are expected to override the defined empty methods to complete the implementation of an application, which are an abstraction of Base classes used as hooks within a Framework.</li></ul><p><strong>Example: A Report Generation Framework</strong></p><p>A software application that is coded to generate various types of reports (e.g., daily reports, monthly reports, and quarterly financial reports). Each report has its unique format, but the report generation steps follow a standard format: fetching data, processing, and outputting the results.</p><p>In this scenario, a standardised framework designed to generate different reports ensures that common steps are handled consistently and allows developers to add custom logics for unique report requirements.</p><ol><li><strong>The “Frozen Spot”: </strong>BaseReportGenerator</li></ol><p>The Framework defines an unchangeable sequence of steps common to all reports, that is the “<strong>Frozen Spot</strong>”, which is part of the framework logic that developers generally don’t modify.</p><pre>from abc import ABC, abstractmethod<br><br><br>class BaseReportGenerator(ABC):<br>    &quot;&quot;&quot;<br>    Abstract Base Class defining the fixed steps for report generation.<br>    This is the &#39;Frozen Spot&#39; - the invariant algorithm.<br>    &quot;&quot;&quot;<br><br>    def generate_report(self):<br>        &quot;&quot;&quot;<br>        The Template Method (orchestrator) - this framework fixes this sequence<br>        &quot;&quot;&quot;<br>        print(f&quot;\n--- Generating Report: {self.__class__.__name__} ---&quot;)<br>        self._setup()<br>        data = self.fetch_data()<br>        processed_data = self.process_data(data)<br>        self.output_report(processed_data)<br>        self._teardown()<br>        print(f&quot;--- Report Generation Complete: {self.__class__.__name__} ---\n&quot;)<br><br>    @abstractmethod<br>    def fetch_data(self):<br>        &quot;&quot;&quot;<br>        Abstract method to fetch raw data for the report.<br>        Developer MUST implement this for specific data sources.<br>        &quot;&quot;&quot;<br>        pass<br><br>    @abstractmethod<br>    def process_data(self, raw_data):<br>        &quot;&quot;&quot;<br>        Abstract method to transform/process the raw data.<br>        Developer MUST implement this for specific report logic.<br>        &quot;&quot;&quot;<br>        pass<br><br>    @abstractmethod<br>    def output_report(self, processed_data):<br>        &quot;&quot;&quot;<br>        Abstract method to output the report (e.g., print, save to file, web).<br>        Developer MUST implement this for specific output formats.<br>        &quot;&quot;&quot;<br>        pass<br><br>    def _setup(self):<br>        &quot;&quot;&quot;<br>        Optional hook method for pre-processing steps.<br>        Provides a default empty implementation.<br>        &quot;&quot;&quot;<br>        print(f&quot;Setting up {self.__class__.__name__}...&quot;)<br><br>    def _teardown(self):<br>        &quot;&quot;&quot;<br>        Optional hook method for post-processing steps.<br>        Provides a default empty implementation.<br>        &quot;&quot;&quot;<br>        print(f&quot;Tearing down {self.__class__.__name__}...&quot;)</pre><p>2.<strong> The “Hot Spots”: Specific Report Implementations</strong></p><p>These are the places where the application developer injects custom code for report-specific logic. To implement this, create a custom class that inherits from the BaseReportGenerator and implements (overrides) its abstract methods.</p><pre>import datetime<br><br>class DailySalesReport(BaseReportGenerator):<br>    &quot;&quot;&quot;<br>    Developer&#39;s implementation for a specific report.<br>    This fills in the &#39;Hot Spots&#39; of the framework.<br>    &quot;&quot;&quot;<br>    def fetch_data(self):<br>        print(&quot;Fetching daily sales data from database...&quot;)<br>        return [<br>            {&quot;product&quot;: &quot;Laptop&quot;, &quot;sales&quot;: 10, &quot;revenue&quot;: 10000},<br>            {&quot;product&quot;: &quot;Mouse&quot;, &quot;sales&quot;: 50, &quot;revenue&quot;: 1000},<br>            {&quot;product&quot;: &quot;Keyboard&quot;, &quot;sales&quot;: 20, &quot;revenue&quot;: 1500},<br>        ]<br><br>    def process_data(self, raw_data):<br>        print(&quot;Calculating total daily revenue...&quot;)<br>        total_revenue = sum(item[&#39;revenue&#39;] for item in raw_data)<br>        return {&quot;date&quot;: datetime.date.today(), &quot;total_revenue&quot;: total_revenue, &quot;details&quot;: raw_data}<br><br>    def output_report(self, processed_data):<br>        print(&quot;Outputting Daily Sales Report to console:&quot;)<br>        print(f&quot;Report Date: {processed_data[&#39;date&#39;]}&quot;)<br>        print(f&quot;Total Daily Revenue: ${processed_data[&#39;total_revenue&#39;]:.2f}&quot;)<br>        print(&quot;Detailed Sales:&quot;)<br>        for item in processed_data[&#39;details&#39;]:<br>            print(f&quot;{item[&#39;product&#39;]}: {item[&#39;sales&#39;]} units, ${item[&#39;revenue&#39;]:.2f}&quot;)<br><br>    def _setup(self):<br>        super()._setup()<br>        print(&quot;(Specific setup for Daily Sales Report)&quot;)<br><br>class ProductStockReport(BaseReportGenerator):<br>    &quot;&quot;&quot;<br>    Another developer&#39;s implementation for a different report.<br>    &quot;&quot;&quot;<br>    def fetch_data(self):<br>        print(&quot;Fetching current product stock levels from inventory system...&quot;)<br>        return [<br>            {&quot;item&quot;: &quot;Laptop&quot;, &quot;stock&quot;: 50},<br>            {&quot;item&quot;: &quot;Monitor&quot;, &quot;stock&quot;: 120},<br>            {&quot;item&quot;: &quot;Webcam&quot;, &quot;stock&quot;: 300},<br>        ]<br><br>    def process_data(self, raw_data):<br>        print(&quot;Identifying low stock items...&quot;)<br>        low_stock_threshold = 100<br>        low_stock_items = [item for item in raw_data if item[&#39;stock&#39;] &lt; low_stock_threshold]<br>        return {&quot;total_items&quot;: len(raw_data), &quot;low_stock&quot;: low_stock_items, &quot;all_stock&quot;: raw_data}<br><br>    def output_report(self, processed_data):<br>        print(&quot;Outputting Product Stock Report to a simulated file:&quot;)<br>        filename = f&quot;product_stock_report_{datetime.date.today().isoformat()}.txt&quot;<br>        with open(filename, &quot;w&quot;) as f:<br>            f.write(f&quot;Product Stock Report - {datetime.date.date.today()}\n&quot;)<br>            f.write(f&quot;Total Unique Items: {processed_data[&#39;total_items&#39;]}\n\n&quot;)<br>            f.write(&quot;Low Stock Items (below 100):\n&quot;)<br>            if processed_data[&#39;low_stock&#39;]:<br>                for item in processed_data[&#39;low_stock&#39;]:<br>                    f.write(f&quot;  - {item[&#39;item&#39;]}: {item[&#39;stock&#39;]} units\n&quot;)<br>            else:<br>                f.write(&quot;No items currently low in stock.\n&quot;)<br>        print(f&quot;Report saved to {filename}&quot;)<br><br>    def _setup(self):<br>        super()._setup()<br>        print(&quot;(Specific setup for Product Stock Report)&quot;)</pre><p>3. <strong>The Framework IoC in Action</strong></p><p>To generate a specific report, the Framework’s main execution loop will instantiate a particular report generator and then simply call its generate_report() method without knowing the internal details of how each report fetches, processes, or outputs data.</p><pre>if __name__ == &quot;__main__&quot;:<br>    print(&quot;Framework Dispatcher: Starting Report Generation Process\n&quot;)<br><br>    # The framework (or an orchestrator) decides WHEN to create and run your reports.<br>    # It doesn&#39;t know the specifics of sales data or stock data.<br><br>    # 1. Generate Daily Sales Report<br>    sales_report_instance = DailySalesReport()<br>    sales_report_instance.generate_report()<br><br>    # 2. Generate Product Stock Report<br>    stock_report_instance = ProductStockReport()<br>    stock_report_instance.generate_report()<br><br>    print(&quot;\nFramework Dispatcher: All Reports Generated.&quot;)</pre><h3><strong>The Factory Pattern: Orchestrating Object Creation</strong></h3><p>In the previous section, we saw how the Base class defines the component structure and how it should fit into the Framework’s structure. However, the Factory Pattern addresses the crucial aspects of how these components are created, focusing on a creational design pattern that provides flexible and controlled object creation, thereby making the system independent and encapsulating the logic for object instantiation.</p><p>The factory class determines object creation because, instead of directly instantiating objects using constructors, client code interacts with the factory and common interfaces of the objects it creates.</p><h4><strong>Advantages of the Factory Pattern:</strong></h4><ul><li><strong>Encapsulates Creation Logic: </strong>The object creation encapsulates the logic, and the client code doesn’t need to know the specific class name or logic required to create different types of objects.</li><li><strong>Decoupling: </strong>The concrete class from which the objects it creates decouple from the client code, and the client only interacts with the interface/base class of the created objects.</li><li><strong>Flexibility and Extensibility: </strong>Without modifying the existing client business logic, new types of objects or factory implementations can be added to the system. The addition or updation is only required for the factory’s creation logic or adding a new factory implementation.</li><li><strong>Polymorphic Creation: </strong>A single factory is flexible to produce various types of objects that inherit a common base or interface.</li></ul><h4><strong>How the Factory Pattern Serves Frameworks:</strong></h4><p>The Factory Pattern serves frameworks by combining IoC and base classes.</p><ul><li><strong>Dynamic Component Instantiation: </strong>The Framework’s internal architecture is often implemented to handle the dynamic instantiation of various components based on<strong> </strong>runtime conditions (e.g., routing based on the controller, user requests based on services, etc.), and the Factories implement these controlled mechanisms.</li><li><strong>Abstracting System Dependencies: </strong>In a large and complex framework that supports multiple underlying technologies (Such as Different database systems, caching mechanisms, and templating engines), the factory design pattern can abstract the creation of objects for these technologies.</li><li><strong>Plug-and-Play Architectures: </strong>If a framework enables user-defined plugins, a factory can be used to instantiate custom components at runtime, allowing users to extend the Framework’s capability seamlessly.</li><li><strong>Implementing IoC for Object Creation: </strong>The Framework’s internal factory is invoked, and decides which specific object to return based on the configuration. For Example, instead of the application code directly instantiating new DatabaseConnection() The Framework’s internal DatabaseFactorty() is invoked and decides which specific MySQLConneciton or PostGreSQLConnection to return based on the configuration.</li></ul><h4><strong>Example: A Simple Framework Component “NotificationFactory”</strong></h4><p>Let’s imagine a simple framework that needs to send various types of notifications — (Email, SMS, or push notifications).</p><pre>from abc import ABC, abstractmethod<br><br><br># Base Class for all notification types<br>class Notifier(ABC):<br>    @abstractmethod<br>    def send(self, recipient, message):<br>        pass<br><br><br># Framework provided or user-defined<br>class EmailNotifier(Notifier):<br>    def send(self, recipient, message):<br>        print(f&quot;Sending email to {recipient}: {message}&quot;)<br><br><br>class SMSNotifier(Notifier):<br>    def send(self, recipient, message):<br>        print(f&quot;Sending SMS to {recipient}: {message}&quot;)<br><br><br>class PushNotifier(Notifier):<br>    def send(self, recipient, message):<br>        print(f&quot;Sending push notification to {recipient}: {message}&quot;)<br><br><br># Framework&#39;s Factory<br>class NotificationFactory:<br>    &quot;&quot;&quot;<br>    A factory responsible for creating Notifier objects.<br>    This hides the concrete implementation details from the client.<br>    &quot;&quot;&quot;<br><br>    @staticmethod<br>    def get_notifier(notifier_type):<br>        if notifier_type == &quot;email&quot;:<br>            return EmailNotifier()<br>        elif notifier_type == &quot;sms&quot;:<br>            return SMSNotifier()<br>        elif notifier_type == &quot;push&quot;:<br>            return PushNotifier()<br>        else:<br>            raise ValueError(f&quot;Unknown notifier type: {notifier_type}&quot;)<br><br><br># --- How a developer uses it (in their application logic) ---<br><br>class UserService:<br>    def __init__(self, notification_type=&quot;email&quot;):<br>        # The service doesn&#39;t care about the concrete notifier class,<br>        # it just asks the factory for an object that can &#39;send&#39; notification.<br>        self.notifier = NotificationFactory.get_notifier(notification_type)<br><br>    def register_user(self, username, email):<br>        print(f&quot;Registering user: {username} with email: {email}&quot;)<br>        welcome_message = f&quot;Welcome, {username}! Your account is created.&quot;<br>        self.notifier.send(email, welcome_message)<br><br><br># --- Framework&#39;s (or main app&#39;s) entry point ---<br>if __name__ == &quot;__main__&quot;:<br>    email_service = UserService(&quot;email&quot;)<br>    email_service.register_user(&quot;Alice&quot;, &quot;alice@example.com&quot;)<br><br>    sms_service = UserService(&quot;sms&quot;)<br>    sms_service.register_user(&quot;Bob&quot;, &quot;+914582369853&quot;)<br><br>    push_service = UserService(&quot;push&quot;)<br>    push_service.register_user(&quot;Tom&quot;, &quot;charlie_device_token&quot;)<br><br>    try:<br>        unknown_service = UserService(&quot;fax&quot;)<br>        unknown_service.register_user(&quot;David&quot;, &quot;david@example.com&quot;)<br>    except ValueError as e:<br>        print(f&quot;Error: {e}&quot;)</pre><p><strong>In this Example:</strong></p><ul><li>Notifier — The mechanism for sending notifications across all channels serves as a base class/interface.</li><li>EmailNotifier , SMSNotifier and PushNotifier — These are the concrete class implementations.</li><li>NotificationFactory — This is a factory class that creates the Notifier objects.</li><li>UserService — This is the application logic and uses the Framework and asks NotificationFactory for a Notifier to send an email or SMS based on the notification type. The following demonstration shows the decoupling and the Framework’s control over object creation.</li></ul><h3><strong>Beyond the Basics: Related Concepts</strong></h3><p>Other patterns and principles work alongside each other within a Framework, and Base Classes, Factories, and IoC work in the central area.</p><ul><li><strong>Dependency Injection (DI): </strong>The Framework injects the dependencies into a class rather than the class creating them itself, a specific form of IoC that works with factories.</li><li><strong>Strategy Pattern: </strong>Factories create different “strategy” objects based on the configuration, allowing them to be selected at runtime.</li><li><strong>Observer Pattern: </strong>The Framework often uses this pattern for event handling, when one object changes its state, then all its dependents are notified and updated automatically.</li><li><strong>Template Method Pattern: </strong>This design pattern often directly implements the “Frozen Spots” and “Hot Spots” using inheritance. The base class defines the skeleton of an algorithm, but subclasses override specific steps of the algorithm without changing its structure.</li><li><strong>Architectural Patterns (MVC, MVP, MVVM): </strong>To build a framework with proper architecture, it requires implementing high-level design patterns that define the overall structure and interaction between the main components of an application. These are not code patterns but conceptual guidelines that guide how an application should be organized to promote separation of concerns, testability, and maintainability.</li></ul><h3><strong>Conclusion: Empowering Developers Through Abstraction and Structure</strong></h3><p>In Framework, the implementations are essentially collections of utility functions, and the architectural blueprints provide developers with the flexibility to orchestrate the development process. With the power of Inversion of Control, the Framework dictates the flow. It allows developers to call defined logic at the right moments, and this is made possible by leveraging “<strong>Base Classes</strong>” &amp; “<strong>The Factory Pattern</strong>”.</p><ul><li><strong>Base Classes:</strong> It provides a foundational structure where developers inject their custom business logic in critical “<strong>Hot Spots</strong>” of common functionalities. Ensures the defined contract and custom components fit seamlessly into the Framework’s design.</li><li><strong>The Factory Pattern: </strong>The intelligent object creator that dynamically creates the components based on the configurations or runtime conditions, and ensures, without code modifications, that the Framework can easily accommodate new types of objects.</li></ul><p>To design better software, the principles of modularity, decoupling, and high cohesion are essential in frameworks for building robust software systems. If you understand how the Framework operates, the flow of control helps in debugging the issue more efficiently. A deeper understanding of these underlying principles enables you to write cleaner, more idiomatic code, which in turn allows you to leverage the Framework’s capabilities as a whole.</p><p>Always remember the next time you install pip install django or npm install react Beneath the surface lies a beautifully engineered system that relies on these OOP principles, providing the robust scaffolding needed to build the next generation of incredible Software applications.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5a0d0897ffe7" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Why did I build Kafka Manager?]]></title>
            <link>https://hackbotone.medium.com/why-did-i-build-kafka-manager-6554baf9f0da?source=rss-14e6e8a4998f------2</link>
            <guid isPermaLink="false">https://medium.com/p/6554baf9f0da</guid>
            <category><![CDATA[kafka-python]]></category>
            <category><![CDATA[python]]></category>
            <category><![CDATA[pypi]]></category>
            <category><![CDATA[open-source]]></category>
            <category><![CDATA[kafka]]></category>
            <dc:creator><![CDATA[Anshuman Pattnaik]]></dc:creator>
            <pubDate>Sun, 04 May 2025 21:48:08 GMT</pubDate>
            <atom:updated>2025-05-04T21:50:44.880Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Hw_7rQdV8ku-GdB2qCaz2g.png" /></figure><p>This article will discuss my recent development of Kafka Manager in Python. The tool is open-source on my GitHub and has detailed documentation. Please visit, and if you’re interested in new features and ideas, feel free to raise a PR to contribute.</p><p><strong>Repository link:</strong> <a href="https://github.com/anshumanpattnaik/kafka-manager">https://github.com/anshumanpattnaik/kafka-manager</a></p><p>Kafka’s real-time use cases are present in most applications, such as real-time data streaming, messaging systems, log aggregation, etc. This piece of technology is versatile and can serve as a robust and scalable message broker, which is often a replacement for legacy systems like RabbitMQ or ActiveMQ. Proper management techniques for producers, consumers, and topics are essential to implement Kafka within a system. I have written a Python utility class to interact with Kafka to simplify the process, providing a higher-level abstraction for managing Producers, Consumers, and Topics. The core concept of the Kafka Manager class is that it integrates the <a href="https://pypi.org/project/kafka-python/">kafka-python</a> library internally, encapsulates the complexity behind the implementation of the Kafka API, and provides a user-friendly interface for developers to implement Kafka effectively in their applications.</p><h3><strong>Why Kafka Manager class?</strong></h3><p>A Manager class is a general concept in Software development designed to control, coordinate, and oversee the lifecycle and operations of other objects or resources within an application. The manager class doesn’t necessarily perform all the tasks, but defines core functions to ensure that the proper functions do the right thing at the right time. The core responsibilities of the Manager class are to maintain the object lifecycle management to create, initialize, start, stop, and destroy instances of the objects it manages. The managed object’s resource and state management should happen properly once resource allocation is completed, and it’s the responsibility of the manager class to define functions to release shared resources, which again will be called by the parent application explicitly.</p><p>So, the main reason for building Kafka Manager as a separate library is that the <a href="https://pypi.org/project/kafka-python/">kafka-python</a> library provides many core functionalities, such as Producing Messages, Consuming Messages, Metadata Operations, and Low-Level Client operations. Implementing all these modules repeatedly in every project is redundant, and managing the implementation and complexity behind the Kafka-Python library is challenging. I decided to write a Python utility class that simplifies the Kafka interaction and provides a high-level abstraction for managing Producers, Consumers, and Topics, which will be user-friendly for developers to implement Kafka effectively in their applications. This methodology makes the code more organized, maintainable, and testable.</p><p>You can install the library with the following command:</p><pre>pip install kafka-manager</pre><p>I have also published documentation with all the procedures. See for more details: <br><a href="https://kafka-manager-docs.readthedocs.io/en/latest/index.html">https://kafka-manager-docs.readthedocs.io/en/latest/index.html</a></p><h3><strong>What are the Features Kafka Manager provides?</strong></h3><p>The kafka-manager library’s highlighted features help developers work with Kafka by offering a higher level of abstraction, simplifying common operations, providing control over key components of Kafka, and promoting robust and stable integrations.</p><ol><li>Producer Management</li><li>Consumer Management</li><li>Topic Management</li><li>Admin Client Configurations</li><li>Error Handling</li><li>Resource Management</li></ol><p><strong>Producer Management</strong></p><p>It provides interfaces to start/stop producers, send messages to topics, and check the producer running status. It also invokes functions to initialize and terminate producer instances to publish messages to Kafka, and it effectively checks the producer status to ensure that messages are sent successfully.</p><pre>import json<br><br>from kafka_manager.kafka_manager import KafkaManager<br><br>bootstrap_servers = [&#39;localhost:9092&#39;]  # Replace with your Kafka broker addresses<br>topic_name = &#39;example_topic&#39;  # Replace topic name with your choice<br>group_id = &#39;example_group&#39;  # Replace consumer group ID with your choice<br><br># Create a KafkaManager instance<br>kafka_manager = KafkaManager(bootstrap_servers=bootstrap_servers)<br><br># Start the Kafka producer<br>kafka_manager.start_producer();<br><br># Send Kafka message<br>try:<br>    message_payload = json.dumps({<br>        &quot;message_key&quot;: &quot;message_value&quot;<br>    })<br>    metadata = kafka_manager.send_message(topic=topic_name, value=message_payload)<br>    if metadata:<br>        print(f&#39;Message sent successfully to Kafka topic: &quot;{topic_name}&quot;&#39;)<br>    else:<br>        print(f&#39;Failed to send message to Kafka topic: &quot;{topic_name}&quot;&#39;)<br>except Exception as e:<br>    print(f&#39;Error in sending message to Kafka topic: {e}&#39;)<br><br># Stop Kafka producer<br>kafka_manager.stop_producer();</pre><p><strong>Consumer Management</strong></p><p>It enables configuring various configurations to Create/Manage consumers and provides an interface to start/stop consumers. The Kafka Manager allows developers to create consumers per their application needs, such as different deserialization methods or offset management strategies. It provides a user-defined callback function to consume messages, allowing developers to define custom logic for processing each received message and enabling further data processing.</p><pre>from kafka_manager.kafka_manager import KafkaManager<br><br>bootstrap_servers = [&#39;localhost:9092&#39;]  # Replace with your Kafka broker addresses<br>topic_name = &#39;example_topic&#39;  # Replace topic name with your choice<br>group_id = &#39;example_group&#39;  # Replace consumer group ID with your choice<br><br># Create a KafkaManager instance<br>kafka_manager = KafkaManager(bootstrap_servers=bootstrap_servers)<br><br># Create a Kafka Consumer<br>consumer = kafka_manager.create_consumer(topics=[topic_name], group_id=group_id, auto_offset_reset=&#39;earliest&#39;)<br><br># Start the Kafka Consumer<br>kafka_manager.start_consumer(consumer_id=group_id):<br><br>def message_handler(message):<br>    &quot;&quot;&quot;<br>    This method is a callback function called by the consumer, which handles the received messages when a new message<br>    arrives.<br><br>    In production real-world application, the received message would be processed as follows:<br>    - Perform some business logic<br>    - Store the message in a database for further processing.<br>    - Message deserialization<br>    - etc.<br><br>    :param message: Message received from the consumer.<br>    &quot;&quot;&quot;<br>    print(f&#39;Received message: Partition={message.partition}, Offset={message.offset}, Value={message.value}&#39;)<br><br># Consume Messages<br>kafka_manager.consume_messages(consumer_id=group_id, message_handler=message_handler)</pre><p><strong>Topic Management</strong></p><p>Kafka-Manager allows developers to create and delete topics dynamically, which serve as categories from which sent messages are published. It’s essential for managing data streams and evolving application requirements.</p><pre>from kafka_manager.kafka_manager import KafkaManager<br><br>bootstrap_servers = [&#39;localhost:9092&#39;]  # Replace with your Kafka broker addresses<br>topic_name = &#39;example_topic&#39;  # Replace topic name with your choice<br>group_id = &#39;example_group&#39;  # Replace consumer group ID with your choice<br><br># Create a KafkaManager instance<br>kafka_manager = KafkaManager(bootstrap_servers=bootstrap_servers)<br><br># For topic management connect to Kafka admin client<br>kafka_manager.connect_admin_client()<br><br># Create a topic - (if it doesn&#39;t exist)<br>kafka_manager.create_topic(topic_name=topic_name, num_partitions=1, replication_factor=1)</pre><p><strong>Admin Client Configurations</strong></p><p>It provides interfaces to connect to the Kafka Admin client and allows developers to perform administrative operations such as creating and deleting topics. However, the admin-client connection is vital to performing many advanced Kafka management tasks, such as describing cluster configurations and managing Kafka ACLs.</p><pre>from kafka_manager.kafka_manager import KafkaManager<br><br>bootstrap_servers = [&#39;localhost:9092&#39;]  # Replace with your Kafka broker addresses<br>topic_name = &#39;example_topic&#39;  # Replace topic name with your choice<br>group_id = &#39;example_group&#39;  # Replace consumer group ID with your choice<br><br># Create a KafkaManager instance<br>kafka_manager = KafkaManager(bootstrap_servers=bootstrap_servers)<br><br># Connect to Kafka admin client<br>admin_client = kafka_manager.connect_admin_client()<br><br># Listing Consumer Groups<br>consumers_groups = admin_client.list_consumer_groups()<br>print(consumers_groups)<br><br># Describing Consumer Groups<br>admin_client.describe_consumer_groups(list(consumers_groups))</pre><p><strong>Error Handling</strong></p><p>To handle errors in Kafka due to network failures, broker failures, or misconfigurations, Kafka Manager handles these exceptions efficiently and ensures application stability.</p><p><strong>Resource Management</strong></p><p>Kafka Manager resource management ensures that all connections to Kafka are correctly closed. It provides a close() function for proper shutdown, which prevents resource leaks and potential data corruption. It’s essential for maintaining data integrity and managing the Kafka cluster and application.</p><h3><strong>How to use the kafka-manager library?</strong></h3><p>The following section provides a basic example of how to use the <a href="https://pypi.org/project/kafka-manager/">kafka-manager</a> library and a real implementation of its use.</p><pre>import json<br><br>from kafka_manager.kafka_manager import KafkaManager<br><br>bootstrap_servers = [&#39;localhost:9092&#39;]  # Replace with your Kafka broker addresses<br>topic_name = &#39;example_topic&#39;  # Replace topic name with your choice<br>group_id = &#39;example_group&#39;  # Replace consumer group ID with your choice<br><br><br>def message_handler(message):<br>    &quot;&quot;&quot;<br>    This method is a callback function called by the consumer, which handles the received messages when a new message<br>    arrives.<br><br>    In production real-world application, the received message would be processed as follows:<br>    - Perform some business logic<br>    - Store the message in a database for further processing.<br>    - Message deserialization<br>    - etc.<br><br>    :param message: Message received from the consumer.<br>    &quot;&quot;&quot;<br>    print(f&#39;Received message: Partition={message.partition}, Offset={message.offset}, Value={message.value}&#39;)<br><br><br>def main():<br>    # 1. Create a KafkaManager instance<br>    kafka_manager = KafkaManager(bootstrap_servers=bootstrap_servers)<br><br>    # 2. For topic management connect to Kafka admin client<br>    if not kafka_manager.connect_admin_client():<br>        print(&#39;Failed to connect to Kafka admin client.&#39;)<br>        exit()<br><br>    # 3. Create a topic - (if it doesn&#39;t exist)<br>    try:<br>        # Define topic<br>        if not kafka_manager.create_topic(topic_name=topic_name, num_partitions=1, replication_factor=1):<br>            print(f&#39;Failed to create topic &quot;{topic_name}&quot;. Check that if the topic already exists.&#39;)<br>        # In production, please ensure the topic exists; don&#39;t exit the check and continue.<br>    except Exception as e:<br>        print(f&#39;Error in creating Kafka topic: {e}&#39;)<br><br>    # 4. Start the Kafka producer<br>    if not kafka_manager.start_producer():<br>        print(&#39;Failed to start Kafka producer.&#39;)<br>        exit()<br><br>    # 5. Send Kafka message<br>    try:<br>        message_payload = json.dumps({<br>            &quot;message_key&quot;: &quot;message_value&quot;<br>        })<br>        metadata = kafka_manager.send_message(topic=topic_name, value=message_payload)<br>        if metadata:<br>            print(f&#39;Message sent successfully to Kafka topic: &quot;{topic_name}&quot;&#39;)<br>        else:<br>            print(f&#39;Failed to send message to Kafka topic: &quot;{topic_name}&quot;&#39;)<br>    except Exception as e:<br>        print(f&#39;Error in sending message to Kafka topic: {e}&#39;)<br><br>    # 6. Create a Kafka Consumer<br>    consumer = kafka_manager.create_consumer(topics=[topic_name], group_id=group_id, auto_offset_reset=&#39;earliest&#39;)<br>    if consumer is None:<br>        print(&#39;Failed to create consumer.&#39;)<br>        exit()<br><br>    # 7. Start the Kafka Consumer<br>    if not kafka_manager.start_consumer(consumer_id=group_id):<br>        print(&#39;Failed to start consumer.&#39;)<br>        exit()<br><br>    # 8. Consume Messages<br>    kafka_manager.consume_messages(consumer_id=group_id, message_handler=message_handler)<br><br>    # 9. Stop Kafka producers, Kafka consumers and Admin Client.<br>    kafka_manager.stop_producer()<br>    kafka_manager.stop_consumer(consumer_id=group_id)<br>    kafka_manager.close_admin_client()<br>    print(&#39;Stopped all Kafka producer, consumer and admin client.&#39;)<br><br><br>if __name__ == &quot;__main__&quot;:<br>    main()</pre><p>The above example is only a basic implementation of how to get started with the library. Still, you can implement it in the real world based on a suitable design pattern.</p><h3><strong>Conclusion</strong></h3><p>The current development of the library is the initial version, which shows how the library can encapsulate the complexity behind the <a href="https://pypi.org/project/kafka-manager/">kafka-python</a> library and provides an interface to interact with Kafka seamlessly. Still, many more developments are in progress. Stay tuned for future updates. Please check out this repository and contribute if you’ve any new feature suggestions or encounter any issues with bug fixes.</p><p>This article provides an overview of how to get started with the library. If you have any questions or suggestions, please reach out to me on X at <a href="http://twitter.com/anspattnaik">@anspattnaik</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=6554baf9f0da" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How Apache Kafka Works?]]></title>
            <link>https://hackbotone.medium.com/how-apache-kafka-works-6b7aa1faac85?source=rss-14e6e8a4998f------2</link>
            <guid isPermaLink="false">https://medium.com/p/6b7aa1faac85</guid>
            <category><![CDATA[cluster]]></category>
            <category><![CDATA[apache]]></category>
            <category><![CDATA[kafka]]></category>
            <category><![CDATA[distributed-systems]]></category>
            <category><![CDATA[microservices]]></category>
            <dc:creator><![CDATA[Anshuman Pattnaik]]></dc:creator>
            <pubDate>Tue, 25 Apr 2023 19:54:58 GMT</pubDate>
            <atom:updated>2023-04-28T23:23:01.863Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*5cehxP2AmL7qoTXyZGwuIQ.png" /></figure><p>Kafka is a distributed streaming platform, one of the industry’s most widely used framework. The primary use case of this platform is to build a real-time streaming data pipeline that combines messaging, storage, and stream processing to analyze historical and real-time data. This article will teach the architecture behind Kafka and its use cases.</p><h4><strong>What is Apache Kafka?</strong></h4><p>Apache Kafka is an open-source streaming data platform originally developed by LinkedIn. To further enhance the development of this project, LinkedIn donated the project to the <a href="https://kafka.apache.org/">Apache</a> software foundation, and now the framework is being used by many companies for mission-critical projects.</p><p>Kafka is designed to handle high-throughput distributed systems that run as a cluster and can scale to handle large-scale applications and also serve as a storage system that keeps the data as long as necessary, which means it becomes a unique messaging queue from traditional message queue that removes messages immediately after the consumer reads the message. The amount of time Kafka stores the data is called <a href="https://kafka.apache.org/documentation/#upgrade_2_1_0">retention</a>. These retention periods are configurable, and you can set them in the log retention policy. The default value is 168 hours (seven days), after which Kafka will automatically drop the logs even if the segment is not full. Still, as I mentioned, you can change this period and set it to “<strong>forever</strong>” which will keep the log indefinitely.</p><h4><strong>Can Apache Kafka consider as a Database?</strong></h4><p>As we’ve seen, Kafka can also serve as a storage system that can replicate data over the brokers inside a cluster, but can we trade off using Kafka as a database? That depends on your requirements, but in theory, the answer is yes because there are many add-ons provided by Kafka, like <a href="https://ksqldb.io/">ksqlDB</a> or Tiered storage for data processing and event streaming, that you can use in your application. But many different types of databases are available, like relational databases, NoSQL, and many more. Now the question is how to choose which database is suitable for your application, either Kafka or any other traditional database system.</p><blockquote><strong>Trade-Offs</strong></blockquote><ol><li>What is the structure of the data? (i.e. JSON, CSV, etc.)</li><li>How long does the data need to be retained in the database?</li><li>Do I have to run any complex aggregation queries to retrieve the data?</li><li>Do I require an ACID guarantee?</li><li>What is the volume?</li></ol><p>These trade-offs require more analysis, and once you have found all the answers to all these questions, you can decide which database is suitable for your application. Always remember every database architecture is different, and it has its characteristics.</p><h4><strong>What is the architecture and concept behind Apache Kafka?</strong></h4><p>This section will teach some core concepts of Apache Kafka to understand more in-depth how Kafka works.</p><p><strong>Topics</strong></p><p>A topic refers to a category in Kafka where producers publish a stream of data from a particular category, and consumers read those data by subscribing to a specific topic. Once data is published within a topic, it’s immutable, and the user can create <strong>n</strong> number of topics within a Kafka cluster. These topics are quite similar to tables in a database but with no constraints and must be unique so their name can identify them within a Kafka cluster.</p><p>Youtube application can be an example of a Kafka Topic, imagine there are tons of creators who create videos from different areas and publish the videos on youtube with a unique channel name. The user first needs to subscribe to these channels to watch the videos and get a notification when a new video is uploaded. So the channel name is nothing but a Kafka topic; each creator pushes content to the specific channels, and the videos get organized in the youtube system.</p><p><strong>Partitions</strong></p><p>In Kafka, partitions are the smallest storage units, and the messages are stored in the partitions within a particular topic. It’s essential to note that while creating a topic, it’s required to specify the number of partitions. Each message is stored in a partition with an incremental id called offset. This offset value provides guarantees that each message is stored in a partition in a sequenced fashion. There is no limitation to partitions; there can be <strong>n </strong>number<strong> </strong>of partitions within a topic.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*lzF94QJ8qL5ff6YZ0KtkAA.png" /></figure><p>In the above diagram, the topic contains three partitions. Each partition has different offset values that holds unique individual messages, and the relevant partition gets selected when we write a message to a topic. In this example diagram, Partition 0 starts with offset 0, increments the next offset by +1, and at the 10th offset, the next message should be written and stores the messages in each offset sequentially. Partition 1 has 0 to 5 offsets, and the next message that should be written is the 6th. Similarly, Partition 2 has 0 to 9 offsets; the next message that should be written is the 10th offset. So, all three partition stores the messages in each position independently with their offsets.</p><p><strong>Brokers</strong></p><p>A Kafka broker is a container that holds different topics and their partitions. Each broker within a cluster also knows as a Bootstrap broker because a broker contains information on all other brokers, partitions, and topics within a cluster. Kafka Brokers store all the data in a server directory, and each topic partition gets its directory with a topic name associated with it. The main architecture behind Kafka Broker is to achieve higher throughput and scalability on topics, and partitions are distributed among brokers evenly within a cluster.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*nEO1BZKWh4Bs6kBD91hS8Q.png" /></figure><p>In the above diagram, each broker has two topics (A &amp; B) and each partition is distributed among each broker. It’s essential to understand a single broker does not hold all the partitions of a topic. Similarly, topic <strong>B</strong> has three partitions, but it is distributed among each broker within a cluster and has no relationship with the topic <strong>A</strong> partition.</p><p>Kafka Broker is highly efficient in distributing partitions among brokers. In high traffic, the Kafka Administrator can move the partition to a different broker and load balance the cluster.</p><p><strong>Producers</strong></p><p>Kafka Producers is the client that publishes data to topics within different partitions. The main architecture behind producers is to identify automatically which type of data to store on which partition and broker. It’s not required by the user to set any configuration to specify the broker and partition. But in some cases, the user needs to set the preference to specify the partition with a message key to store the message in a specific order.</p><p>The message key allows producers to send data to a specific partition, and if the producer doesn’t apply the key, the data will be written to the default round-robin in each partition. This technique is called load balancing, and this process is quite helpful when the traffic is high and allows a producer to write a little bit of data to distributed partition.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*E8KlWo2me84DV3uitvRh7g.png" /></figure><p>In the above diagram, the producer writes data to a Kafka cluster without specifying the key. The data gets distributed among each partition over Topic-A under each broker — (Broker — 01, Broker — 02, and Broker — 03).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*hxeX7ZOLp9HlBFI1CHxIpQ.png" /></figure><p>In the above diagram, the producer writes data with specifying the key as <strong>msg_id</strong>, so in partition 0 under Broker 1, the data will be sent as <strong>msg_id_1, </strong>and in partition 1 under Broker 2, the data will be sent as <strong>msg_id_2. </strong>The message key concept helps store the data in a specified partition uniquely and retrieve the data by the consumer with the key name.</p><p><strong>Consumer and Consumer Groups</strong></p><p>To read data from Kafka, it’s quite important to understand consumers and consumer groups, as reading data from Kafka is a bit different than other messaging systems. Kafka uses a KafkaConsumer, which creates a consumer object, subscribes to appropriate Kafka topics, and starts receiving messages from these topics.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*4RTeq0VxEapk7gYnhmEqzg.png" /></figure><p>The application will create one consumer object within a consumer group and subscribe to the appropriate topic and start receiving messages, this methodology will work when traffic is less. Still, in case of higher traffic, the producers start writing more and more messages on the topic. With a single consumer, the application fails to balance the load with the incoming rate and is unable to read the messages from the topic. To resolve this issue, we definitely need to scale and allow multiple consumers to read data from the same topic. When multiple consumers subscribe to the same topic within the same consumer group, each consumer will receive messages from different partitions of the topic.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*uzxYKJu203XtVzH9DW3NNg.png" /></figure><p>In the above diagram, there are 3 consumers within a single consumer group, and it’s the main way to scale the data consumption from a Kafka topic by allowing multiple consumers to a consumer group. So, when there is high traffic, Kafka consumers can balance the load and provide high latency in the application. It’s also essential to understand that there is no point in adding multiple consumers when there is less traffic to the application and fewer partitions; otherwise, some consumers will be just idle.</p><p>I’ll publish more in-depth about Kafka Consumers architecture in my future articles.</p><h4><strong>What is Zookeeper?</strong></h4><p>Zookeeper is a free and <a href="https://github.com/apache/zookeeper">open-source</a> distributed software developed by Apache Software Foundation. Zookeeper act as a centralized service to coordinate and manage Kafka cluster nodes and keeps track of Kafka producers, consumers, topics and partitions.</p><p>Zookeeper distributes data over multiple collections of nodes and provides high availability and consistency within a cluster. If a node fails then instantly Zookeeper can performs failover migration and starts a new node in real-time.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*oi4jtklnKwQHblCUWeZPSQ.png" /></figure><p>The services provided by Zookeeper:</p><ol><li><strong>Naming Service</strong> — In a cluster there are multiple nodes and to identify a node required naming service similar to DNS.</li><li><strong>Configuration Management</strong> — To manage the configuration of the system throughout the life cycle it’s important to have a configuration management system.</li><li><strong>Cluster Management — </strong>To monitor when the node joining / leaving and node status at real time in a cluster, it’s requied to have cluster management.</li><li><strong>Leader Election — </strong>The server that has been selected by ensemble server is called a Leader. A node is elected as leader for coordination purpose.</li><li><strong>Locking and Synchromization service — </strong>The mechanism of locking helps to lock the data while modifying it and helps automatic fail recovery while connecting to other distributed applications.</li><li><strong>Highly reliable data registry — </strong>In case of one or few nodes are down the data always be available.</li></ol><p>Zookeeper framework is a highly efficient to manage distributed application, and handled data inconsistency with atomicity and provides various mechanism to overcome with many challenges such as Race condition and deadlock with fail-safe synchronization approach.</p><p>I hope you enjoyed reading this article, which gave you an insight into Kafka architecture and how it works. If you think this article helped you in anyways then feel free to share it with your friends.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=6b7aa1faac85" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[What is ACID (atomicity, consistency, Isolation, and durability)?]]></title>
            <link>https://hackbotone.medium.com/what-is-acid-atomicity-consistency-isolation-and-durability-7c5b39b3cba4?source=rss-14e6e8a4998f------2</link>
            <guid isPermaLink="false">https://medium.com/p/7c5b39b3cba4</guid>
            <category><![CDATA[backend]]></category>
            <category><![CDATA[acid]]></category>
            <category><![CDATA[database]]></category>
            <category><![CDATA[database-design]]></category>
            <category><![CDATA[backend-development]]></category>
            <dc:creator><![CDATA[Anshuman Pattnaik]]></dc:creator>
            <pubDate>Thu, 15 Dec 2022 20:45:03 GMT</pubDate>
            <atom:updated>2022-12-15T20:45:03.143Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*reX2hgQepDYfN8w5ZANVNg.png" /></figure><p>ACID is a set of properties in database transactions that guarantees data integrity with fault tolerance and ensures it keeps the database in a proper state in the event of unexpected errors. Each database operation that satisfies ACID properties is called a transaction. For example — a high-level function transfers funds from one bank account to another, deducts money from one account, and credits it to another is called a single transaction, and ACID properties guarantee that both accounts should have the same initial amount in case of failures.</p><p>In this article, we will explore what a database transaction is, the architecture of a database transaction, and how ACID properties resolve database transaction issues.</p><p><strong>What is a database transaction?</strong></p><p>Databases are responsible for processing millions of concurrent requests per second and allowing multiple clients to access the same system simultaneously. In other words, a sequence of multiple database transactions is executed on a database as a single logical unit that serves all the operations as a whole. Once the transaction is committed, the changes are applied to the database, and the results are saved.</p><p>Let’s look at a typical money transfer example of a database transaction.</p><p>There are two accounts, Accounts (A &amp; B), and we need to transfer $100 from Account A to Account B. Let’s assume account A and B has $50 each.</p><p><strong>Database Transaction Operations:</strong></p><ol><li>Check account A’s balance to see whether it has a minimum balance to transfer money.</li><li>If it has the balance, then subtract $100 from account A.</li><li>Check account B’s balance before it receives a $100 amount from account A.</li><li>Add a $100 credit to account B if it still needs to receive the amount.</li></ol><p>In the above example, if there is a system failure during the transaction, then the database operation will be rollback to its original state, and both accounts will have the initial amount. Because when the database runs this transaction, it performs as a single logical unit and commits only one transaction.</p><p><strong>The architecture of database transactions</strong></p><p>The database transaction has several states to complete an operation and typically one of the following:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*JfFHHXRSSdWpOuWkxxbxbA.png" /><figcaption>Database Transaction Architecture</figcaption></figure><ol><li><strong>Active State: </strong>In every execution of a transaction, it is the first state, and it remains active until the operation fails or is terminated.</li><li><strong>Partially committed State: </strong>Transaction is initiated, and a change has been executed, but the database still needs to commit the whole change on disk instead, it stores the data in the memory buffer.</li><li><strong>Committed State: </strong>In this state, the database executes the final transaction and saves the results in the database. So, we cannot rollback the transaction at this state.</li><li><strong>Failed State: </strong>When a particular transaction fails or is aborted from an active state, it enters a failed state.</li><li><strong>Terminated State: </strong>The final transaction state, either committed or aborted. It is the end of the database transaction.</li></ol><p><strong>What are ACID properties?</strong></p><p>To maintain the consistency of a database transaction, ACID properties are followed before the execution of a transaction. Let’s learn about all these properties and their advantages.</p><p><strong>Atomicity</strong></p><p>Atomicity guarantees that all the operations performed to complete a transaction should be treated as a single logical unit, either committed or failed. In that way, we can identify the database state in case of failure and rollback to the original state.</p><p><strong>Consistency</strong></p><p>Consistency guarantees that all transactions should comply with database constraints. The entire transaction should fail if the data falls into any illegal state.</p><p>For example, In a money transfer operation, there are many constraints: the amount should be a positive integer or the overdraw of the amount, the transaction should fail, etc. Because ACID transaction violates consistency properties and transaction fails.</p><p><strong>Isolation</strong></p><p>To avoid interference between transactions, Isolation guarantees that all transaction operations should perform in an isolated environment so that when multiple transactions run concurrently, they won’t interrupt each other.</p><p>For example, there are only two tickets on a booking website. If two people buy the tickets simultaneously, the transaction should run in Isolation so that when both transactions are complete, each person should have one ticket instead of two.</p><p><strong>Durability</strong></p><p>Durability guarantees that once the transaction operations are completed, and results are stored in the database, they should be persisted. In case of failures or system crashes, data within the system will remain permanent on the disk. However, If the database is lost in case of a crash, the recovery manager guarantees the database&#39;s long-term possibilities.</p><p><strong>Conclusion</strong></p><p>Databases are the key elements to many services and significantly impact our ecosystem. To maintain the database state consistency, it&#39;s essential to ensure the integrity and accuracy of the data that ACID transactions provide with different sets of properties. And it’s hard to imagine, without ACID properties, how we can manage or use services and platforms daily.</p><p>I hope you enjoyed reading this article, which gave you an insight into ACID properties. If you think this article helped you in anyways then feel free to share it with your friends. If you find any difficulties while following this tutorial, please let me know in the comment section.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7c5b39b3cba4" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to build and deploy a Python Flask application to AWS EKS using ECR]]></title>
            <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://hackbotone.medium.com/how-to-build-and-deploy-a-python-flask-application-to-aws-eks-using-ecr-ef9da21aa5e4?source=rss-14e6e8a4998f------2"><img src="https://cdn-images-1.medium.com/max/2600/1*41RrizTj7dJf7_v3G5GoaA.png" width="4000"></a></p><p class="medium-feed-snippet">In this article, I&#x2019;ll demonstrate how to build and deploy a Python Flask application to AWS EKS (Elastic Kubernetes Service) using ECR&#x2026;</p><p class="medium-feed-link"><a href="https://hackbotone.medium.com/how-to-build-and-deploy-a-python-flask-application-to-aws-eks-using-ecr-ef9da21aa5e4?source=rss-14e6e8a4998f------2">Continue reading on Medium »</a></p></div>]]></description>
            <link>https://hackbotone.medium.com/how-to-build-and-deploy-a-python-flask-application-to-aws-eks-using-ecr-ef9da21aa5e4?source=rss-14e6e8a4998f------2</link>
            <guid isPermaLink="false">https://medium.com/p/ef9da21aa5e4</guid>
            <category><![CDATA[python]]></category>
            <category><![CDATA[aws]]></category>
            <category><![CDATA[docker]]></category>
            <category><![CDATA[kubernetes]]></category>
            <category><![CDATA[flask]]></category>
            <dc:creator><![CDATA[Anshuman Pattnaik]]></dc:creator>
            <pubDate>Mon, 12 Dec 2022 02:41:44 GMT</pubDate>
            <atom:updated>2022-12-12T02:41:44.308Z</atom:updated>
        </item>
        <item>
            <title><![CDATA[Cloud Security Governance]]></title>
            <link>https://hackbotone.medium.com/cloud-security-governance-24d5b4918f01?source=rss-14e6e8a4998f------2</link>
            <guid isPermaLink="false">https://medium.com/p/24d5b4918f01</guid>
            <category><![CDATA[cloud-certification]]></category>
            <category><![CDATA[cybersecurity]]></category>
            <category><![CDATA[cloud-security]]></category>
            <category><![CDATA[cloud-security-services]]></category>
            <category><![CDATA[governance]]></category>
            <dc:creator><![CDATA[Anshuman Pattnaik]]></dc:creator>
            <pubDate>Tue, 29 Nov 2022 19:13:25 GMT</pubDate>
            <atom:updated>2022-11-29T19:31:01.862Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*BenhLw-lSS-hyjfCCs5fAA.png" /><figcaption>Cloud Security Governance</figcaption></figure><p>Today’s enterprises are increasingly migrating technology platforms and services into the cloud environment of three primary areas — <strong>Infrastructure as a Service</strong> <strong>(IaaS)</strong>, <strong>Platform as a Service</strong> <strong>(PaaS)</strong> and <strong>Software as a Service (SaaS)</strong>. These services help reduce operating costs and improve efficiency within the infrastructure and the ability to scale the platform and deliver the business objective to end-user customers. However, enterprises find difficulties enforcing security compliance to these services because of infrastructure security challenges commonly found in a cloud environment, such as Insufficient Identity Access Management, Vulnerabilities in the platform, Data breaches and many more. The enterprise must address these security risks and enforce countermeasure policies and procedures to mitigate the threat, which can effectively manage and reduce the security risks in the cloud. Every enterprise’s primary challenge is the need for effective cloud security governance that can help optimize the infrastructure security challenges and cloud security problems.</p><p><strong>What is Cloud Security Governance?</strong></p><p>Cloud security governance is a model of regulations and procedures that enables adequate and efficient security management procedures in the cloud environment so that enterprises can optimize business computing in the cloud by securing the platform, operations and infrastructure. Cloud security governance protocol is specially designed to improve the efficiency and consistency of the cloud infrastructure. This model contains an order of organizational mandates such as operational practices, systems, performance expectations and metrics that will be effective when implemented and create value for the business of an enterprise.</p><p>The enterprise can customize cloud governance models for a specific customer. Still, it’s essential to understand the customer’s operational processes and business requirements to implement an effective security governance model within an enterprise. And also, Cloud security governance provides various frameworks based on the organization’s standards because every infrastructure has different operational structures and procedures. As a result, the cloud security governance architecture is customizable to achieve business requirements and targets.</p><p><strong>What are Cloud Security Governance Challenges?</strong></p><p>The Cloud security governance model is an efficient and effective solution for an enterprise, but the significant challenges the cloud users experience are needing help maintaining these cloud security protocols throughout their business or organizations. The organization’s executive members must understand this security model’s importance and be responsible enough to maintain these models and reach the cloud governance security standards. If the organization’s executive members fail to maintain these standards, the governance model will fail to support business risks, and cloud infrastructure will be vulnerable to cyber-attacks.</p><p>Another primary challenge in cloud security governance is assessing a governance model’s effectiveness. It requires estimating the system to measure the security risks that help the governance model prevent security threats and minimize the attack surface.</p><p><strong>Cloud Security Governance Framework</strong></p><p>In building an efficient cloud security governance model, many customers use a standardized framework appropriate to their infrastructure and follow proper security standards. Many commonly available frameworks are used to develop a security governance model, such as (<a href="https://www.nist.gov/cyberframework">NIST</a>, <a href="https://aws.amazon.com/compliance/irap/">IRAP</a>, <a href="https://aws.amazon.com/compliance/pci-dss-level-1-faqs/">PCI DSS</a>, <a href="https://aws.amazon.com/compliance/iso-27001-faqs/">ISO</a>, etc.). Utilizing these enterprise standard frameworks allows us to enforce minimum security management and provides guidance and best practices for establishing the governance model for security in the cloud infrastructure. Choosing the appropriate governance framework is necessary to accomplish the security standard, reach the enterprise’s business targets, and protect the data of customers and other assets in the cloud environment.</p><p>Once the appropriate framework you’ve chosen then, it’s essential to implement the control mechanism to your cloud infrastructure, including firewalls, logging mechanisms, access management tools and many more. To build a robust security governance model, one must establish the necessary control management.</p><p><strong>Disciplines of Cloud Governance</strong></p><p>Many common governance disciplines are a good starting point and guide the appropriate level of automation and enforcement of organization policy across cloud platforms.</p><p><a href="https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/govern/governance-disciplines#disciplines-of-cloud-governance">https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/govern/governance-disciplines#disciplines-of-cloud-governance</a></p><blockquote><strong>Cost Management</strong>: Cost is a primary concern for cloud users. Develop policies for cost control for all cloud platforms.</blockquote><blockquote><strong>Security Baseline:</strong> Security is a complex subject, unique to each company. Once security requirements are established, cloud governance policies and enforcement apply those requirements across network, data, and asset configurations.</blockquote><blockquote><strong>Identity Baseline:</strong> Inconsistencies in the application of identity requirements can increase the risk of breach. The Identity Baseline discipline focuses on ensuring that identity is consistently applied across cloud adoption efforts.</blockquote><blockquote><strong>Resource Consistency:</strong> Cloud operations depend on consistent resource configuration. Through governance tooling, resources can be configured consistently to manage risks related to onboarding, drift, discoverability, and recovery.</blockquote><blockquote><strong>Deployment Acceleration:</strong> Centralization, standardization, and consistency in approaches to deployment and configuration improve governance practices. When provided through cloud-based governance tooling, they create a cloud factor that can accelerate deployment activities.</blockquote><p><strong>Conclusions</strong></p><p>Gaining professional experience in Cloud computing services requires skills and knowledge to mitigate the security risks to the cloud infrastructure and understand the enterprise requirements in depth to reach business goals. Many <a href="https://www.coursera.org/articles/popular-cloud-security-certifications">Cloud Security and Governance certifications</a> enable one to gain critical knowledge, become a professional in this field, solve real-world security governance challenges, and strengthen your network’s proficiency to safeguard against cyber threats.</p><p>I hope you enjoyed reading this article, which gave you an insight into Cloud Security Governance. If you think this article helped you in anyways then feel free to share it with your friends. If I still need to include something, let me know with a comment below.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=24d5b4918f01" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Arrays and Strings: Two Sum]]></title>
            <link>https://hackbotone.medium.com/arrays-and-strings-two-sum-203e8261d37e?source=rss-14e6e8a4998f------2</link>
            <guid isPermaLink="false">https://medium.com/p/203e8261d37e</guid>
            <category><![CDATA[space-complexity]]></category>
            <category><![CDATA[data-structure-algorithm]]></category>
            <category><![CDATA[leetcode]]></category>
            <category><![CDATA[time-complexity]]></category>
            <category><![CDATA[arrays]]></category>
            <dc:creator><![CDATA[Anshuman Pattnaik]]></dc:creator>
            <pubDate>Sat, 01 Oct 2022 22:00:08 GMT</pubDate>
            <atom:updated>2022-10-01T22:25:17.892Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Twhox6spHEaZF44b_7BVDw.png" /></figure><h3>Problem Statement</h3><p>Given an array of integers nums and an integer target, return <em>indices of the two numbers such that they add up to </em><em>target</em>.</p><p>You may assume that each input would have <strong><em>exactly</em> one solution</strong>, and you may not use the <em>same</em> element twice.</p><p>You can return the answer in any order.</p><p><strong>Example 1:</strong></p><pre><strong>Input:</strong> nums = [2,7,11,15], target = 9<br><strong>Output:</strong> [0,1]<br><strong>Explanation:</strong> Because nums[0] + nums[1] == 9, we return [0, 1].</pre><p><strong>Example 2:</strong></p><pre><strong>Input:</strong> nums = [3,2,4], target = 6<br><strong>Output:</strong> [1,2]</pre><p><strong>Example 3:</strong></p><pre><strong>Input:</strong> nums = [3,3], target = 6<br><strong>Output:</strong> [0,1]</pre><p><strong>Constraints:</strong></p><ul><li>2 &lt;= nums.length &lt;= 104</li><li>-109 &lt;= nums[i] &lt;= 109</li><li>-109 &lt;= target &lt;= 109</li><li><strong>Only one valid answer exists.</strong></li></ul><h3>Solution</h3><p>Let’s understand the problem statement. Given an array of integers and a target sum, we need to write an algorithm which returns indices of two elements in an array, so when we add these two elements, it should be equal to the target sum.</p><p><strong>In Example — 1: </strong>[2, 7, 11, 15] is the given array and the given target sum = 9. If we look at the given array, the sum of pair (2, 7) is 9, i.e. 2 + 7 = 9. The algorithm should return the indices as (0, 1) because the elements 2 and 7 index positions in the given array. And also, we can return the indices in any order, which means either [0, 1] or [1, 0] as output, and both will be correct.</p><h4><strong>Solution 1 — Brute Force</strong></h4><p>The first approach to this problem is checking every possible pair in the given array.</p><p><strong>Algorithm Steps:</strong></p><ol><li>Run two nested loops and check for every combination in the given array.</li><li>Set the outer loop to a specific index and iterate over the inner loop to get all the possible pairs.</li><li>In each iteration of the inner loop, check if the numbers defined by the outer loop index add up to the target sum.</li><li>If the array <strong>nums[outerIndex] + nums[innerIndex] = target</strong> then return <strong>[outerIndex, innerIndex]</strong> as a result. Or else check the next iteration for the next pair.</li><li>Repeat the above steps until you find a possible pair that adds up to the given target.</li></ol><p><strong>Note:</strong> The size of the array element is <strong>n</strong>.</p><p>In the above problem statement, the <strong>nums</strong> array contains [2, 7, 11, 15] and the target sum=9. By following the brute force approach to solving this problem statement, first, we need to set the outer loop at the index to 0, i.e. i=0 (element 7), and then iterate the inner loop from (<strong>j=i+1</strong> to <strong>j=n-1) </strong>from the index 1 to 3 to find out a possible pair. In the current index, the following pair of elements in the first iteration of the outer loop — (2, 7) (2, 11) and (2, 15). Now we find a combination of (2, 7) in the current index as <strong>nums[0] + nums[1] = 9</strong>. So the algorithm returns <strong>[0, 1]</strong> as the possible pair. If we don’t find a pair in the current index then we need to repeat the steps until we find a possible pair.</p><p><strong>Program:</strong></p><p><strong>Language: Python</strong></p><pre>class Solution:<br>    def twoSum(self, nums: List[int], target: int) -&gt; List[int]:<br>        for i in range(len(nums)):<br>            for j in range(i + 1, len(nums)):<br>                if nums[j] == target — nums[i]:<br>                    return [i, j]</pre><p><strong>Result:</strong></p><pre>Runtime: 60ms</pre><pre>Your input: [2, 7, 11, 15]</pre><pre>Output: [0, 1]</pre><pre>Expected: [0, 1]</pre><p><strong>Complexity Analysis</strong></p><ol><li>We traverse the array through each element to find the compliment, which takes O(n) time. Therefore the time complexity is O(n2).</li><li>The size of the input array does not depend on the space, and only constant space is used. Therefore the space complexity is O(1).</li></ol><h4><strong>Solution 2 — Hashmap</strong></h4><p>The second approach to solve this problem is Hashmap. We can store the indices of the elements per iteration.</p><ol><li>Key: The number in the given input array</li><li>Value: The index value in the given input array</li></ol><p><strong>Algorithm Steps</strong></p><ol><li>Initialize a Hashmap that accepts integer datatype as key and value.</li><li>Iterate the array through each element starting from index 0.</li><li>In each iteration, check if the (complementNumber = targetSum — currentArrayValue) is present in the Hashmap.</li><li>If the complement number is present in the Hashmap, return [requiredArrayIndex, currentArrayIndex] as a result.</li><li>Else insert the current array value as a key and index as a value to the Hashmap.</li><li>Repeat the above steps until you find the complement.</li></ol><p><strong>Program:</strong></p><p><strong>Language: Python</strong></p><pre>class Solution:<br>    def twoSum(self, nums: List[int], target: int) -&gt; List[int]:<br>        nums_dict = {}<br>        for i in range(len(nums)):<br>            complement = target - nums[i]<br>            if complement in nums_dict:<br>                return [i, nums_dict[complement]]<br>            nums_dict[nums[i]] = i</pre><p><strong>Result:</strong></p><pre>Runtime: 43ms</pre><pre>Your input: [2, 7, 11, 15]</pre><pre>Output: [1, 0]</pre><pre>Expected: [1, 0]</pre><p><strong>Complexity Analysis</strong></p><ol><li>We traverse the array through each element only once, and each element iteration costs only O(1).</li><li>In the Hash table, the number of items stored at most n elements, so extra space required depends on the items. Therefore the space complexity O(n).</li></ol><p>I hope you find the article useful. If you think this article helped you in anyways then feel free to share it with your friends. If you think of anything I’ve missed, let me know with a comment below.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=203e8261d37e" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[What is a Load Balancer?]]></title>
            <link>https://hackbotone.medium.com/what-is-a-load-balancer-d4a24d8cf00d?source=rss-14e6e8a4998f------2</link>
            <guid isPermaLink="false">https://medium.com/p/d4a24d8cf00d</guid>
            <category><![CDATA[web-security]]></category>
            <category><![CDATA[load-balancer]]></category>
            <category><![CDATA[web-server]]></category>
            <category><![CDATA[cybersecurity]]></category>
            <category><![CDATA[web-development]]></category>
            <dc:creator><![CDATA[Anshuman Pattnaik]]></dc:creator>
            <pubDate>Tue, 27 Sep 2022 18:39:38 GMT</pubDate>
            <atom:updated>2022-09-27T18:39:38.967Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ihD2oYJibAT55KNgZ7qOeQ.png" /></figure><p><strong>Introduction</strong></p><p>Load balancing is a technique to distribute tasks and resources across multiple servers and is generally used to improve the performance of the web application, databases and other services. The load balancer keeps track of the health status of each resource while broadcasting requests to each server. If a server cannot respond or raises an error rate, then Load Balancer stops sending traffic to that server.</p><p>A load balancer acts as a reverse proxy and sits between client and server, receives incoming traffic and distributes the traffic across clusters of servers using various industry standard load balancing algorithms. Load balancing is an efficient technique to reduce the load of an individual server, improve the application availability, and mitigate the application server from becoming a single point of failure.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*FfDKGgcaAzTB4u4ma-VFsA.png" /><figcaption>Load Balancer Architecture</figcaption></figure><p>Load balancers are typically grouped into two types: <strong>Layer 4</strong> and<strong> 7</strong>. <strong>Layer 4</strong> load balancer uses only a TCP connection from a client to the server, while <strong>Layer 7</strong> load balancer uses two TCP connections from the client to the server. <strong>Layer 7</strong> load balances are based on the data’s content, and <strong>Layer 4</strong> load balances are based on its inbuilt software algorithm. <strong>Layer 7</strong> is an excellent choice for microservices. However, <strong>Layer 4</strong> does not apply to microservices.</p><p><strong>Load balancers traffic</strong></p><p>There are four main types of traffic the administrators create as forwarding rules.</p><ol><li>HTTP</li><li>HTTPS</li><li>TCP</li><li>UDP</li></ol><p><strong>1. HTTP</strong></p><p>The Load Balancer sets the <strong>X-Forwarded-For</strong>, <strong>X-Forwarded-Proto, </strong>and <strong>X-Forwarded-Port </strong>headers to provide the backends information regarding the initial request.</p><p><strong>2. HTTPS</strong></p><p>Standard HTTPS balances load using encryption, and it is handled in two techniques with <strong>SSL passthrough </strong>or an <strong>SSL termination</strong>.</p><p><strong>2.1 SSL passthrough</strong></p><p>SSL passthrough is the act of handing data via a load balancer to a server without decrypting. The data is passed along to a web server as a simple HTTP, and the decryption or SSL termination occurs at the load balancer.</p><p><strong>2.2 SSL termination</strong></p><p>SSL termination happens at the load balancer because the decryption process is a very CPU-intensive task. If the load balancer takes the load for decryption, the server spends time processing power on application tasks that helps improve the application performance.</p><p><strong>3. TCP</strong></p><p>A TCP load balancer uses a transmission control protocol which operates at layer 4, and it’s used to route the traffic to a database cluster distributed across all of the servers.</p><p><strong>4. UDP</strong></p><p>A UDP load balancer operates at layer 4 in the OSI model and recently added support to core internet protocols such as DNS and syslogd.</p><p><strong>Backend Server Health Checks</strong></p><p>Healthy backend servers consistently receive incoming traffic from the load balancers. The Load balancer regularly connects with the backend server and checks the health status. If a server fails on a health check and cannot respond to the load balancer, it automatically stops forwarding the traffic to the corresponding server.</p><p><strong>Load Balancing Algorithms</strong></p><p>A Load balancer uses load balancing algorithms to distribute network traffic between servers. There are two types of load balancing algorithms:</p><ol><li>Dynamic load balancing algorithms</li><li>Static load balancing algorithms</li></ol><p><strong>Dynamic load balancing algorithms</strong></p><p>Dynamic load balancing algorithms use each server’s current state and distribute the traffic accordingly. It is divided into four different types.</p><ol><li>Least connection</li><li>Weighted least connection</li><li>Weighted response time</li><li>Resource-based</li></ol><p><strong>1. Least connection</strong></p><p>Load balancers check which server has the fewest connections open and send traffic to those servers, which means all the connections require equal processing power.</p><p><strong>2. Weighted least connection</strong></p><p>It gives the privilege to the administrator to assign different weights to each server by the assumption that some servers can handle more connections.</p><p><strong>3. Weighted response time</strong></p><p>The average response time of each server and the number of open connections specify where to send traffic. The algorithm sends traffic to the server with the fastest response time, ensuring quicker service to the end users.</p><p><strong>4. Resource-based</strong></p><p>Specialized software called <strong>agent</strong> runs on each server that measures the server’s available CPU and memory. The load balancers query the agent to check what resources are available on each server while distributing the traffic to that server.</p><p><strong>Static load balancing algorithms</strong></p><p>Static load balancing algorithms send an equal amount of traffic to each server; either it can be random or in a specified order. It is divided into three different types.</p><ol><li>Round robin</li><li>Weighted round-robin</li><li>IP hash</li></ol><p><strong>1. Round robin</strong></p><p>Round robin load balancing algorithm distributes traffic to clusters of servers in a cycle using DNS. The load balancer selects the first server from the list and then moves down to the second until it reaches the end.</p><p><strong>2. Weighted round-robin</strong></p><p>It gives the privilege to the administrators to assign different weights to each server so that the servers can handle more traffic. Using DNS records can configure the weighting.</p><p><strong>3. IP hash</strong></p><p>The combination of incoming traffic’s source and destination IP addresses generates a hash using a mathematical function. The connection is assigned to a specific server by using the generated hash.</p><p><strong>How to handle Load Balancers failure?</strong></p><p>There are many ways a load balancer can fail within a system. If one load balancer fails, the second load balancer should connect immediately and can become active. The two load balancers can be connected to form a cluster, where each can monitor the status of the other’s heartbeat; each load balancer has equal capability to detect failure and recovery.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*bxcIV8coWiileJWqGYpIWQ.png" /><figcaption>Load balancing in a cluster</figcaption></figure><p>When the primary load balancer fails, the DNS should be able to route the application to the second load balancer. But to make changes to the DNS, It will take a minimum of <strong>24 hours</strong> to reflect on the internet. To make this process automatic, system administrators use systems like <a href="https://en.wikipedia.org/wiki/Reserved_IP_addresses"><strong>Reserved IPs</strong></a> that allow for elastic IP address mapping. The IP address with the domain name remains the same but is moved between servers.</p><p><strong>Conclusion</strong></p><p>I hope you enjoyed reading this article, which gave you an insight into Load Balancers. If you think this article helped you in anyways then feel free to share it with your friends. If you think of anything I’ve missed, let me know with a comment below.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d4a24d8cf00d" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[HTTP Headers Fields: Types, Directives, Syntax and Usage]]></title>
            <link>https://hackbotone.medium.com/http-headers-b1fbcc9ab64c?source=rss-14e6e8a4998f------2</link>
            <guid isPermaLink="false">https://medium.com/p/b1fbcc9ab64c</guid>
            <category><![CDATA[web-security]]></category>
            <category><![CDATA[cybersecurity]]></category>
            <category><![CDATA[http-headers]]></category>
            <category><![CDATA[web-development]]></category>
            <category><![CDATA[website]]></category>
            <dc:creator><![CDATA[Anshuman Pattnaik]]></dc:creator>
            <pubDate>Sat, 24 Sep 2022 20:59:23 GMT</pubDate>
            <atom:updated>2022-09-24T21:21:50.808Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*6M_ZSy17NOVkdF7Tf0AVrA.png" /></figure><p><strong>Introduction</strong></p><p>HTTP headers are the list of strings used to pass information between client and server through request and response headers. These headers are hidden from the end user and only processed or logged by the server and client applications. HTTP headers consist of their case-insensitive name and colon-separated by key-value pair in clear text string format with a Whitespace before the value, terminated by a carriage return (CR) and line feed (LF) character sequence. At the end of the header section, two consecutive CR-LF pairs are marked by the empty field line. HTTP method names (GET, POST, etc.) are case-sensitive, and the header field names are case-insensitive.</p><p>HTTP headers are the essential components of the request and response, containing information about the client browser, the target server host, cookie and more. The <a href="https://www.ietf.org/">Internet Engineering Task Force (IETF)</a> standardized the HTTP headers field names in <a href="https://www.rfc-editor.org/rfc/rfc7230">RFC7230</a>, <a href="https://www.rfc-editor.org/rfc/rfc7231">RFC7231</a>, <a href="https://www.rfc-editor.org/rfc/rfc7233">RFC7233</a>, <a href="https://www.rfc-editor.org/rfc/rfc7234">RFC7234 </a>and <a href="https://www.rfc-editor.org/rfc/rfc7235">RFC7235</a>. The IANA maintains the Field Names, Header Fields and Repository of Provisional Registrations.</p><p>As per the standard, there is no size limit for HTTP headers. In an HTTP message, there can be as many Headers as possible, but because of security reasons and page loading performance issues, the web servers limit the size of the HTTP headers. For example — the Apache server limits the size of the HTTP headers to 8,190 bytes and 100 HTTP Headers.</p><p><strong>HTTP Headers types</strong></p><ol><li>Request HTTP Headers</li><li>Response HTTP Headers</li><li>Representation HTTP Headers</li><li>Payload HTTP Headers</li><li>End-to-end HTTP Headers</li><li>Hop-by-hop HTTP Headers</li></ol><p><strong>1. HTTP Request Headers</strong></p><p><strong>Standard request fields</strong></p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/3cbd4f111b451374284ac2dcf7ce6d70/href">https://medium.com/media/3cbd4f111b451374284ac2dcf7ce6d70/href</a></iframe><p><strong>Non-standard request fields</strong></p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/f7541f91a86369fb5cc205bf43ea6bf6/href">https://medium.com/media/f7541f91a86369fb5cc205bf43ea6bf6/href</a></iframe><p><strong>2. HTTP Response Headers</strong></p><p><strong>Standard response fields</strong></p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/e5faaef3a776fa8fae8997cf8719a127/href">https://medium.com/media/e5faaef3a776fa8fae8997cf8719a127/href</a></iframe><p><strong>Non-standard response fields</strong></p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/965e1d0c2593f75a246f4b062d3cd0bc/href">https://medium.com/media/965e1d0c2593f75a246f4b062d3cd0bc/href</a></iframe><p><strong>3. Representation Headers</strong></p><p>A representation header is an HTTP header representing the individual model of the resource sent in an HTTP message body. A particular resource is always a different representation, meaning the same data is formatted in a specific media type, such as <a href="https://www.json.org/json-en.html">JSON </a>or <a href="https://developer.mozilla.org/en-US/docs/Web/XML/XML_introduction">XML</a>. In each case, the underlying structure of the resource is the same, but the data representation is different.</p><ol><li>Content-type</li><li>Content-Encoding</li><li>Content-Language</li><li>Content-Location</li></ol><p><strong>4. Payload Header</strong></p><p>A payload header is an HTTP header representing the message body described to secure transmission and construct the resource representation. The information includes the message payload length, encoding, integrity checks, etc. The payload header presents in both HTTP request and response messages.</p><ol><li>Content-Length</li><li>Content-Range</li><li>Trailer</li><li>Transfer-Encoding</li></ol><p><strong>Lists of HTTP Headers</strong></p><ul><li>HTTP access control (CORS)</li><li>HTTP Authentication</li><li>HTTP Caching</li><li>HTTP Compression</li><li>HTTP Conditional Requests</li><li>HTTP Content Negotiation</li><li>HTTP Cookies</li><li>HTTP Range Requests</li><li>HTTP Redirects</li><li>HTTP Proxies</li><li>HTTP Controls</li><li>HTTP WebSockets</li><li>HTTP Downloads</li><li>HTTP Connection Management</li></ul><p><strong>HTTP access control (CORS)</strong></p><p>CORS HTTP Headers are related to security HTTP headers that provide a mechanism to indicate the origins of the request. The request and response get processed based on the policy between different origins.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/10d42607d84296a4f104a50f8f16a138/href">https://medium.com/media/10d42607d84296a4f104a50f8f16a138/href</a></iframe><p><strong>HTTP Authentication</strong></p><p>The client and server use the HTTP authentication framework to share authentication information and inspect a client’s request. These headers are used mainly for proxy and webserver authentication. The Web servers can communicate with the user-agent and requestor based on the proxy-server authentication information.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/35907ded9b61dd108501bf7e6f8beaff/href">https://medium.com/media/35907ded9b61dd108501bf7e6f8beaff/href</a></iframe><p><strong>HTTP Caching</strong></p><p>HTTP caching headers are used to cache the web page resources such as Images, Javascript, CSS files and other related resources. Caching mechanism is always required to improve the loading performance of the webpage.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/d2e406dc0a7ca098443a97d4eda48efe/href">https://medium.com/media/d2e406dc0a7ca098443a97d4eda48efe/href</a></iframe><p><strong>HTTP Compression</strong></p><p>HTTP compression header is used to compress the web page resources, increasing page loading performance. These compression headers the web developers don’t need to implement by themselves as both browsers and servers implement these compression headers mechanisms by default. But as a practice still, it’s required to check the server configurations.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/89551d527fff7a4c02a6effb670e9f01/href">https://medium.com/media/89551d527fff7a4c02a6effb670e9f01/href</a></iframe><p><strong>HTTP Conditional Requests</strong></p><p>HTTP conditional header is used for conditional requests where the value of a validator can change the results by comparing the affected resources. The conditional requests are always helpful in validating the content of the cache and performing other useful operations to verify the integrity of a document.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/447bc2fdac5da0929ee3ae53b3ac0dfb/href">https://medium.com/media/447bc2fdac5da0929ee3ae53b3ac0dfb/href</a></iframe><p><strong>HTTP Content Negotiation</strong></p><p>Content negotiation is a mechanism that serves different representations of resources to the same URI, such as which document language, which image format or which content encoding.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/fff95cd3d94379095a5de3e81c2a805f/href">https://medium.com/media/fff95cd3d94379095a5de3e81c2a805f/href</a></iframe><p><strong>HTTP Cookies</strong></p><p>Cookie HTTP headers are used to retrieve stored HTTP Cookies from the server. It can also send or receive cookies from web servers.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/b0cea320fd70b11fa0e859051f393eda/href">https://medium.com/media/b0cea320fd70b11fa0e859051f393eda/href</a></iframe><p><strong>HTTP Range Requests</strong></p><p>HTTP range requests header is used to request the server to send only part of the HTTP message back to the client, and these headers are useful while retrieving large files from the target web server.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/e21735d510ac99c2bebb65188c948706/href">https://medium.com/media/e21735d510ac99c2bebb65188c948706/href</a></iframe><p><strong>HTTP Redirects</strong></p><p>HTTP redirects header is used to redirect a web page URL to a particular location using the Location header.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/13ab41828e820dcdddb8cad621d22264/href">https://medium.com/media/13ab41828e820dcdddb8cad621d22264/href</a></iframe><p><strong>HTTP Proxies</strong></p><p>HTTP proxy header provides information for the proxy servers, such as originating IP address, origin host, etc.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/91ba36b2d6e1dab9acce3af7b40a6885/href">https://medium.com/media/91ba36b2d6e1dab9acce3af7b40a6885/href</a></iframe><p><strong>HTTP Controls</strong></p><p>HTTP Controls header is used to specify how the server handles the request during the transmission of the message.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/7a8a3e28cc0f2fae929109b875ce2687/href">https://medium.com/media/7a8a3e28cc0f2fae929109b875ce2687/href</a></iframe><p><strong>HTTP WebSockets</strong></p><p>HTTP WebSockets headers are used for WebSockets to send and receive data between a web browser and a web server. WebSockets HTTP headers enhance client and web server transmission for two-way interactive sessions.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/3185015ecc8b598a48d809da2334b05d/href">https://medium.com/media/3185015ecc8b598a48d809da2334b05d/href</a></iframe><p><strong>HTTP Downloads</strong></p><p>HTTP Downloads header contains only “Content-Disposition”, which provides a “<strong>Save As</strong>” dialog option within the browser to display the content inline or usually handled, such as download action.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/d9c2ffe8bd5c7d878573038e1ecffbaf/href">https://medium.com/media/d9c2ffe8bd5c7d878573038e1ecffbaf/href</a></iframe><p><strong>HTTP Connection Management</strong></p><p>HTTP Connection Management header controls the connection request and determines the connection life for how long to keep the connection alive. These headers are essential to maintain the server overload and response time quality.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/f0e2239e675309fa760fe70624d2876f/href">https://medium.com/media/f0e2239e675309fa760fe70624d2876f/href</a></iframe><p><strong>What is the need for HTTP Headers on a Website?</strong></p><p>HTTP Headers are the key to the website, which determine how the web browser will pass messages to the web server and performs different actions based on the HTTP Status Codes, such as redirecting the website to a particular location, etc. HTTP Headers help improve the web page loading performance and security to protect the user’s privacy from cybersecurity issues and vulnerabilities, which are critical for search engine optimization, web server security, etc. HTTP Headers are very useful in enhancing the SEO of the website, which instructs the search engine to index a page using robot directives and improves the ranking of the website. HTTP headers can change the behaviour and functionality of the website by its configurations; they can serve different web pages of a website.</p><p>I hope you enjoyed reading this article, which gave you an insight into HTTP Headers. If you think this article helped you in anyways then feel free to share it with your friends. If you think of anything I’ve missed, let me know with a comment below.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b1fbcc9ab64c" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[http/1.1 vs http/2]]></title>
            <link>https://hackbotone.medium.com/http-1-1-vs-http-2-830f0364a8a4?source=rss-14e6e8a4998f------2</link>
            <guid isPermaLink="false">https://medium.com/p/830f0364a8a4</guid>
            <category><![CDATA[world-wide-web]]></category>
            <category><![CDATA[web-development]]></category>
            <category><![CDATA[multiplexing]]></category>
            <category><![CDATA[http2]]></category>
            <category><![CDATA[http1]]></category>
            <dc:creator><![CDATA[Anshuman Pattnaik]]></dc:creator>
            <pubDate>Sun, 18 Sep 2022 18:36:51 GMT</pubDate>
            <atom:updated>2022-09-19T17:39:28.281Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*QG4BPLPAQcbDgAD-2PaZug.png" /></figure><h3><strong>Introduction</strong></h3><p>The HTTP or Hypertext Transfer Protocol is an application layer control protocol for transmitting hypermedia documents such as graphics, audio, video, plain text and hyperlinks on the World Wide Web. To obtain information from the target web server, the client makes a request and keeps the Connection open until it receives a response. HTTP is a stateless protocol that means the target server does not support information between two requests.</p><p>Since the evolvement of HTTP/1.1 in 1997, this version was the standardized communication protocol in <a href="https://datatracker.ietf.org/doc/html/rfc2068">RFC 2068</a> until the HTTP/2 protocol was introduced in 2015 by IETF (<a href="https://www.ietf.org/">Internet Engineering Task Force</a>). HTTP/2 protocol version was introduced to decrease latency, increase speed and enable complete request and response multiplexing, which means when the client opens a connection to the target web server, it can send multiple requests and receive multiple responses with a single line of communication.</p><p>Now, let’s dive deep into these two protocols and understand the main difference between HTTP/1.1 and HTTP/2 and the technical changes HTTP/2 has adopted in the modern World Wide Web.</p><h3><strong>What is HTTP/1.1?</strong></h3><p>In 1989 Timothy Berners Lee developed a communication protocol for the World Wide Web called Hypertext Transfer Protocol that exchanges data between a client and a remote web server. When a client visits a website on his browser, for example — <a href="http://www.google.com,"><strong>www.google.com,</strong></a> it sends a request to the remote web server and waits until the server sends a response; in this communication, the server acknowledges it with an HTML page.</p><p>To send a particular request client calls methods like <strong>GET </strong>or <strong>POST, </strong>which later be interpreted by HTTP and processed to the remote web server.</p><pre>GET /index.html HTTP/1.1<br>Host: <a href="http://www.google.com">www.google.com</a></pre><p>The above HTTP request is an example of a<strong> GET </strong>method, and it requests the remote <strong>Host:</strong> to get the resources of <a href="http://www.google.com"><strong>www.google.com</strong></a> and the web server returns an HTML with all the necessary resources like CSS, js, images, etc. But all these contents are not returned to the client at once in a single request. To render the complete HTML page on the web browser, the client sends multiple requests to receive all the resources from the target web server; once the web browser receives all the resources, it displays the complete HTML web page on the screen.</p><h3><strong>What is HTTP/2?</strong></h3><p>HTTP/2 is a primary revision of HTTP/1.1 and derived from the <a href="https://www.chromium.org/spdy/spdy-whitepaper/">SPDY</a> protocol, which Google originally developed as a way to improve the web page loading performance by reducing the latency using the technique such as complete request and response multiplexing, efficient Compression of HTTP header fields, enabling request prioritization and server push.</p><p>The HTTP Working Group developed HTTP/2, also called as httpbis, of the <a href="https://www.ietf.org/">Internet Engineering Task Force</a> (IETF). The Working Group first presented the HTTP/2 protocol research to the <a href="https://datatracker.ietf.org/group/iesg/about/">Internet Engineering Steering Group</a> (IESG) on December 2014, and later IESG approved it on February 17, 2015. The specification for HTTP/2 was published as <a href="https://datatracker.ietf.org/doc/html/rfc7540">RFC-7540</a> on May 14, 2015. The protocol is supported by many standardized browsers Chrome, Firefox, Safari, Opera and many more.</p><p>The architecture behind HTTP/2 is the binary framing layer which sends all the requests and responses in binary format and maintains HTTP semantics such as methods and headers. When the client makes a request using a high-level API, it still constructs the messages in traditional HTTP formats. Still, it’s essential to understand that all these messages are converted into binary at a low level. HTTP/2 version has many features and evolved significantly by transforming messages from plain text to binary, allowing this protocol to deliver the message faster and more efficiently.</p><p>As of now, we understand the typical difference between these two protocols and ensure that both protocols use the same HTTP semantics such as headers, methods and verbs. To send messages, HTTP/1.1 uses the plain text technique, and HTTP/2 transform the messages into binary. In the next section, we will briefly discuss how HTTP/1.1 uses different methods to send messages and what challenges occurred and were resolved by the HTTP/2 using the binary framing layer technique.</p><h3><strong>Head Of Line blocking in HTTP/1.1</strong></h3><p>In computer networking, <a href="https://en.wikipedia.org/wiki/Head-of-line_blocking#:~:text=Head%2Dof%2Dline%20blocking%20(,multiple%20requests%20in%20HTTP%20pipelining.">Head-of-line blocking</a> (HOL blocking) is a performance-limiting phenomenon that occurs when a group of packets are in the queue by the first packet in line. For example — when the client or browsers have restrictions on accessing a server, and a new request waits for the previous request to complete before it can be processed.</p><p>In HTTP/1.1 (HOL), blocking occurs because when a client opens a TCP connection, it sends multiple requests with the same Connection without waiting for a response. After all, HTTP/1.1 protocol creates persistent connections by default without specifying the <strong>Connection: keep-alive</strong> header that allows multiple requests to be sent over the same TCP connection using the pipeline technique. However, the pipeline improves the loading time performance of the webpage but also creates a HOL blocking issue because processing one request or response takes a longer time, which causes a delay in retransmitting other requests and responses.</p><p>HTTP/2 fixes HOL blocking issues using the binary framing layer technique that improves the connection efficiency and allows multiple connections to increase the flexibility of transmitting information to the desired destination. In the next section, we will learn more about the binary framing layer technique and its advantages.</p><h3><strong>HTTP/2 — Binary Framing Layer</strong></h3><p>The binary framing layer converts requests/responses into binary and breaks them into smaller chunks to form a bidirectional communication stream. HTTP/2 establishes a single TCP connection between the client and the server, and during the Connection, there are multiple streams of data transfers between two machines.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Ld46mPk36I2wKg2sxbbudQ.png" /></figure><p>Each stream contains multiple messages in request/response form, which are divided into smaller units called Frames. HTTP/2 concurrently can open various streams within a single connection and can assign frames from other streams on the Connection. A Stream is a bidirectional flow of frames between two machines, and What can also share Streams between the client and the server.</p><p>The architecture behind HTTP/2 consists of a group of binary-encoded frames within a single communication channel that is tagged to a particular stream. Each frame is the smallest unit of communication that contains a specific type of data — For example, HTTP Headers, messages, etc. Those frames are from different streams interleaved and reassembled via an embedded stream identifier in each frame’s header. The interleaved requests and responses run in parallel without blocking the messages behind them and confirm no messages have to wait for another to finish, and this methodology is called multiplexing.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*e07Zg0wpYoJICGDrjeqHrA.png" /></figure><p>The multiplexing technique allows servers and clients to send concurrent requests and responses for more efficient connection management within a single TCP connection and also reduces the latency, improves the network and bandwidth utilization and lowers the operational cost throughout the network. To secure the communication throughout the channel, the client and the server can reuse the same secured session for multiple requests and responses because during TLS or SSL handshaking, both the machines agree to use a single key throughout the session; if the session ends a new key will generate for further communication that also improves the performance of HTTPS protocol.</p><p>As a final thought, multiplexing with a binary framing layer improves the performance of TCP communication and solves a couple of issues of the HTTP/1.1 protocol. But still, within a channel, awaited streams use the same resources that cause performance issues. In the next section, we will learn how stream prioritization optimizes application performance and manage resources.</p><h3><strong>HTTP/2 — Stream Prioritization</strong></h3><p>Stream Prioritization is a technique that allows customization of requests’ relative weight to optimize application performance and solves potential requests competition for the same resource. The prioritization technique is essential to understand better, so you can take benefit of this feature of HTTP/2.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*g7SXiKEkIJ9StVQlCRBYQA.png" /></figure><p>The binary framing layer manages requests/responses into a parallel data stream. When a server receives concurrent client requests, it prioritizes the responses by setting a weight between 1 and 256 per stream. If the number is higher, then that is the higher priority. An Identifier specifies each stream’s dependency on another stream by the client, so it’s easier to identify the dependant of the stream. When there is no parent stream ID, the root stream is considered as the stream’s dependent.</p><p>The client constructs and communicates a prioritization tree by combining stream dependencies and their weight, showing how the client would prefer to receive the responses. The server utilizes this information to prioritize stream processing by controlling resource utilization, such as allocating CPU, memory, and other resources. When the response data is ready to send to the client, it ensures bandwidth allocation is better so it can able to deliver high-priority responses to the client. Streams that share the same parent should allocate resources in proportion to their weight.</p><p>Let’s see a few examples to get hands-on with stream allocation.</p><p><strong>Examples</strong></p><blockquote>Author, <a href="https://www.igvita.com/">Ilya Grigorik</a> (Year). Title of the article. <a href="https://www.oreilly.com/library/view/high-performance-browser/9781449344757/ch12.html">High-Performance Browser Networking, Stream Prioritization.</a></blockquote><blockquote>If stream A has a weight of 12 and its one sibling B has a weight of 4, then to determine the proportion of the resources that each of these streams should receive:</blockquote><blockquote>Sum all the weights: 4 + 12 = 16</blockquote><blockquote>Divide each stream weight by the total weight: A = 12/16, B = 4/16</blockquote><blockquote>Thus, stream A should receive three-quarters and stream B should receive one-quarter of available resources; stream B should receive one-third of the resources allocated to stream A. Let’s work through a few more hands-on examples:</blockquote><blockquote>Neither stream A nor B specify a parent dependency and are said to be dependent on the implicit “root stream”; A has a weight of 12, and B has a weight of 4. Thus, based on proportional weights: stream B should receive one-third of the resources allocated to stream A.</blockquote><blockquote>D depends on the root stream; C depends on D. Thus, D should receive full allocation of resources ahead of C. The weights are inconsequential because C’s dependency communicates a stronger preference.</blockquote><blockquote>D should receive full allocation of resources ahead of C; C should receive full allocation of resources ahead of A and B; stream B should receive one-third of the resources allocated to stream A.</blockquote><blockquote>D should receive full allocation of resources ahead of E and C; E and C should receive equal allocation ahead of A and B; A and B should receive a proportional allocation based on their weights.</blockquote><p>As we saw in the above examples by <a href="https://www.igvita.com/">Ilya Grigorik</a>, resource prioritization is crucial in improving browsing performance in today’s modern web applications with the combination of stream dependencies and weights.</p><p>And also, HTTP/2 allows the client to change the preferences at any moment, enabling further enhancement to the browser, which means we can reallocate weights in response, and update the dependencies, to enhance the user browsing experience.</p><h3><strong>Resource Inlining vs Server Push</strong></h3><p>In every web application, when a client sends a GET request to the target web server in the first response, it only accepts the website’s index page. But to render the complete web page on the browser still requires fetching additional resources such as CSS, Javascript and other media files. So, the client makes further requests to bring other resources but increases latency and web page load time and consumes more bandwidth.</p><p>This section will discuss how HTTP/1.1 and HTTP/2 follow different methodologies to improve the web page loading time and reduces bandwidth consumption.</p><h3><strong>HTTP/1.1 — Resource Inlining</strong></h3><p>In HTTP/1.1, resource inlining is a technique to include the required resources with the HTML document so that the server can send all the resources in the response at the initial request. For example — To render the complete web page, the index.html file requires additional resources; inlining these resources with the index file will reduce the total number of network calls. This technique is only feasible for text-based resources. However, inline, a large file with an HTML document can significantly increase the HTML document’s size and reduces the network speed, delaying response to the client.</p><p>The major drawback of resource inline is that the client cannot separate the inlined resources from an HTML document or cache the resources in a particular state. And if every web page on the site is inline with the same resource, it will increase the HTML document’s size and reduce the web page loading time.</p><p>The resource inlining technique is not optimal for decreasing the web page loading time and increasing the connection speed. In the next section, we will learn how HTTP/2 uses server push methodology to optimize the web page connection.</p><h3><strong>HTTP/2 — Server Push</strong></h3><p>In HTTP/2, as we know, it sends multiple concurrent responses to the client’s requests. The target web server can send additional resources along with the HTML document without the client’s request for the resource, and this process is called server push. HTTP/2 even maintains the separation between pushed resources and HTML documents by using this technique, which resolves the issue of resource inlining as the client can either cache the resource or decline the pushed resources from the HTML document.</p><p>The technique behind this process is that the server will send a <a href="https://httpwg.org/specs/rfc7540.html#PUSH_PROMISE">PUSH_PROMISE</a> frame to notify the client that it will send a pushed resource. The frame only includes the header of the message, and the client knows which type of resource the server will push before sending the request. In this technique, if the client already cached the existing resource, it can decline the pushed resource by sending an <a href="https://httpwg.org/specs/rfc7540.html#RST_STREAM">RST_STREAM</a> frame in the response. As the client knows ahead of time which resources the server will send, it holds the client from sending duplicate requests.</p><p>The client has complete control over server push that can adjust the priority or even disable the server push; whenever required, it will only send a <a href="https://httpwg.org/specs/rfc7540.html#SETTINGS">SETTINGS</a> frame to change the HTTP/2 component.</p><p>The server push has many features but is still not supported by the many web browsers that disable many critical components for the client, such as cancelling a cached resource, allowing duplicate resources, etc. And this technique should be used based on the requirement of the web application.</p><p>To read more on web application optimization and server push, you can check out the <a href="https://www.patterns.dev/posts/prpl/">PRPL</a> pattern developed by Google.</p><h3><strong>Header Compression</strong></h3><p>The most common message between the client and server in every HTTP transmission is the HTTP headers. These headers are always sent as plain text of around 500–800 bytes per transfer; if the header contains a cookie, the size can be up to kilobytes. To reduce the size of the HTTP messages, HTTP uses various compression algorithms so that the web application performance can be increased and transferring of messages can be faster.</p><h3><strong>HTTP/1.1 — gzip compression</strong></h3><p>In HTTP/1.1, a program like <a href="https://www.gzip.org/">gzip</a> compression software is used to compress the size of CSS and JavaScript files to reduce the data size. But the major problem in HTTP/1.1 is that the headers are always transferred in plain text, which increases the message’s size. When API has many different features and resources, such as Cookies and additional headers, the weight of the messages becomes heavy and increases the latency transfer rate.</p><p>To solve the header compression issue, HTTP/2 has a compression feature, <a href="https://www.rfc-editor.org/rfc/rfc7541">HPACK</a>, which we will discuss in the next section.</p><h3><strong>HTTP/2 — HPACK Compression</strong></h3><p>In HTTP/2, compressing the header is different; it divides the header from the data and keeps it in a header and data frame. To compress the header frame, HTTP/2 uses the compression software <a href="https://www.rfc-editor.org/rfc/rfc7541">HPACK</a>. The algorithm behind this compression program is <a href="https://en.wikipedia.org/wiki/Huffman_coding">Huffman coding</a> which encodes the header metadata and reduces the size of the header.</p><p>The HPACK also keeps track of the previous header metadata, which will only compress the altered field in the subsequent request.</p><pre>Request — 1<br>— — — — — —<br>method: GET<br>scheme: https<br>host: example.com<br>path: /blog<br>accept: /image/png<br>user-agent: Mozilla/5.0…</pre><pre>Request — 2<br>— — — — — —<br>method: GET<br>scheme: https<br>host: example.com<br>path: /blog/17885642<br>accept: /image/png<br>user-agent: Mozilla/5.0…</pre><p>In the above requests, the only path header uses different values that update dynamically in the subsequent request. So, in Request — 2, the HPACK will only compress the path header metadata and restore the most common and newly encoded path fields.</p><p>To learn more on HPACK, you can also refer to <a href="https://www.rfc-editor.org/rfc/rfc7541">RFC7541</a>.</p><h3><strong>Conclusions</strong></h3><p>There are many significant differences between HTTP/1.1 and HTTP/2 in terms of features and techniques to improve web application performance. As we’ve seen, both the protocols’ implementations to enhance the web are entirely different. HTTP/2 changes the web architecture by implementing various methods such as multiplexing, stream prioritization, flow control, server push and compression that transform the web application to the next level.</p><p>I hope you enjoyed reading this article, which gave you an insight into the difference between HTTP/1.1 and HTTP/2. If you think this article helped you in anyways then feel free to share it with your friends. If you think of anything I’ve missed, let me know with a comment below.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=830f0364a8a4" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>