<?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"><channel><title><![CDATA[Saurabh Mahajan]]></title><description><![CDATA[Living, Learning and Leveling up, one day at a time]]></description><link>https://blog.saurabhmahajan.com</link><generator>RSS for Node</generator><lastBuildDate>Tue, 21 Apr 2026 14:04:37 GMT</lastBuildDate><atom:link href="https://blog.saurabhmahajan.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Clean Code - The Practical Guide]]></title><description><![CDATA[Introduction
In the vast landscape of software development, writing code is not just about instructing a computer to perform a task; it's about crafting a language that communicates with fellow developers, both present and future. Clean code is the a...]]></description><link>https://blog.saurabhmahajan.com/clean-code-the-practical-guide</link><guid isPermaLink="true">https://blog.saurabhmahajan.com/clean-code-the-practical-guide</guid><category><![CDATA[code]]></category><category><![CDATA[coding]]></category><category><![CDATA[clean code]]></category><category><![CDATA[#codenewbies]]></category><category><![CDATA[#namingconvention]]></category><category><![CDATA[comments]]></category><category><![CDATA[Code Formatting]]></category><category><![CDATA[classes]]></category><category><![CDATA[Objects]]></category><category><![CDATA[dry]]></category><category><![CDATA[KISS]]></category><category><![CDATA[YAGNI]]></category><category><![CDATA[OOPS]]></category><category><![CDATA[SOLID principles]]></category><category><![CDATA[TDD (Test-driven development)]]></category><dc:creator><![CDATA[Saurabh Mahajan]]></dc:creator><pubDate>Mon, 20 Jan 2025 16:16:56 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1737387571600/a5007bde-78fb-4c5e-929b-6aa1f6396d66.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-introduction">Introduction</h1>
<p>In the vast landscape of software development, writing code is not just about instructing a computer to perform a task; it's about crafting a language that communicates with fellow developers, both present and future. Clean code is the art of writing code that is not only functional but also elegant, efficient, and understandable to others.</p>
<p>Imagine a coach flipping through a playbook where each play is neatly arranged, labeled, and easily accessible. This organized playbook is not just a collection of random strategies but a carefully curated guide to success on the field. With every play clearly defined and structured, the team can execute with precision, knowing exactly what to do in any situation.</p>
<p>In the realm of software development, clean code serves as the playbook for developers. Each line of code is akin to a play in the playbook—purposeful, structured, and easily understandable. When the code base is clean and well-organized, developers can navigate through it seamlessly, making changes and enhancements with confidence.</p>
<p>In this blog, we embark on a journey into the realm of clean code, exploring its principles, practices, and significance in modern software development. Whether you're a seasoned developer looking to refine your craft or a newcomer eager to learn the ropes, join us as we delve into the art of writing code that not only works but also stands the test of time. Let's elevate our programming practices and strive for cleaner, more elegant solutions that not only solve problems but also inspire and empower others.</p>
<hr />
<h1 id="heading-what-is-clean-code">What is clean code?</h1>
<p>Clean code refers to source code that is well-organized, easy to read, and easy to understand. It emphasizes clarity and simplicity, making it easier for developers to maintain, modify, and debug. Clean code is not just about functionality; it's about writing code in a way that minimizes complexity and maximizes readability.</p>
<p>Clean code is not just about whether code works; it's primarily about whether it's easy to read and understand. As developers, we spend a significant amount of time reading and understanding code, whether it's our own past code or code written by colleagues. Clean code prioritizes readability and comprehension to enhance productivity and prevent loss of time. It's crucial for maintaining code bases over time and ensuring their longevity. There's no one-size-fits-all solution for writing clean code, but it's essential for effective software development.</p>
<hr />
<h1 id="heading-why-is-clean-code-important">Why is clean code important?</h1>
<ul>
<li><p><strong>Readability and Maintainability:-</strong></p>
<p>  Clean code is easier to read and understand, reducing the time and effort required to maintain and modify it. This leads to faster bug fixes, easier feature additions, and smoother code reviews.</p>
</li>
<li><p><strong>Reduced Technical Debt:-</strong></p>
<p>  Technical debt accumulates when shortcuts are taken or code quality is compromised in favor of quick fixes or tight deadlines. Clean code reduces technical debt by prioritizing long-term maintainability and reducing the cost of future changes.</p>
</li>
<li><p><strong>Enhanced Collaboration:-</strong></p>
<p>  Clean code improves collaboration among developers by providing a common understanding of how the code works and where to find specific functionality. It also reduces the risk of miscommunication and misunderstandings between team members.</p>
</li>
<li><p><strong>Improved Productivity:-</strong></p>
<p>  Developers spend a significant portion of their time reading and understanding code. Clean code reduces cognitive overhead and makes developers more productive by allowing them to focus on solving problems rather than deciphering complex code.</p>
</li>
<li><p><strong>Better Quality Software:-</strong></p>
<p>  Clean code results in better quality software that is more reliable, easier to test, and less prone to bugs and errors. This leads to higher customer satisfaction and a better overall user experience.</p>
</li>
</ul>
<p>In summary, clean code is essential for building maintainable, scalable, and high-quality software applications. It improves readability, reduces technical debt, enhances collaboration, boosts productivity, and ultimately leads to better software outcomes for both developers and end-users.</p>
<hr />
<h1 id="heading-properties-of-clean-code">Properties of clean code</h1>
<ul>
<li><p><strong>Readable and Meaningful:-</strong></p>
<p>  Clean code should be easy to understand for other developers who might work on it in the future. This means using descriptive names for variables, functions, and classes, as well as writing clear and concise comments where necessary.</p>
</li>
<li><p><strong>Reduces Cognitive Load:-</strong></p>
<p>  Clean code minimizes the mental effort required to understand it. This involves breaking down complex tasks into smaller, more manageable components and organizing the code in a logical manner.</p>
</li>
<li><p><strong>Concise and "To the Point":-</strong></p>
<p>  Clean code gets straight to the point without unnecessary complexity or verbosity. It eliminates redundant or superfluous code, keeping only what is essential for the functionality.</p>
</li>
<li><p><strong>Avoids Unintuitive Names, Complex Nesting, and Big Code Blocks:-</strong></p>
<p>  Clean code uses meaningful and intuitive names for variables, functions, and classes, making it easier to understand their purpose and usage. It also avoids deep nesting of control structures and large code blocks, which can make code harder to follow and maintain.</p>
</li>
<li><p><strong>Follows Common Best Practices and Patterns:-</strong></p>
<p>  Clean code adheres to established best practices and design patterns in software development. This includes principles like DRY (Don't Repeat Yourself), SOLID, and others that promote modular, reusable, and maintainable code.</p>
</li>
<li><p><strong>Well-Tested:-</strong></p>
<p>  Clean code is thoroughly tested to ensure its correctness and robustness. This involves writing unit tests, integration tests, and other forms of automated testing to validate the code's behavior under various conditions.</p>
</li>
<li><p><strong>Documented When Necessary:-</strong></p>
<p>  Clean code includes appropriate documentation to explain its purpose, usage, and any important considerations for developers working with it. This documentation should be clear, concise, and kept up-to-date as the code evolves.</p>
</li>
<li><p><strong>Consistent Formatting and Style:-</strong></p>
<p>  Clean code follows a consistent formatting and coding style throughout the code-base. This includes aspects such as indentation, spacing, naming conventions, and so on, which help improve readability and maintainability.</p>
</li>
<li><p><strong>Performance Considerations:-</strong></p>
<p>  While clean code prioritizes readability and maintainability, it also takes performance into account where necessary. This involves optimizing critical sections of code, avoiding unnecessary overhead, and considering factors like memory usage and algorithmic efficiency.</p>
</li>
<li><p><strong>Fun to Write and Maintain:-</strong></p>
<p>  Clean code is enjoyable to work with for developers. It's satisfying to write code that is elegant, efficient, and easy to understand, and it's less stressful to maintain code that is well-organized and documented.</p>
</li>
</ul>
<p>By adhering to these principles, developers can produce code that is not only functional but also easy to understand, modify, and extend over time.</p>
<hr />
<h1 id="heading-things-to-be-considered">Things to be considered</h1>
<h2 id="heading-rules-and-concepts">Rules and concepts</h2>
<ul>
<li><h3 id="heading-dry-dont-repeat-yourself"><strong>DRY (Don't Repeat Yourself):-</strong></h3>
<p>  This principle emphasizes the avoidance of duplicating code. Duplicated code increases the risk of inconsistencies and makes maintenance more difficult. Instead, reusable code should be encapsulated into functions, classes, or modules.</p>
</li>
<li><h3 id="heading-kiss-keep-it-simple-stupid"><strong>KISS (Keep It Simple, Stupid):-</strong></h3>
<p>  This principle advocates for simplicity in design and implementation. Complex solutions can lead to confusion and bugs, while simpler solutions are easier to understand, debug, and maintain.</p>
</li>
<li><h3 id="heading-yagni-you-aint-gonna-need-it"><strong>YAGNI (You Ain't Gonna Need It):-</strong></h3>
<p>  This principle discourages adding functionality that is not currently needed. Speculative features can bloat the codebase, increase complexity, and introduce unnecessary dependencies. Only implement features that are required by the current requirements.</p>
</li>
</ul>
<h2 id="heading-patterns-amp-principles">Patterns &amp; Principles</h2>
<ul>
<li><h3 id="heading-design-patterns"><strong>Design Patterns:-</strong></h3>
<p>  Design patterns are reusable solutions to common problems in software design. Examples include the Singleton pattern, Factory pattern, Observer pattern, etc. These patterns provide proven solutions to recurring design challenges and promote clean, maintainable code.</p>
</li>
<li><h3 id="heading-solid-principles">SOLID Principles:-</h3>
<ul>
<li><p><strong>S</strong> - Single Responsibility Principle</p>
</li>
<li><p><strong>O</strong> - Open/Closed Principle</p>
</li>
<li><p><strong>L</strong> - Liskov Substitution Principle</p>
</li>
<li><p><strong>I</strong> - Interface Segregation Principle</p>
</li>
<li><p><strong>D</strong> - Dependency Inversion Principle</p>
</li>
</ul>
</li>
</ul>
<p>    These principles form the foundation of object-oriented design and promote modular, flexible, and maintainable code.</p>
<h2 id="heading-test-driven-development-tdd">Test-Driven Development (TDD)</h2>
<p>Test-Driven Development is a development approach where tests are written before the code implementation. This follows a cycle of:</p>
<ol>
<li><p><strong>Write a Test</strong>: First, write a test that specifies a desired behavior or feature.</p>
</li>
<li><p><strong>Write the Code</strong>: Implement the code necessary to make the test pass.</p>
</li>
<li><p><strong>Run the Tests</strong>: Execute all tests to ensure the new code did not break existing functionality.</p>
</li>
<li><p><strong>Refactor</strong>: Once the tests pass, refactor the code to improve its structure, readability, and performance while keeping the tests passing.</p>
</li>
</ol>
<p>TDD promotes clean code by ensuring that code is thoroughly tested and that new features are added incrementally while maintaining existing functionality.</p>
<h2 id="heading-paradigm-specific-considerations">Paradigm-specific Considerations</h2>
<ul>
<li><h3 id="heading-functional-programming"><strong>Functional Programming:-</strong></h3>
<p>  Emphasizes immutability, pure functions, and higher-order functions. This paradigm encourages a declarative style of programming, which can lead to cleaner, more concise code with fewer side effects.</p>
</li>
<li><h3 id="heading-object-oriented-programming"><strong>Object-Oriented Programming:-</strong></h3>
<p>  Focuses on encapsulating behavior and state within objects. Principles like encapsulation, inheritance, and polymorphism help promote modular design and code reuse.</p>
</li>
<li><h3 id="heading-procedural-programming"><strong>Procedural Programming:-</strong></h3>
<p>  Prioritizes procedures or functions that perform operations on data. While not as modular as OOP or as declarative as FP, procedural code can still be kept clean by adhering to principles like DRY and KISS, and by organizing code into cohesive functions or modules.</p>
</li>
</ul>
<p>Continuous improvement and refactoring are indispensable practices in our journey towards maintaining a robust and sustainable codebase. While we strive to craft exemplary code from the outset, the iterative nature of software development means that opportunities for enhancement will inevitably arise as our projects evolve. By embracing the ethos that "Refactoring today is the work we save tomorrow," we acknowledge the value of investing time and effort into improving code quality upfront, leading to long-term benefits such as reduced technical debt, increased agility, and enhanced developer productivity.</p>
<p>As a team, we recognize that integrating refactoring into our development workflow is essential for addressing shortcomings and inefficiencies as they emerge, rather than allowing them to accumulate and impede progress. This proactive approach fosters a culture of craftsmanship and quality within our team, promoting collaboration, innovation, and a shared commitment to excellence in software engineering practices.</p>
<p>By continuously refining and optimizing our code, we can mitigate the accumulation of complexity, eliminate redundancy, and adapt more effectively to changing requirements and technological advancements. Through this iterative process of improvement, we not only ensure the resilience and longevity of our software projects but also position ourselves for sustained innovation, competitive advantage, and customer satisfaction in an ever-evolving technological landscape.</p>
<hr />
<h1 id="heading-naming">Naming</h1>
<p>Click <a target="_blank" href="https://blog.saurabhmahajan.com/clean-code-part-1-naming"><em>here</em></a></p>
<hr />
<h1 id="heading-comments">Comments</h1>
<p>Click <a target="_blank" href="https://blog.saurabhmahajan.com/clean-code-part-2-comments"><em>here</em></a></p>
<hr />
<h1 id="heading-code-formatting">Code Formatting</h1>
<p>Click <a target="_blank" href="https://blog.saurabhmahajan.com/clean-code-part-3-code-formatting"><em>here</em></a></p>
<hr />
<h1 id="heading-functionsmethods">Functions/Methods</h1>
<p>Click <a target="_blank" href="https://blog.saurabhmahajan.com/clean-code-part-4-functionsmethods"><em>here</em></a></p>
<hr />
<h1 id="heading-control-structure-amp-errors">Control Structure &amp; Errors</h1>
<p>Click <a target="_blank" href="https://blog.saurabhmahajan.com/clean-code-part-5-control-structure-errors"><em>here</em></a></p>
<hr />
<h1 id="heading-classes-objects-and-data-containers">Classes, Objects and Data Containers</h1>
<p>Click <a target="_blank" href="https://blog.saurabhmahajan.com/clean-code-part-6-classes-objects-data-containers"><em>here</em></a></p>
<hr />
<h1 id="heading-key-takeaways">Key Takeaways</h1>
<h2 id="heading-1-naming"><strong>1. Naming:</strong></h2>
<ul>
<li><p>Descriptive names: Use nouns for variables and properties, and verbs for methods.</p>
</li>
<li><p>Specificity: Be as specific as possible without being redundant.</p>
</li>
<li><p>Consistency: Avoid slang, unknown abbreviations, and maintain consistency in naming conventions.</p>
</li>
<li><p>Clarity: Make names easy to read and understand by humans.</p>
</li>
</ul>
<h2 id="heading-2-comments-and-formatting"><strong>2. Comments and Formatting:</strong></h2>
<ul>
<li><p>Minimal comments: Most comments are discouraged; only include necessary comments like legal information, warnings, or explanations.</p>
</li>
<li><p>Vertical formatting: Keep related concepts together and separate unrelated ones using blank lines and line breaks.</p>
</li>
<li><p>Horizontal formatting: Keep lines short, use indentation, and split code across multiple lines for readability.</p>
</li>
<li><p>IDE assistance: Utilize auto-formatting tools and IDE features to aid in writing clean code.</p>
</li>
</ul>
<h2 id="heading-3-functions"><strong>3. Functions:</strong></h2>
<ul>
<li><p>Parameters: Limit the number of parameters and consider grouping them into dictionaries or objects for clarity.</p>
</li>
<li><p>Function body: Keep functions small and focused on a single task to maintain clarity and avoid repetition.</p>
</li>
<li><p>Abstraction levels: Ensure consistency between the level of abstraction implied by the function name and its implementation.</p>
</li>
<li><p>DRY principle: Avoid repeating code and strive for reusability.</p>
</li>
<li><p>Side effects: Minimize unexpected side effects to enhance code readability.</p>
</li>
</ul>
<h2 id="heading-4-control-structures"><strong>4. Control Structures:</strong></h2>
<ul>
<li><p>Positive wording: Use positive language in control structures for clarity.</p>
</li>
<li><p>Avoid deep nesting: Utilize guard clauses and extract logic into separate functions to prevent deep nesting.</p>
</li>
<li><p>Polymorphism and factory functions: Reduce code duplication by employing polymorphism and factory functions.</p>
</li>
<li><p>Error handling: Use real errors instead of synthetic errors to improve code clarity.</p>
</li>
</ul>
<h2 id="heading-5-objects-and-classes"><strong>5. Objects and Classes:</strong></h2>
<ul>
<li><p>Differentiation: Distinguish between real objects with methods and data structures that only hold data.</p>
</li>
<li><p>Class size: Keep classes small by focusing on a single responsibility.</p>
</li>
<li><p>Law of Demeter: Avoid diving too deeply into object hierarchies to maintain code clarity.</p>
</li>
<li><p>SOLID principles: Follow principles like SRP and OCP to enhance maintainability and improve code readability.</p>
</li>
</ul>
<p>Clean code prioritizes human readability and understanding over mere functionality. By following guidelines for naming, comments, formatting, functions, control structures, and objects/classes, developers can ensure their code is clear, concise, and maintainable. Consistency, clarity, and simplicity are key principles that should guide the writing and organization of code, ultimately leading to better collaboration, easier debugging, and enhanced software quality.</p>
<hr />
<h1 id="heading-conclusion">Conclusion</h1>
<p>In conclusion, the pursuit of clean code transcends the mere execution of programming tasks; it is an art form, a philosophy, and a commitment to excellence in software development. Throughout this discussion, we have delved into the intricacies of various aspects that constitute clean code, ranging from naming conventions to the principles of object-oriented programming. At its core, clean code is about prioritizing the human experience of reading and understanding code over mere functionality.</p>
<p>Through meticulous naming, minimal yet purposeful comments, and thoughtful formatting, developers create code that is not only functional but also comprehensible to others. By adhering to principles such as modular function design, clear control structures, and object-oriented best practices, clean code fosters readability, simplicity, and maintainability.</p>
<p>In essence, clean code is not merely a set of rules or guidelines; it is a mindset—a commitment to craftsmanship and excellence in software development. As we continue to evolve in our understanding and practice of clean code, let us remain steadfast in our dedication to writing code that not only speaks to machines but also resonates with our fellow humans. For in the end, clean code is not just about computers; it's about people.</p>
]]></content:encoded></item><item><title><![CDATA[Clean Code - Part-6: Classes, Objects & Data Containers]]></title><description><![CDATA[Imagine classes as specialized tools in a toolkit, each serving a specific purpose. Just like you wouldn't use a hammer to tighten a screw, avoid bloating classes with unrelated functionalities. Instead, keep them focused and concise, adhering to the...]]></description><link>https://blog.saurabhmahajan.com/clean-code-part-6-classes-objects-data-containers</link><guid isPermaLink="true">https://blog.saurabhmahajan.com/clean-code-part-6-classes-objects-data-containers</guid><category><![CDATA[code]]></category><category><![CDATA[coding]]></category><category><![CDATA[clean code]]></category><category><![CDATA[classes]]></category><category><![CDATA[Objects]]></category><category><![CDATA[containers]]></category><dc:creator><![CDATA[Saurabh Mahajan]]></dc:creator><pubDate>Mon, 20 Jan 2025 16:11:01 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1737387886979/8bd2e0fa-b6d0-44f2-91d0-83e1bc0f76da.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Imagine classes as specialized tools in a toolkit, each serving a specific purpose. Just like you wouldn't use a hammer to tighten a screw, avoid bloating classes with unrelated functionalities. Instead, keep them focused and concise, adhering to the Single Responsibility Principle (SRP). This ensures that each class does one thing and does it well, making your code cleaner and easier to understand.</p>
<p>Similarly, think of data containers as organized compartments to store your tools. Whether it's a simple list or a custom class, choose the appropriate container based on the complexity and structure of your data. This helps in maintaining data integrity and improves code readability.</p>
<p><strong>Tell, Don't Ask Principle:</strong> This principle suggests that instead of asking an object for its state and then making decisions based on that state, we should tell the object to do something. For example, instead of asking a <code>Car</code> object for its speed and then deciding whether to accelerate, we should simply tell the <code>Car</code> to accelerate.</p>
<p>Example:</p>
<pre><code class="lang-python"><span class="hljs-comment"># Example of a class adhering to SRP</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserManager</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">authenticate</span>(<span class="hljs-params">self, username, password</span>):</span>
        <span class="hljs-comment"># Authentication logic</span>
        <span class="hljs-keyword">pass</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">updateUserProfile</span>(<span class="hljs-params">self, user_id, new_data</span>):</span>
        <span class="hljs-comment"># Profile update logic</span>
        <span class="hljs-keyword">pass</span>

<span class="hljs-comment"># Example of a data container</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Customer</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, name, email</span>):</span>
        self.name = name
        self.email = email

<span class="hljs-comment"># Usage</span>
user_manager = UserManager()
customer = Customer(<span class="hljs-string">"John Doe"</span>, <span class="hljs-string">"john@example.com"</span>)
</code></pre>
<hr />
<h1 id="heading-cohesion">Cohesion</h1>
<h4 id="heading-maximum-cohesion">Maximum Cohesion:</h4>
<p>High cohesion means that all methods within a class are closely related and work together to achieve a common goal. This leads to more readable and maintainable code.</p>
<p><strong>Example:</strong> In a <code>BankAccount</code> class, methods like <code>deposit</code>, <code>withdraw</code>, and <code>getBalance</code> all directly relate to managing the bank account's balance and transactions.</p>
<h4 id="heading-no-cohesion">No Cohesion:</h4>
<p>Low or no cohesion occurs when methods in a class are unrelated or don't work together towards a common purpose. This often indicates poor design and can make the code harder to understand and maintain.</p>
<p><strong>Example:</strong> A <code>Utilities</code> class with methods like <code>sortArray</code> and <code>calculateAverage</code>, which don't relate to each other or any specific entity.</p>
<p>Strive for high cohesion in your classes, where every method collaborates harmoniously towards a common goal. This is like having a well-orchestrated team, where each member knows their role and works seamlessly with others. By maximizing cohesion, you create classes that are focused, understandable, and easy to maintain.</p>
<p>Conversely, avoid creating classes with low or no cohesion, resembling a group of individuals with no shared purpose. This leads to confusion and complexity in your codebase. Instead, aim for classes where every method contributes meaningfully to the overall functionality, promoting clarity and cleanliness.</p>
<p>Example:</p>
<pre><code class="lang-python"><span class="hljs-comment"># High cohesion example</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Calculator</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">add</span>(<span class="hljs-params">self, x, y</span>):</span>
        <span class="hljs-keyword">return</span> x + y

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">subtract</span>(<span class="hljs-params">self, x, y</span>):</span>
        <span class="hljs-keyword">return</span> x - y

<span class="hljs-comment"># Low cohesion example</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Utilities</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">sortArray</span>(<span class="hljs-params">self, arr</span>):</span>
        <span class="hljs-comment"># Sorting logic</span>
        <span class="hljs-keyword">pass</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">calculateAverage</span>(<span class="hljs-params">self, arr</span>):</span>
        <span class="hljs-comment"># Average calculation logic</span>
        <span class="hljs-keyword">pass</span>

<span class="hljs-comment"># Usage</span>
calculator = Calculator()
result = calculator.add(<span class="hljs-number">5</span>, <span class="hljs-number">3</span>)
</code></pre>
<hr />
<h1 id="heading-law-of-demeter">Law of Demeter</h1>
<p>The Law of Demeter, also known as the principle of least knowledge, states that a module should not know about the internal workings of the objects it manipulates. Instead, it should only interact with its immediate friends (its own attributes, parameters passed to the method, objects it creates, or global variables).</p>
<p>Embrace the Law of Demeter as your guiding principle when interacting with objects. Just like maintaining professional boundaries, ensure that your modules only communicate with their immediate 'friends' and avoid delving into unnecessary details. By following this principle, you foster modularity and encapsulation, resulting in code that is less prone to unexpected changes and easier to maintain.</p>
<p>Remember, clean code is not just about achieving functionality; it's about creating code that is intuitive, organized, and easy to modify. By incorporating these principles into your coding practices, you not only write cleaner code but also empower yourself and your team to build robust and scalable software solutions.</p>
<p>Example:</p>
<pre><code class="lang-python"><span class="hljs-comment"># Without adhering to the Law of Demeter</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Customer</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, name, address</span>):</span>
        self.name = name
        self.address = address

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">getAddress</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">return</span> self.address

<span class="hljs-comment"># Usage</span>
customer = Customer(<span class="hljs-string">"John Doe"</span>, <span class="hljs-string">"123 Main St"</span>)
street = customer.getAddress().split(<span class="hljs-string">','</span>)[<span class="hljs-number">0</span>]  <span class="hljs-comment"># Directly accessing internal state</span>

<span class="hljs-comment"># Adhering to the Law of Demeter</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Customer</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, name, address</span>):</span>
        self.name = name
        self.address = address

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">getStreet</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">return</span> self.address.split(<span class="hljs-string">','</span>)[<span class="hljs-number">0</span>]

<span class="hljs-comment"># Usage</span>
customer = Customer(<span class="hljs-string">"John Doe"</span>, <span class="hljs-string">"123 Main St"</span>)
street = customer.getStreet()  <span class="hljs-comment"># Indirectly accessing internal state</span>
</code></pre>
<p>In conclusion, writing clean code is not just a matter of syntax and formatting; it's a mindset that values simplicity, clarity, and maintainability. By embracing principles such as Single Responsibility, Polymorphism, Maximum Cohesion, and the Law of Demeter, developers can elevate their code to a higher standard.</p>
<p>Encouraging users to adopt these principles fosters a culture of clean coding practices within their projects. It empowers developers to create classes that are focused, data containers that are well-organized, and interactions between modules that are cohesive and respectful of boundaries.</p>
<hr />
<h1 id="heading-solid-principles">SOLID Principles</h1>
<p>The SOLID principles are a set of five design principles that help developers create more maintainable, flexible, and scalable software systems. Each principle focuses on a different aspect of object-oriented design:</p>
<ol>
<li><p><strong>Single Responsibility Principle (SRP):</strong> This principle states that a class should have only one reason to change, meaning it should have only one responsibility or job. By adhering to SRP, classes become more focused, easier to understand, and less prone to unexpected changes.</p>
</li>
<li><p><strong>Open/Closed Principle (OCP):</strong> The Open/Closed Principle suggests that software entities (classes, modules, functions, etc.) should be open for extension but closed for modification. This means that the behavior of a module can be extended without modifying its source code, promoting code reuse and minimizing the risk of introducing bugs in existing code.</p>
</li>
<li><p><strong>Liskov Substitution Principle (LSP):</strong> LSP states that objects of a superclass should be replaceable with objects of its subclasses without affecting the correctness of the program. In other words, derived classes should be substitutable for their base classes without altering the desired properties of the program.</p>
</li>
<li><p><strong>Interface Segregation Principle (ISP):</strong> ISP suggests that clients should not be forced to depend on interfaces they do not use. Instead of implementing large, monolithic interfaces, it's better to break them into smaller, more specific interfaces. This promotes loose coupling and allows clients to depend only on the functionality they need.</p>
</li>
<li><p><strong>Dependency Inversion Principle (DIP):</strong> DIP advocates for high-level modules to not depend on low-level modules, but rather both should depend on abstractions. Furthermore, it suggests that abstractions should not depend on details; instead, details should depend on abstractions. By decoupling high-level and low-level modules, DIP increases flexibility, maintainability, and testability of the codebase.</p>
</li>
</ol>
<p><em>Find more details</em> <a target="_blank" href="https://blog.saurabhmahajan.com/solid-principles-the-practical-guide"><em>here</em></a></p>
]]></content:encoded></item><item><title><![CDATA[Clean Code - Part-5: Control Structure & Errors]]></title><description><![CDATA[In this section, we'll delve into essential strategies for code refinement, including avoiding deep nesting, preferring positive checks, utilizing errors, leveraging factory functions and polymorphism, and modularizing code. By understanding and appl...]]></description><link>https://blog.saurabhmahajan.com/clean-code-part-5-control-structure-errors</link><guid isPermaLink="true">https://blog.saurabhmahajan.com/clean-code-part-5-control-structure-errors</guid><category><![CDATA[code]]></category><category><![CDATA[coding]]></category><category><![CDATA[clean code]]></category><category><![CDATA[errors]]></category><dc:creator><![CDATA[Saurabh Mahajan]]></dc:creator><pubDate>Mon, 20 Jan 2025 16:10:16 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1737387875210/cff95f63-6180-461f-8d7a-3292d68af22e.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this section, we'll delve into essential strategies for code refinement, including avoiding deep nesting, preferring positive checks, utilizing errors, leveraging factory functions and polymorphism, and modularizing code. By understanding and applying these principles, developers can enhance code readability, reduce complexity, and facilitate future maintenance and scalability.</p>
<hr />
<h1 id="heading-avoid-deep-nesting">Avoid Deep Nesting</h1>
<p>Deeply nested code can be challenging to read, understand, and maintain. To mitigate this issue, it's advisable to use guards and fail-fast mechanisms. Guards are conditions placed at the beginning of a function or block of code to check for invalid inputs or conditions. If these conditions are met, the function exits early or raises an error. This approach helps reduce the level of nesting and improves code readability.</p>
<p><strong>Example with Guards:</strong></p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">calculate_total_price</span>(<span class="hljs-params">items</span>):</span>
    <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> items:
        <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>  <span class="hljs-comment"># Guard clause to handle empty list</span>

    total_price = <span class="hljs-number">0</span>
    <span class="hljs-keyword">for</span> item <span class="hljs-keyword">in</span> items:
        <span class="hljs-keyword">if</span> item[<span class="hljs-string">'price'</span>] &lt;= <span class="hljs-number">0</span>:
            <span class="hljs-keyword">continue</span>  <span class="hljs-comment"># Guard clause to skip items with non-positive price</span>
        total_price += item[<span class="hljs-string">'price'</span>]
    <span class="hljs-keyword">return</span> total_price
</code></pre>
<p>In this example, the guard clause <code>if not items</code> checks if the list of items is empty, exiting the function early if it is. Inside the loop, another guard clause <code>if item['price'] &lt;= 0</code> skips items with non-positive prices, reducing the nesting level.</p>
<hr />
<h1 id="heading-prefer-positive-checks">Prefer Positive Checks</h1>
<p>Positive checks are generally easier to understand than negative ones because they express what is expected rather than what is not. It's recommended to extract control structures into functions with positive phrasing to improve code readability. Additionally, using clean function rules and inverting conditional logic can further enhance code clarity.</p>
<p><strong>Example with Positive Check:</strong></p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">is_valid_age</span>(<span class="hljs-params">age</span>):</span>
    <span class="hljs-keyword">return</span> age &gt;= <span class="hljs-number">18</span>  <span class="hljs-comment"># Positive check for age validity</span>

<span class="hljs-keyword">if</span> is_valid_age(user[<span class="hljs-string">'age'</span>]):
    print(<span class="hljs-string">"User is an adult."</span>)
</code></pre>
<p>In this example, the function <code>is_valid_age</code> performs a positive check to determine if the given age is valid (&gt;= 18), making the code more straightforward and self-explanatory.</p>
<hr />
<h1 id="heading-utilize-errors">Utilize Errors</h1>
<p>Throwing and handling errors can be an effective alternative to complex if statements, leading to more focused and readable functions. Utilizing try-catch blocks to handle errors gracefully and creating error guards to catch potential issues early in the code can greatly improve code robustness and maintainability.</p>
<p><strong>Example with Error Handling:</strong></p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">divide</span>(<span class="hljs-params">x, y</span>):</span>
    <span class="hljs-keyword">if</span> y == <span class="hljs-number">0</span>:
        <span class="hljs-keyword">raise</span> ValueError(<span class="hljs-string">"Cannot divide by zero"</span>)
    <span class="hljs-keyword">return</span> x / y

<span class="hljs-keyword">try</span>:
    result = divide(<span class="hljs-number">10</span>, <span class="hljs-number">0</span>)
<span class="hljs-keyword">except</span> ValueError <span class="hljs-keyword">as</span> e:
    print(<span class="hljs-string">"Error:"</span>, e)
</code></pre>
<p>Here, the <code>divide</code> function throws a <code>ValueError</code> if the divisor is zero, and this error is caught and handled using a try-except block, providing a clear indication of what went wrong.</p>
<hr />
<h1 id="heading-use-factory-functions-amp-polymorphism">Use Factory Functions &amp; Polymorphism</h1>
<p>Factory functions can dynamically create objects or functions based on input parameters, contributing to cleaner control structures. By embracing polymorphism, methods with the same name can exhibit different behaviors based on input parameters, promoting modularity and extensibility.</p>
<p><strong>Example with Factory Function:</strong></p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">create_operation</span>(<span class="hljs-params">type</span>):</span>
    <span class="hljs-keyword">if</span> type == <span class="hljs-string">'add'</span>:
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">lambda</span> x, y: x + y
    <span class="hljs-keyword">elif</span> type == <span class="hljs-string">'subtract'</span>:
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">lambda</span> x, y: x - y

add_operation = create_operation(<span class="hljs-string">'add'</span>)
subtract_operation = create_operation(<span class="hljs-string">'subtract'</span>)

result1 = add_operation(<span class="hljs-number">5</span>, <span class="hljs-number">3</span>)
result2 = subtract_operation(<span class="hljs-number">5</span>, <span class="hljs-number">3</span>)
</code></pre>
<p>In this example, the <code>create_operation</code> factory function dynamically creates different operations (addition or subtraction) based on the input type, enhancing code modularity and readability.</p>
<hr />
<h1 id="heading-modularize-code">Modularize Code</h1>
<p>Modularizing code involves organizing related functions into separate files or modules, promoting better code organization and maintainability. By grouping functions logically and importing them as needed, you can create a cleaner and more manageable codebase.</p>
<p><strong>Example of Modularization:</strong></p>
<pre><code class="lang-python"><span class="hljs-comment"># File: math_operations.py</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">add</span>(<span class="hljs-params">x, y</span>):</span>
    <span class="hljs-keyword">return</span> x + y

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">subtract</span>(<span class="hljs-params">x, y</span>):</span>
    <span class="hljs-keyword">return</span> x - y

<span class="hljs-comment"># File: main.py</span>
<span class="hljs-keyword">import</span> math_operations

result1 = math_operations.add(<span class="hljs-number">5</span>, <span class="hljs-number">3</span>)
result2 = math_operations.subtract(<span class="hljs-number">5</span>, <span class="hljs-number">3</span>)
</code></pre>
<p>Here, the math operations are modularized into a separate module (<code>math_</code><a target="_blank" href="http://operations.py"><code>operations.py</code></a>), which is then imported into the main file (<a target="_blank" href="http://main.py"><code>main.py</code></a>), enhancing code organization and readability.</p>
<hr />
<h1 id="heading-summary">Summary</h1>
<p>In conclusion, mastering control structures and error handling techniques is essential for writing clean, maintainable, and scalable code. By applying the principles outlined in this guide—avoiding deep nesting, preferring positive checks, utilizing errors, leveraging factory functions and polymorphism, and modularizing code—developers can enhance code readability, reduce complexity, and future-proof their applications. With a commitment to smart coding practices and continuous improvement, developers can unlock the full potential of their software projects and deliver exceptional value to their users and stakeholders.</p>
]]></content:encoded></item><item><title><![CDATA[Clean Code - Part-4: Functions/Methods]]></title><description><![CDATA[In the realm of clean code, it's crucial that both the call to a function and its definition are clear and easy to understand. When invoking a function, readability is key, including clear argument orders. Equally important is the ease of working wit...]]></description><link>https://blog.saurabhmahajan.com/clean-code-part-4-functionsmethods</link><guid isPermaLink="true">https://blog.saurabhmahajan.com/clean-code-part-4-functionsmethods</guid><category><![CDATA[code]]></category><category><![CDATA[coding]]></category><category><![CDATA[clean code]]></category><category><![CDATA[functions]]></category><category><![CDATA[Methods]]></category><dc:creator><![CDATA[Saurabh Mahajan]]></dc:creator><pubDate>Mon, 20 Jan 2025 16:09:02 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1737387861656/9990eaf6-930a-4aac-ae28-b7e5a9354243.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In the realm of clean code, it's crucial that both the call to a function and its definition are clear and easy to understand. When invoking a function, readability is key, including clear argument orders. Equally important is the ease of working within the function itself, whether it's writing new code or maintaining existing functions. Therefore, the number and order of arguments play a significant role in how readable and manageable a function is to use. Additionally, the length of the function body matters, as it affects the complexity of understanding and maintaining the code within.</p>
<hr />
<h1 id="heading-calling-a-function">Calling a function</h1>
<p>Let's delve into a more comprehensive explanation of the principles and practices surrounding function parameters in the context of writing clean and maintainable code.</p>
<h3 id="heading-consideration-of-parameters">Consideration of parameters</h3>
<p>Parameters are the inputs that functions accept to perform their tasks. When designing functions, the number and order of parameters play a pivotal role in their usability and readability.</p>
<p>Minimizing the number of parameters is a cardinal rule in clean code practices. Reducing parameter count simplifies the function interface, making it easier to understand and use. Developers are less likely to make mistakes when calling functions with fewer parameters, as there's less cognitive overhead in remembering their order and purpose.</p>
<h3 id="heading-refactoring-with-objects">Refactoring with objects</h3>
<p>One effective technique for reducing parameter count is to bundle related parameters into an object. By encapsulating parameters within an object, you create a cohesive data structure that represents the inputs to the function. This approach improves readability by providing a clear and self-descriptive interface for invoking the function.</p>
<p>Let's consider a practical example to illustrate this concept. Suppose you have a logging function that logs messages, along with an optional flag indicating whether the message is an error. Initially, you might define the function with separate parameters for the message and error flag:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">log</span>(<span class="hljs-params">message, is_error=False</span>):</span>
    <span class="hljs-keyword">if</span> is_error:
        print(<span class="hljs-string">f"Error: <span class="hljs-subst">{message}</span>"</span>)
    <span class="hljs-keyword">else</span>:
        print(message)
</code></pre>
<p>However, as the function evolves and additional parameters are introduced, the function call becomes less intuitive and more error-prone.</p>
<p>To address this, you can refactor the function to accept a single parameter—an object representing the logging options:</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">LogOptions</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, message, is_error=False</span>):</span>
        self.message = message
        self.is_error = is_error

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">log</span>(<span class="hljs-params">options</span>):</span>
    <span class="hljs-keyword">if</span> options.is_error:
        print(<span class="hljs-string">f"Error: <span class="hljs-subst">{options.message}</span>"</span>)
    <span class="hljs-keyword">else</span>:
        print(options.message)
</code></pre>
<p>With this refactoring, calling the <code>log</code> function becomes more expressive and readable:</p>
<pre><code class="lang-python">log(LogOptions(<span class="hljs-string">"hi"</span>, is_error=<span class="hljs-literal">False</span>))
</code></pre>
<p>While this technique aligns particularly well with functional programming principles, where functions often operate on single data structures, it's also applicable in object-oriented programming. By adopting this approach, you create cleaner and more maintainable code that adheres to the principles of encapsulation and separation of concerns.</p>
<h3 id="heading-exceptions">Exceptions</h3>
<p>It's important to note that there are exceptions to the guideline of minimizing parameter count. Functions that accept a dynamic number of arguments, such as Python's <code>*args</code> and <code>**kwargs</code>, may have a larger parameter count by necessity.</p>
<h3 id="heading-naming">Naming</h3>
<p>Lastly, when naming functions and their parameters, prioritize clarity and descriptiveness. Meaningful names enhance the readability of the codebase, making it easier for developers to understand and maintain.</p>
<p>In conclusion, by carefully considering the number and order of function parameters and leveraging techniques such as parameter bundling with objects, developers can write cleaner, more readable, and maintainable code. These practices ultimately contribute to the long-term sustainability and scalability of software projects.</p>
<hr />
<h1 id="heading-writing-a-function-body">Writing a function body</h1>
<p>In software development, the length of a function's body has a profound effect on code quality and maintainability. Long, complex functions tend to obscure the logic, making it difficult for developers to grasp the overall flow and purpose. On the other hand, breaking down functions into smaller, focused units of work enhances readability, promotes code reuse, and facilitates easier debugging and testing.</p>
<h3 id="heading-single-long-body-vs-distributed-responsibilities">Single Long Body vs. Distributed Responsibilities</h3>
<p><strong>Bad Example:</strong> A single long body function encapsulates multiple tasks within its structure, leading to a tangled web of logic that's challenging to comprehend at a glance. This monolithic structure intertwines various tasks, making it challenging to understand and modify.</p>
<p><strong>Good Example:</strong> Distributing responsibilities across multiple smaller functions results in a more modular and readable codebase. Each function focuses on a single task, making it easier to understand and modify.</p>
<h3 id="heading-pros-of-distributing-responsibilities">Pros of Distributing Responsibilities</h3>
<ol>
<li><p><strong>Modularity:</strong> Breaking down functions into smaller units promotes modularity, allowing developers to understand and modify individual components without impacting the entire codebase.</p>
</li>
<li><p><strong>Readability:</strong> Smaller functions are easier to read and comprehend, as they focus on specific tasks and maintain a clear, linear flow of execution.</p>
</li>
<li><p><strong>Reusability:</strong> Modular functions can be reused across different parts of the codebase, reducing duplication and promoting a more efficient development process.</p>
</li>
</ol>
<h3 id="heading-guide-for-how-to-distribute-responsibilities">Guide for how to distribute responsibilities</h3>
<p>Deciding when &amp; how to split a function effectively is a critical aspect of writing clean and maintainable code. When breaking down functions, it's essential to adhere to the principle of "each function should only do one thing." Here's a detailed guide on how to decide when and how to split functions, while also considering levels of abstraction:</p>
<ol>
<li><p>Single Responsibility Principle (SRP):</p>
<p> Each function should have a single responsibility or perform a single task. When assessing whether to split a function, consider whether it's responsible for more than one distinct operation or task. If so, it's a clear indication that the function should be broken down into smaller, more focused units.</p>
</li>
<li><p>Levels of Abstraction:</p>
<p> Functions should operate at a consistent level of abstraction, meaning that the operations they perform should be at a similar conceptual level. For example, a function named <code>saveUser(user)</code> should handle operations related to saving a user, such as validating input data or persisting user information to a database.</p>
<pre><code class="lang-python"> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">saveUser</span>(<span class="hljs-params">user</span>):</span>
     <span class="hljs-keyword">if</span> isEmailValid(user.email):  <span class="hljs-comment"># Level of abstraction: Validation</span>
         <span class="hljs-comment"># Save user to database       # Level of abstraction: Persistence</span>
         <span class="hljs-keyword">pass</span>
     <span class="hljs-keyword">else</span>:
         <span class="hljs-comment"># Handle invalid email       # Level of abstraction: Error handling</span>
         <span class="hljs-keyword">pass</span>

 <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">isEmailValid</span>(<span class="hljs-params">email</span>):</span>
     <span class="hljs-comment"># Validate email address</span>
     <span class="hljs-keyword">pass</span>
</code></pre>
<p> In this example, <code>saveUser(user)</code> delegates the task of email validation to <code>isEmailValid(email)</code>, ensuring that each function operates at a consistent level of abstraction.</p>
</li>
<li><p>Functions Should Do Work One Level Below Their Name:</p>
<p> A function's name should provide a clear indication of the task it performs, and the function itself should handle operations one level below that abstraction. For instance, a function named <code>saveUser(user)</code> should encapsulate operations related to saving a user, such as validating user input data, checking email validity, and persisting user information to a database.</p>
</li>
<li><p>Avoid mixing levels of abstraction:</p>
<p> Avoid mixing operations with different levels of abstraction within the same function. For example, a function responsible for user authentication should not handle low-level tasks such as database access or input validation. By keeping functions focused on a single level of abstraction, code becomes more modular, readable, and maintainable.</p>
</li>
<li><p>Write pure functions:</p>
<p> A pure function is one that has no side effects and always produces the same output for a given input. This property makes pure functions predictable, testable, and easier to reason about. By isolating their behavior from the rest of the system, pure functions promote code reliability and maintainability.</p>
</li>
<li><p>Avoid side effects:</p>
<p> Side effects occur when a function modifies state outside of its scope, such as changing global variables, modifying external resources, or printing to the console. While some side effects are necessary, such as updating a database or interacting with external services, excessive side effects can make code difficult to understand and maintain.</p>
<p> When a function has side effects, it's crucial to reflect this in its name. Descriptive function names can provide clarity about the potential side effects, helping developers understand the function's behavior and usage. For example, a function named <code>updateDatabase</code> implies that it may modify the database state.</p>
<p> Alternatively, if a function performs side effects, consider encapsulating the side effect in a separate function or module. This approach isolates side effects, making them easier to manage and reason about. The pure function can then call the side effect function without directly modifying state.</p>
</li>
</ol>
<h3 id="heading-guide-for-when-to-distribute-responsibilities">Guide for when to distribute responsibilities</h3>
<p>Deciding when to split functions depends on several factors:</p>
<ol>
<li><p><strong>Complexity:</strong></p>
<p> If a function becomes too complex or lengthy, it's often an indication that it should be split into smaller, more manageable units.</p>
</li>
<li><p><strong>Single Responsibility:</strong></p>
<p> If a function performs multiple tasks or operations, it's a clear sign that it should be broken down into smaller functions, each with a single responsibility.</p>
</li>
<li><p><strong>Reusability:</strong></p>
<p> Identify portions of code that could be reused in other parts of the codebase. Extracting reusable logic into separate functions promotes code reuse and maintains a DRY (Don't Repeat Yourself) codebase.</p>
</li>
</ol>
<h3 id="heading-guide-for-when-not-to-distribute-responsibilities">Guide for when not to distribute responsibilities</h3>
<p>Avoiding the unnecessary splitting up of functions is crucial to maintaining a balance between granularity and readability. While breaking down functions can enhance code organization and clarity, excessive fragmentation can lead to code that is difficult to navigate and understand. Here's a more detailed explanation of when to avoid uselessly splitting up functions:</p>
<ol>
<li><p>Granularity vs Readability:</p>
<p> While granularity can improve code organization and reusability, it won't automatically enhance readability in all cases. Breaking down functions into excessively small units can result in code that is difficult to follow, especially if the functions are named poorly or if the split does not correspond to logical divisions in the code.</p>
</li>
<li><p>Renaming the Operation:</p>
<p> If splitting a function results in merely renaming the operation without providing additional clarity or modularity, it may not be necessary. For example, if a function named <code>calculateTotalPrice</code> is split into <code>calculateSubtotal</code> and <code>calculateTax</code>, but the original function's purpose remains unchanged, the split may not add value.</p>
</li>
<li><p>Finding the New Function Takes Longer:</p>
<p> If locating the newly extracted function takes longer than reading the extracted code inline, it defeats the purpose of splitting the function. The goal of function extraction is to enhance readability and maintainability, so if the extracted function introduces unnecessary complexity or confusion, it should be avoided.</p>
</li>
<li><p>Can't Produce Reasonable Name:</p>
<p> If you struggle to produce a reasonable, descriptive name for the extracted function, it may indicate that the operation being extracted does not have sufficient coherence or significance to warrant its own function. Functions should encapsulate meaningful units of work, so if the extracted function lacks clear purpose or relevance, it may be better to keep the operation within the original function.</p>
</li>
</ol>
<p>In conclusion, clean code is not just about writing code that works; it's about writing code that is easy to understand, maintain, and extend. When it comes to functions and methods, readability is paramount. Calling a function should be intuitive, with clear argument orders and concise naming conventions. Moreover, the length of a function's body plays a significant role in readability. By distributing responsibilities effectively and adhering to the single responsibility principle, functions become easier to comprehend and manage.</p>
]]></content:encoded></item><item><title><![CDATA[Clean Code - Part-3: Code Formatting]]></title><description><![CDATA[Code formatting is the practice of structuring code in a consistent and organized manner to enhance readability and convey meaning effectively.

Vertical Formatting
Vertical formatting concerns how code is organized from top to bottom, focusing on re...]]></description><link>https://blog.saurabhmahajan.com/clean-code-part-3-code-formatting</link><guid isPermaLink="true">https://blog.saurabhmahajan.com/clean-code-part-3-code-formatting</guid><category><![CDATA[code]]></category><category><![CDATA[coding]]></category><category><![CDATA[formatting]]></category><category><![CDATA[formats]]></category><category><![CDATA[clean code]]></category><dc:creator><![CDATA[Saurabh Mahajan]]></dc:creator><pubDate>Mon, 20 Jan 2025 16:08:08 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1737387846075/3c55b416-b32b-4a75-93b0-653683c5138d.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Code formatting is the practice of structuring code in a consistent and organized manner to enhance readability and convey meaning effectively.</p>
<hr />
<h1 id="heading-vertical-formatting">Vertical Formatting</h1>
<p>Vertical formatting concerns how code is organized from top to bottom, focusing on readability and logical grouping.</p>
<ol>
<li><p><strong>Readability like an essay:-</strong></p>
<p> Code should be structured in a way that allows for smooth reading from top to bottom, without unnecessary jumps or disruptions. This ensures that the code flows logically and is easy to follow.</p>
<pre><code class="lang-python"> <span class="hljs-comment"># Bad vertical formatting</span>
 <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">main</span>():</span>
     print(<span class="hljs-string">"Hello,"</span>)
 print(<span class="hljs-string">"world!"</span>)

 <span class="hljs-comment"># Good vertical formatting</span>
 <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">main</span>():</span>
     print(<span class="hljs-string">"Hello,"</span>)
     print(<span class="hljs-string">"world!"</span>)
</code></pre>
</li>
<li><p><strong>Separating Different Concepts:-</strong></p>
<p> Different concepts or sections of code should be separated by spacing to visually distinguish them. This improves readability by clearly indicating transitions between different parts of the code.</p>
<pre><code class="lang-python"> <span class="hljs-comment"># Bad: No spacing between different concepts</span>
 <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">process_data</span>():</span>
     <span class="hljs-comment"># code for processing data</span>

 <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">display_results</span>():</span>
     <span class="hljs-comment"># code for displaying results</span>

 <span class="hljs-comment"># Good: Separating different concepts with spacing</span>
 <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">process_data</span>():</span>
     <span class="hljs-comment"># code for processing data</span>

 <span class="hljs-comment"># Spacer</span>
 <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">display_results</span>():</span>
     <span class="hljs-comment"># code for displaying results</span>
</code></pre>
</li>
<li><p><strong>Related Concepts Close Together:-</strong></p>
<p> Code that is related or serves a similar purpose should be kept close together. This makes it easier for developers to understand the context and relationship between different parts of the code.</p>
<pre><code class="lang-python"> <span class="hljs-comment"># Bad: Related concepts separated by unrelated code</span>
 <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">calculate_area</span>():</span>
     <span class="hljs-comment"># code for calculating area</span>

 print(<span class="hljs-string">"Results:"</span>)

 <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">display_results</span>():</span>
     <span class="hljs-comment"># code for displaying results</span>

 <span class="hljs-comment"># Good: Related concepts grouped together</span>
 <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">calculate_area</span>():</span>
     <span class="hljs-comment"># code for calculating area</span>

 <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">display_results</span>():</span>
     <span class="hljs-comment"># code for displaying results</span>

 print(<span class="hljs-string">"Results:"</span>)
</code></pre>
</li>
</ol>
<hr />
<h1 id="heading-horizontal-formatting">Horizontal Formatting</h1>
<p>Horizontal formatting refers to how code is structured within a line, focusing on indentation, line breaks, and spacing.</p>
<ol>
<li><p><strong>Indentation:-</strong></p>
<p> Indentation is crucial for readability and code organization. Even if not strictly required by the language syntax, consistent indentation enhances readability by visually representing the structure of the code.</p>
<pre><code class="lang-python"> <span class="hljs-comment"># Bad: Inconsistent indentation</span>
 <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">main</span>():</span>
 print(<span class="hljs-string">"Hello, world!"</span>)

 <span class="hljs-comment"># Good: Consistent indentation</span>
 <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">main</span>():</span>
     print(<span class="hljs-string">"Hello, world!"</span>)
</code></pre>
</li>
<li><p><strong>Breaking Long Statements:-</strong></p>
<p> Long statements should be broken into multiple shorter ones to improve readability and prevent excessively long lines of code. This enhances clarity and makes it easier for developers to understand each part of the statement.</p>
<pre><code class="lang-python"> <span class="hljs-comment"># Bad: Long statement without line breaks</span>
 result = calculate_some_long_expression() + another_long_expression() - \
          some_other_long_expression()

 <span class="hljs-comment"># Good: Breaking long statement into multiple lines</span>
 result = (calculate_some_long_expression() +
           another_long_expression() -
           some_other_long_expression())
</code></pre>
</li>
<li><p><strong>Clear but Not Unreadable Long Names:-</strong></p>
<p> Variable and function names should be clear and descriptive, but not excessively long. This balance ensures that code remains readable while conveying the intent of each identifier.</p>
<pre><code class="lang-python"> <span class="hljs-comment"># Bad: Unreadably long name</span>
 <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">calculate_area_of_rectangle_given_length_and_width</span>(<span class="hljs-params">length, width</span>):</span>
     <span class="hljs-keyword">pass</span>

 <span class="hljs-comment"># Good: Clear and concise name</span>
 <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">calculate_rectangle_area</span>(<span class="hljs-params">length, width</span>):</span>
     <span class="hljs-keyword">pass</span>
</code></pre>
</li>
<li><p><strong>Spacing Between Code:-</strong></p>
<p> Proper spacing between elements of code improves readability and helps distinguish different parts of the code. Consistent use of spacing enhances clarity and makes the code easier to follow.</p>
<pre><code class="lang-python"> <span class="hljs-comment"># Bad: Lack of spacing between code elements</span>
 <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">main</span>():</span>
 result=calculate_area_of_rectangle_given_length_and_width(<span class="hljs-number">5</span>,<span class="hljs-number">10</span>)

 <span class="hljs-comment"># Good: Consistent spacing between code elements</span>
 <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">main</span>():</span>
     result = calculate_rectangle_area(<span class="hljs-number">5</span>, <span class="hljs-number">10</span>)
</code></pre>
</li>
<li><p><strong>Line Width</strong>:-</p>
<p> Lines of code should ideally be kept within a reasonable width to prevent horizontal scrolling and maintain readability. While there's no strict rule, a common guideline is to limit lines to around 80 characters.</p>
<pre><code class="lang-python"> <span class="hljs-comment"># Bad: Exceeding recommended line width</span>
 result = calculate_some_long_expression() + another_long_expression() - some_other_long_expression()

 <span class="hljs-comment"># Good: Keeping line width within recommended limit</span>
 result = (calculate_some_long_expression() +
           another_long_expression() -
           some_other_long_expression())
</code></pre>
</li>
</ol>
<p>Different programming languages may have their own conventions and guidelines for code formatting. It's essential to follow these conventions to ensure consistency and readability within the specific language ecosystem.</p>
<p>In summary, code formatting plays a crucial role in improving readability and conveying meaning within the code base. By adhering to principles of vertical and horizontal formatting, and following language-specific conventions, developers can create code that is easier to understand, maintain, and collaborate on.</p>
]]></content:encoded></item><item><title><![CDATA[Clean Code - Part-2: Comments]]></title><description><![CDATA[Our first priority should be that we shouldn't need to write comments in our code. The code should be clean enough (i.e. naming conventions, formatting, functions, etc) that it should self explain when looked at. But there are some cases where we mig...]]></description><link>https://blog.saurabhmahajan.com/clean-code-part-2-comments</link><guid isPermaLink="true">https://blog.saurabhmahajan.com/clean-code-part-2-comments</guid><category><![CDATA[code]]></category><category><![CDATA[clean code]]></category><category><![CDATA[comments]]></category><category><![CDATA[coding]]></category><dc:creator><![CDATA[Saurabh Mahajan]]></dc:creator><pubDate>Mon, 20 Jan 2025 16:07:17 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1737387827292/f752d353-7327-4205-9ef7-ca8bf4f4ca1c.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Our first priority should be that we shouldn't need to write comments in our code. The code should be clean enough (i.e. naming conventions, formatting, functions, etc) that it should self explain when looked at. But there are some cases where we might wanna consider writing comments.</p>
<p>Implementing the principles of good and bad comments in code requires careful consideration of clarity, necessity, and maintainability.</p>
<p>When writing code, it's best to make it easy to understand without needing lots of comments. This means using clear names for things and organizing the code in a logical way. Comments should only be used when necessary, like when something isn't obvious from the code alone.</p>
<hr />
<h1 id="heading-poor-comments">Poor Comments</h1>
<ol>
<li><p>Redundant Comments:-</p>
<pre><code class="lang-python"> <span class="hljs-comment"># Increment x by 1</span>
 x += <span class="hljs-number">1</span>
</code></pre>
<p> Comments like this are redundant because the code itself is self-explanatory and adding a comment doesn't provide any additional value.</p>
</li>
<li><p>Misleading Comments:-</p>
<pre><code class="lang-python"> <span class="hljs-comment"># Calculate average of numbers</span>
 total = sum(numbers)
</code></pre>
<p> Misleading comments can confuse other developers and lead to misunderstandings about the code's functionality. Like the above example has a comment that says 'Calculate average of numbers'. But actually, it's summing the numbers, not calculating the average.</p>
</li>
<li><p><strong>Commented-out Code:-</strong></p>
<pre><code class="lang-python"> <span class="hljs-comment"># x = 10</span>
 <span class="hljs-comment"># This line is commented out because we're not sure if we still need it.</span>
</code></pre>
<p> Leaving commented-out code in the source can clutter the codebase and make it difficult to understand the active code.</p>
</li>
</ol>
<hr />
<h1 id="heading-good-comments">Good Comments</h1>
<ol>
<li><p><strong>Legal Information:-</strong></p>
<pre><code class="lang-python"> <span class="hljs-comment"># Copyright (C) 2024 CompanyXYZ. All rights reserved.</span>
</code></pre>
<p> This type of comment provides important legal information about the code's ownership and usage rights.</p>
</li>
<li><p><strong>Explanations which can't be replaced by naming convention:-</strong></p>
<pre><code class="lang-python"> <span class="hljs-comment"># Explanation: Using a custom sorting algorithm due to specific requirements.</span>
 <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">custom_sort</span>(<span class="hljs-params">items</span>):</span>
     <span class="hljs-comment"># Custom sorting algorithm implementation</span>
     <span class="hljs-keyword">pass</span>
</code></pre>
<p> In this case, the comment explains why a custom sorting algorithm is being used instead of a built-in sorting function. This explanation provides valuable context that cannot be conveyed solely through the function name or code itself.</p>
</li>
<li><p><strong>Warnings:-</strong></p>
<pre><code class="lang-python"> <span class="hljs-comment"># WARNING: This function modifies the global variable 'counter'.</span>
 <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">increment_counter</span>():</span>
     <span class="hljs-keyword">global</span> counter
     counter += <span class="hljs-number">1</span>
     <span class="hljs-keyword">return</span> counter
</code></pre>
<p> In this example, the comment warns other developers that the function <code>increment_counter()</code> modifies a global variable named <code>counter</code>. This information is crucial for understanding the potential side effects of using this function.</p>
</li>
<li><p>Todo:-</p>
<pre><code class="lang-python"> <span class="hljs-comment"># <span class="hljs-doctag">TODO:</span> Implement error handling for invalid input.</span>
 <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">parse_input</span>(<span class="hljs-params">input_str</span>):</span>
     <span class="hljs-comment"># Code for parsing input goes here</span>
     <span class="hljs-keyword">pass</span>
</code></pre>
<p> Here, the comment indicates that the function <code>parse_input()</code> lacks error handling for invalid input. This serves as a reminder to implement this functionality in the future.</p>
</li>
<li><p><strong>Documentation Comments:-</strong></p>
<pre><code class="lang-python"> <span class="hljs-string">"""
 This function calculates the area of a rectangle.

 :param length: The length of the rectangle.
 :param width: The width of the rectangle.
 :return: The area of the rectangle.
 """</span>
 <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">calculate_rectangle_area</span>(<span class="hljs-params">length, width</span>):</span>
     <span class="hljs-keyword">return</span> length * width
</code></pre>
<p> Documentation comments provide comprehensive documentation for functions, classes, or modules, enhancing code readability and maintainability.</p>
</li>
</ol>
<p>In short, good code speaks for itself. By keeping things clear and organized, we can avoid the need for too many comments. While comments have their place, we should aim for code that's easy to understand without them. If used, comments should add value by providing necessary context, warnings, or documentation, rather than stating the obvious or cluttering the code base with redundant or misleading information.</p>
]]></content:encoded></item><item><title><![CDATA[Clean Code - Part-1: Naming]]></title><description><![CDATA[Assigning Names to Variables, Functions, Classes & More

Names should be meaningful
const us = new MainEntity();
us.process();
if (login) {
    // Some code related to login
}

Consider the above example:-

Lack of clarity on the overall purpose or f...]]></description><link>https://blog.saurabhmahajan.com/clean-code-part-1-naming</link><guid isPermaLink="true">https://blog.saurabhmahajan.com/clean-code-part-1-naming</guid><category><![CDATA[code]]></category><category><![CDATA[coding]]></category><category><![CDATA[clean code]]></category><category><![CDATA[#namingconvention]]></category><dc:creator><![CDATA[Saurabh Mahajan]]></dc:creator><pubDate>Mon, 20 Jan 2025 16:06:03 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1737387806485/cade8d20-bf26-4106-99e0-ff36c0b5e5b8.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Assigning Names to Variables, Functions, Classes &amp; More</p>
<hr />
<h1 id="heading-names-should-be-meaningful">Names should be meaningful</h1>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> us = <span class="hljs-keyword">new</span> MainEntity();
us.process();
<span class="hljs-keyword">if</span> (login) {
    <span class="hljs-comment">// Some code related to login</span>
}
</code></pre>
<p>Consider the above example:-</p>
<ul>
<li><p>Lack of clarity on the overall purpose or functionality of the code snippet.</p>
</li>
<li><p>The purpose and role of <code>MainEntity</code> are undefined, making it unclear what it represents.</p>
</li>
<li><p>The <code>process</code> method lacks description, leaving ambiguity about its functionality.</p>
</li>
<li><p>The condition check for <code>login</code> is unclear, with no indication of its type or purpose.</p>
</li>
<li><p>Ambiguity persists regarding whether <code>login</code> is a boolean flag, variable, or function.</p>
</li>
<li><p>The absence of context, descriptive naming, and documentation makes the code difficult to understand and maintain.</p>
</li>
</ul>
<pre><code class="lang-javascript">
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserSession</span> </span>{
    <span class="hljs-keyword">constructor</span>() {
        <span class="hljs-comment">// Initialize user session</span>
    }

    authenticate(credentials) {
        <span class="hljs-comment">// Authenticate user with provided credentials</span>
        <span class="hljs-comment">// Return true if authentication successful, false otherwise</span>
    }

    isLoggedIn() {
        <span class="hljs-comment">// Check if user is currently logged in</span>
        <span class="hljs-comment">// Return true if logged in, false otherwise</span>
    }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserManager</span> </span>{
    <span class="hljs-keyword">constructor</span>() {
        <span class="hljs-built_in">this</span>.userSession = <span class="hljs-keyword">new</span> UserSession();
    }

    authenticateUser(credentials) {
        <span class="hljs-keyword">const</span> isAuthenticated = <span class="hljs-built_in">this</span>.userSession.authenticate(credentials);
        <span class="hljs-keyword">if</span> (isAuthenticated) {
            <span class="hljs-comment">// Proceed with authenticated user logic</span>
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-comment">// Handle authentication failure</span>
        }
    }

    isLoggedIn() {
        <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.userSession.isLoggedIn();
    }
}
</code></pre>
<ul>
<li><p>The <code>UserManager</code> class effectively manages user-related functionality, including authentication and login status checks.</p>
</li>
<li><p>Descriptive naming of classes and methods, such as <code>authenticateUser</code> and <code>isLoggedIn</code>, enhances readability and understanding of their purpose.</p>
</li>
<li><p>Each method within the <code>UserManager</code> class has a clearly defined role, reducing ambiguity and improving maintainability.</p>
</li>
<li><p>The <code>isLoggedIn</code> method returns a boolean value, providing clarity on the user's login status.</p>
</li>
<li><p>Well-structured code and meaningful names offer context and understanding of the implemented functionality.</p>
</li>
<li><p>While not explicitly shown, adding comments or documentation would further enhance comprehension and maintainability.</p>
</li>
</ul>
<p>Meaningful names in code are paramount as they significantly enhance the readability, maintainability, and scalability of software projects. Clear and descriptive names for variables, functions, and classes facilitate easier comprehension for developers, reducing the cognitive load and enabling efficient collaboration. Additionally, meaningful names serve as a form of self-documentation, conveying the purpose and functionality of code elements without the need for extensive comments or documentation. This aids in debugging and troubleshooting processes, as well as in the ongoing maintenance and evolution of the codebase. Ultimately, investing time and effort into choosing meaningful names pays dividends in terms of code quality, developer productivity, and the long-term sustainability of software projects.</p>
<hr />
<h1 id="heading-name-casing">Name Casing</h1>
<p>Name casing is paramount in clean code as it enhances readability, maintainability, and collaboration among developers. By adhering to consistent naming conventions throughout the code base, developers can quickly understand the purpose and type of each identifier, facilitating easier navigation and modification of code. Clear and intuitive naming conventions also promote effective collaboration, as standardized naming styles reduce misunderstandings and promote cohesive coding standards. Additionally, name casing contributes to code consistency, ensuring that all elements of the code base follow the same conventions, thus enhancing overall code quality.</p>
<p>There are 4 major types of name casing used:-</p>
<ol>
<li><p>Snake Case:-</p>
<p> Usages - Typically used in Python for variables, functions, and methods.</p>
<p> Examples -</p>
<pre><code class="lang-python"> user_name = <span class="hljs-string">"John Doe"</span>
 calculate_discount = <span class="hljs-keyword">lambda</span> price, percentage: price * percentage / <span class="hljs-number">100</span>
</code></pre>
</li>
<li><p>Camel Case:-</p>
<p> Usages - Commonly used in Java and JavaScript for variables, functions, and methods.</p>
<p> Examples -</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">let</span> userName = <span class="hljs-string">"John Doe"</span>;
 <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">calculateDiscount</span>(<span class="hljs-params">price, percentage</span>) </span>{
     <span class="hljs-comment">// Function implementation</span>
 }
</code></pre>
</li>
<li><p>Pascal Case:-</p>
<p> Usages - Used in Python, Java, and JavaScript for naming classes.</p>
<p> Examples -</p>
<pre><code class="lang-java"> <span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserProfile</span> </span>{
     <span class="hljs-keyword">private</span> String name;
     <span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> age;

     <span class="hljs-comment">// Constructor, getters, setters, etc.</span>
 }
</code></pre>
</li>
<li><p>Kebab Case:-</p>
<p> Usages - Often used in HTML for attributes like IDs and classes.</p>
<p> Examples -</p>
<pre><code class="lang-python"> &lt;div id=<span class="hljs-string">"user-profile"</span> <span class="hljs-class"><span class="hljs-keyword">class</span>="<span class="hljs-title">user</span>-<span class="hljs-title">info</span>"&gt;&lt;/<span class="hljs-title">div</span>&gt;</span>
</code></pre>
</li>
</ol>
<p>These naming conventions help maintain consistency and readability within code bases, aiding developers in understanding and navigating the code more efficiently.</p>
<hr />
<h1 id="heading-how-to-name-variables-amp-constants">How to name variables &amp; constants?</h1>
<p>The standard rules when we should follow naming variables and constants is - describe the value and provide more details about the value's context without introducing redundancy (if applicable).</p>
<ol>
<li><p>Object</p>
<p> Representing a user</p>
<p> Variable: <code>user</code></p>
<p> More details: <code>loggedInUser</code>, <code>updatedUser</code>, <code>customer</code></p>
</li>
<li><p>Number</p>
<p> Representing age</p>
<p> Variable: <code>age</code></p>
<p> More details: <code>userAge</code>, <code>customerAge</code>, <code>employeeAge</code></p>
</li>
<li><p>String</p>
<p> Representing a name</p>
<p> Variable: <code>name</code></p>
<p> More details: <code>userName</code>, <code>productName</code>, <code>customerName</code></p>
</li>
<li><p>Boolean</p>
<p> Representing whether a user is active</p>
<p> Variable: <code>isActive</code></p>
<p> More details: <code>isLoggedInUserActive</code>, <code>isCustomerActive</code></p>
</li>
<li><p>Context oriented</p>
<p> User to Customer</p>
<p> Poor examples: <code>u</code>, <code>c</code>, <code>lIU</code>, <code>uR</code></p>
<p> Improved examples: <code>customer</code>, <code>client</code>, <code>loggedInCustomer</code>, <code>registeredCustomer</code></p>
</li>
<li><p>Constants</p>
<p> Representing the value of PI</p>
<p> Variable: <code>PI</code></p>
</li>
</ol>
<p>These examples demonstrate the importance of using descriptive and contextually appropriate names for variables and constants, enhancing readability, clarity, and maintainability of code.</p>
<hr />
<h1 id="heading-how-to-name-functionsmethods">How to name Functions/Methods?</h1>
<p>The standard rule we should follow when naming functions/methods is - use verbs or short phrases with descriptive adjectives.</p>
<p>We can categorize the naming for functions/methods in 3 types:-</p>
<ol>
<li><p><strong>Performs an operation:</strong></p>
<ul>
<li><p><strong>Performs an operation:</strong></p>
<ul>
<li><p><code>calculateArea()</code></p>
<p>  This method calculates the area of a shape, specifying clearly what it does without introducing redundancy. It follows the convention of using a verb (<code>calculate</code>) followed by a noun (<code>Area</code>) to describe the action performed.</p>
</li>
</ul>
</li>
<li><p><strong>Computes a boolean:</strong></p>
<ul>
<li><p><code>isValidEmail()</code></p>
<p>  This function computes a boolean value indicating whether an email address is valid or not. It follows the convention of using a verb (<code>isValid</code>) followed by a noun (<code>Email</code>) to describe the action and the context of the computation.</p>
</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>Context-oriented names:</strong></p>
<ul>
<li><p><code>addEmployeeToDepartment()</code></p>
<p>  This method adds an employee to a specific department, clearly indicating the context and action being performed. It follows the convention of prioritizing clarity and specificity in naming methods related to specific contexts.</p>
</li>
<li><p><code>employee.addToDepartment()</code></p>
<p>  This syntax suggests that an action (<code>addToDepartment</code>) is performed by an instance of the <code>employee</code> object within its own context. It adheres to object-oriented principles by indicating the subject of the action directly.</p>
</li>
<li><p><code>department.addEmployee()</code></p>
<p>  This syntax suggests that an action (<code>addEmployee</code>) is performed on the <code>department</code> object. It follows a logical structure of subject-verb, making it clear what is being acted upon within the context of the department.</p>
</li>
</ul>
</li>
<li><p><strong>Custom examples:</strong></p>
<ul>
<li><p><strong>Performs an operation:</strong></p>
<ul>
<li><p><code>generateReportSummary()</code></p>
<p>  This method generates a summary report based on certain data or criteria. It follows the convention by using a verb (<code>generate</code>) followed by a noun (<code>ReportSummary</code>) to describe the action.</p>
</li>
</ul>
</li>
<li><p><strong>Computes a boolean:</strong></p>
<ul>
<li><p><code>isUserLoggedIn()</code></p>
<p>  This function computes a boolean value indicating whether a user is currently logged in or not. It follows the convention by using a verb (<code>is</code>) followed by a descriptive adjective and noun (<code>UserLoggedIn</code>) to describe the context and the result of the computation.</p>
</li>
</ul>
</li>
<li><p><strong>Context-oriented names:</strong></p>
<ul>
<li><p><code>checkoutCart()</code></p>
<p>  This method performs the action of checking out items in a shopping cart. It follows the convention by clearly indicating the context (<code>cart</code>) and the action (<code>checkout</code>) being performed.</p>
</li>
</ul>
</li>
</ul>
</li>
</ol>
<p>These examples demonstrate how naming conventions can greatly enhance code readability and maintainability by providing clear indications of what each function/method does and within what context it operates.</p>
<hr />
<h1 id="heading-how-to-name-classes">How to name classes?</h1>
<p>The standard rule we should follow when naming classes is - use nouns or short phrases with nouns</p>
<p>Sure, here are detailed examples of naming classes using the provided guidelines along with custom examples:</p>
<ol>
<li><p><strong>Describe the object:</strong></p>
<ul>
<li><p><code>Product</code></p>
<p>  This class represents a product in a system. It follows the convention of using a noun (<code>Product</code>) to clearly describe the object it represents.</p>
</li>
</ul>
</li>
<li><p><strong>Provide more details without introducing redundancy:</strong></p>
<ul>
<li><p><code>Course</code></p>
<p>  This class represents a course, providing additional details without redundancy. It's concise and descriptive, making it clear what kind of object it represents without unnecessary repetition.</p>
</li>
</ul>
</li>
<li><p><strong>Avoid redundant suffixes:</strong></p>
<ul>
<li><p><code>DatabaseManager</code></p>
<p>  This class manages interactions with a database. It avoids redundant suffixes like "Obj" or "Entity" and instead focuses on describing the primary responsibility of the class.</p>
</li>
</ul>
</li>
<li><p><strong>Custom examples:</strong></p>
<ul>
<li><p><strong>Describe the object:</strong></p>
<ul>
<li><p><code>Customer</code></p>
<p>  This class represents a customer entity within a system. It follows the convention by using a noun (<code>Customer</code>) to clearly describe the object it represents.</p>
</li>
</ul>
</li>
<li><p><strong>Provide more details without introducing redundancy:</strong></p>
<ul>
<li><p><code>StudentProfile</code></p>
<p>  This class represents the profile of a student. It provides additional details (<code>Profile</code>) without introducing redundancy, making it clear what kind of object it represents.</p>
</li>
</ul>
</li>
<li><p><strong>Avoid redundant suffixes:</strong></p>
<ul>
<li><p><code>FileHandler</code></p>
<p>  This class handles file-related operations. It avoids redundant suffixes and focuses on describing its primary responsibility, which is handling files.</p>
</li>
</ul>
</li>
<li><p><strong>Bad names (to contrast):</strong></p>
<ul>
<li><p><code>UserObj</code></p>
<p>  This name is considered bad because it lacks specificity and does not provide clear information about the purpose or nature of the object it represents.</p>
</li>
<li><p><code>ObjectA</code></p>
<p>  This name is vague and does not convey any meaningful information about the object it represents, making it difficult to understand its purpose or use in the codebase.</p>
</li>
<li><p><code>Data</code></p>
<p>  This name is too generic and lacks specificity. It does not explain what kind of data the class represents or what its purpose is within the system, making it ambiguous and potentially confusing to other developers.</p>
</li>
</ul>
</li>
</ul>
</li>
</ol>
<hr />
<h1 id="heading-common-pitfalls-when-naming">Common pitfalls when naming</h1>
<p>In the context of writing clean code, naming conventions and consistency are crucial aspects that can greatly affect the readability, maintainability, and overall quality of your code base. Let's break down the common pitfalls that can occur when naming variables, functions, classes &amp; more:</p>
<ol>
<li><p><strong>Avoid unnecessary details in variable names</strong>:-</p>
<p> When naming variables, it's essential to strike a balance between being descriptive and concise. Variables should convey their purpose without including redundant information. For instance, instead of naming a variable <code>customerWithNameAndAge</code>, which explicitly states both the customer's name and age, you could simply name it <code>customer</code>. The context or usage of the variable should provide clarity on what data it holds.</p>
</li>
<li><p><strong>Avoid slang or unclear abbreviations</strong>:-</p>
<p> Using clear and understandable names helps other developers (including your future self) comprehend the code more easily. Avoid using obscure abbreviations or slang that might not be immediately apparent to others. For example, using <code>userWithEscalatedPrivileges</code> instead of an unclear abbreviation like <code>uwep</code> ensures that the purpose of the variable is clear at a glance.</p>
</li>
<li><p><strong>Avoid disinformation</strong>:-</p>
<p> Naming variables or functions in a way that misleads or provides incorrect information can lead to confusion and errors in the code. For instance, naming a variable <code>allCustomers</code> when it actually contains filtered customers can mislead other developers. Choosing names like <code>filteredCustomers</code> would accurately convey the contents of the variable, promoting clarity and reducing the chances of misunderstanding.</p>
</li>
<li><p><strong>Choose distinctive and explanatory names</strong>:-</p>
<p> Functions and methods should have names that clearly describe their purpose and functionality. Ambiguous names like <code>doSomething</code> or <code>processStuff</code> can be vague and unhelpful. Instead, opt for names that succinctly describe the action performed, such as <code>resizeImage</code>, <code>applyFilter</code>, or <code>convertFormat</code>. These names provide clear indications of what the function does, making the code easier to understand and maintain.</p>
</li>
<li><p><strong>Be consistent</strong>:-</p>
<p> Consistency in naming conventions across your codebase is essential for readability and maintainability. Choose a naming style for functions, variables, and classes and stick to it throughout your application. Whether you prefer <code>getCustomers()</code>, <code>fetchCustomers()</code>, or <code>retrieveCustomers()</code>, ensure that the chosen style is consistently applied. Inconsistent naming conventions can confuse developers and make it harder to understand the codebase as a whole.</p>
</li>
</ol>
<p>In summary, adhering to these principles of clean code—using descriptive yet concise names, avoiding ambiguous or misleading terminology, and maintaining consistency—can significantly improve the quality and readability of your code, making it easier to understand, debug, and maintain over time.</p>
]]></content:encoded></item><item><title><![CDATA[S.O.L.I.D Principles - The Practical Guide]]></title><description><![CDATA[Welcome to our exploration of SOLID principles—a foundational set of design principles in software engineering that can elevate the quality and maintainability of your code. In the ever-evolving landscape of software development, writing code that is...]]></description><link>https://blog.saurabhmahajan.com/solid-principles-the-practical-guide</link><guid isPermaLink="true">https://blog.saurabhmahajan.com/solid-principles-the-practical-guide</guid><category><![CDATA[SOLID principles]]></category><category><![CDATA[SRP]]></category><category><![CDATA[OCP]]></category><category><![CDATA[lsp]]></category><category><![CDATA[isp]]></category><category><![CDATA[DIP]]></category><category><![CDATA[coding]]></category><category><![CDATA[software development]]></category><category><![CDATA[Software Engineering]]></category><category><![CDATA[software architecture]]></category><category><![CDATA[design principles]]></category><dc:creator><![CDATA[Saurabh Mahajan]]></dc:creator><pubDate>Wed, 24 Apr 2024 07:22:11 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1713592231548/af154038-fbf5-424f-a68c-be4a2deaa6b7.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Welcome to our exploration of SOLID principles—a foundational set of design principles in software engineering that can elevate the quality and maintainability of your code. In the ever-evolving landscape of software development, writing code that is not only functional but also adaptable and maintainable is crucial. This is where SOLID principles come into play, offering a framework to guide developers in creating clean, flexible, and scalable software designs.</p>
<p>In this blog, we'll delve into the essence of each SOLID principle, understanding what they entail and why they matter. Whether you're a seasoned developer looking to refine your skills or a newcomer eager to grasp fundamental principles, this journey through SOLID principles promises to provide valuable insights and actionable knowledge. Let's embark on this exploration together and unlock the power of SOLID principles to elevate your software craftsmanship.</p>
<hr />
<h1 id="heading-introduction">Introduction</h1>
<p><strong>SOLID principles</strong> are a set of design principles that aim to make software designs more understandable, flexible, and maintainable.</p>
<p>The SOLID acronym stands for:</p>
<ol>
<li><p><strong>S - Single Responsibility Principle (SRP)</strong></p>
</li>
<li><p><strong>O - Open/Closed Principle (OCP)</strong></p>
</li>
<li><p><strong>L - Liskov Substitution Principle (LSP)</strong></p>
</li>
<li><p><strong>I - Interface Segregation Principle (ISP)</strong></p>
</li>
<li><p><strong>D - Dependency Inversion Principle (DIP)</strong></p>
</li>
</ol>
<p>These principles provide guidelines for writing clean, maintainable, and scalable code. By adhering to them, developers can create software systems that are easier to understand, extend, and modify.</p>
<hr />
<h1 id="heading-history">History</h1>
<p>SOLID principles were introduced by Robert C. Martin (also known as Uncle Bob) in the early 2000s and have since become a cornerstone of object-oriented design and programming. Robert C. Martin introduced these principles in his paper "Design Principles and Design Patterns," presented at the OOPSLA conference in 1995. They were further popularized in his book "Agile Software Development, Principles, Patterns, and Practices," published in 2002. Since then, they have become foundational concepts in software engineering and are often taught in computer science courses and used in software development practices worldwide.</p>
<hr />
<h1 id="heading-s-single-responsibility-principle-srp">S - Single Responsibility Principle (SRP)</h1>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1713597457276/27b47920-2477-4c3b-ba18-a3092c2b3bdc.webp" alt class="image--center mx-auto" /></p>
<h2 id="heading-definition">Definition</h2>
<p>A class should have only one reason to change.</p>
<h2 id="heading-explanation">Explanation</h2>
<p>This principle suggests that a class should have only one responsibility or job. It should encapsulate one and only one aspect of functionality within the software. This principle promotes a modular approach to software development by encouraging developers to break down complex systems into smaller, more manageable components.</p>
<p>To understand SRP more thoroughly, let's delve into its key aspects:</p>
<ol>
<li><p><strong>Responsibility</strong>: A responsibility in the context of SRP refers to a reason for a class to change. It can be defined as a cohesive set of tasks or functionalities that the class is responsible for.</p>
</li>
<li><p><strong>Reason to Change</strong>: A reason to change is any requirement or feature that might necessitate modifications to the code. By adhering to SRP, we aim to minimize the number of reasons for a class to change, thus reducing the likelihood of unintended side effects when modifications are made.</p>
</li>
<li><p><strong>Encapsulation</strong>: SRP is closely related to the concept of encapsulation, which is one of the core principles of object-oriented programming. Encapsulation involves bundling data and the methods that operate on that data into a single unit (i.e., a class). SRP suggests that this unit should have a single, well-defined responsibility.</p>
</li>
<li><p><strong>Cohesion</strong>: SRP encourages high cohesion within classes. Cohesion refers to the degree to which the elements of a module (e.g., a class) belong together. A class with high cohesion focuses on a single task or responsibility, making it easier to understand, maintain, and test.</p>
</li>
<li><p><strong>Separation of Concerns</strong>: SRP promotes the separation of concerns, which is a design principle aimed at separating a computer program into distinct sections, each addressing a separate concern. By separating concerns, we can manage complexity more effectively and improve maintainability.</p>
</li>
<li><p><strong>Benefits</strong>:</p>
<ul>
<li><p><strong>Improved Readability</strong>: Classes with a single responsibility tend to be more concise and easier to understand.</p>
</li>
<li><p><strong>Ease of Maintenance</strong>: When a class has only one reason to change, modifications are less likely to have unintended consequences elsewhere in the codebase.</p>
</li>
<li><p><strong>Testability</strong>: Smaller, more focused classes are typically easier to test because they have fewer dependencies and behaviors to consider.</p>
</li>
<li><p><strong>Reusability</strong>: Well-designed classes with a clear responsibility can often be reused in different contexts without modification.</p>
</li>
</ul>
</li>
</ol>
<h2 id="heading-example-violation">Example - Violation</h2>
<p>Let's consider an example where the Single Responsibility Principle is violated in an Account controller that handles deposit, withdrawal, and money transfer operations. We'll combine authorization logic, validation logic, and database transaction logic within the controller.</p>
<pre><code class="lang-java"><span class="hljs-keyword">import</span> org.springframework.stereotype.Controller;
<span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.PostMapping;
<span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.RequestBody;
<span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.RequestParam;
<span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.ResponseBody;

<span class="hljs-meta">@Controller</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AccountController</span> </span>{

    <span class="hljs-keyword">private</span> AccountService accountService;

    <span class="hljs-comment">// Authorization and validation logic combined with business logic</span>
    <span class="hljs-meta">@PostMapping("/deposit")</span>
    <span class="hljs-meta">@ResponseBody</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">deposit</span><span class="hljs-params">(<span class="hljs-meta">@RequestParam("accountId")</span> String accountId, <span class="hljs-meta">@RequestParam("amount")</span> <span class="hljs-keyword">double</span> amount)</span> </span>{
        <span class="hljs-comment">// Authorization logic</span>
        <span class="hljs-keyword">if</span> (!authorizeUser()) {
            <span class="hljs-keyword">return</span> <span class="hljs-string">"Unauthorized"</span>;
        }

        <span class="hljs-comment">// Validation logic</span>
        <span class="hljs-keyword">if</span> (amount &lt;= <span class="hljs-number">0</span>) {
            <span class="hljs-keyword">return</span> <span class="hljs-string">"Invalid amount"</span>;
        }

        <span class="hljs-comment">// Database transaction logic</span>
        <span class="hljs-keyword">if</span> (accountService.deposit(accountId, amount)) {
            <span class="hljs-keyword">return</span> <span class="hljs-string">"Deposit successful"</span>;
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-keyword">return</span> <span class="hljs-string">"Deposit failed"</span>;
        }
    }

    <span class="hljs-comment">// Similar methods for withdrawal and transfer</span>

    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">authorizeUser</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-comment">// Authorization logic implementation</span>
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">true</span>; <span class="hljs-comment">// Placeholder implementation</span>
    }
}
</code></pre>
<p>In this example, the <code>AccountController</code> class is responsible for handling HTTP requests related to account operations. However, it is violating the Single Responsibility Principle by combining authorization logic, validation logic, and database transaction logic within the controller.</p>
<p>To correct this violation and adhere to the Single Responsibility Principle, we can separate these concerns into distinct classes:</p>
<ol>
<li><p><code>AuthorizationService</code>: Responsible for handling authorization logic.</p>
</li>
<li><p><code>ValidationService</code>: Responsible for handling validation logic.</p>
</li>
<li><p><code>AccountService</code>: Responsible for handling database transactions related to account operations.</p>
</li>
</ol>
<h2 id="heading-example-fix">Example - Fix</h2>
<p>Here's how we can refactor the code:</p>
<pre><code class="lang-java"><span class="hljs-keyword">import</span> org.springframework.beans.factory.annotation.Autowired;
<span class="hljs-keyword">import</span> org.springframework.stereotype.Service;

<span class="hljs-meta">@Service</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AuthorizationService</span> </span>{

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">authorizeUser</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-comment">// Authorization logic implementation</span>
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">true</span>; <span class="hljs-comment">// Placeholder implementation</span>
    }
}
</code></pre>
<pre><code class="lang-java"><span class="hljs-keyword">import</span> org.springframework.beans.factory.annotation.Autowired;
<span class="hljs-keyword">import</span> org.springframework.stereotype.Service;

<span class="hljs-meta">@Service</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ValidationService</span> </span>{

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">validateAmount</span><span class="hljs-params">(<span class="hljs-keyword">double</span> amount)</span> </span>{
        <span class="hljs-keyword">return</span> amount &gt; <span class="hljs-number">0</span>;
    }
}
</code></pre>
<pre><code class="lang-java"><span class="hljs-keyword">import</span> org.springframework.beans.factory.annotation.Autowired;
<span class="hljs-keyword">import</span> org.springframework.stereotype.Service;

<span class="hljs-meta">@Service</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AccountService</span> </span>{

    <span class="hljs-meta">@Autowired</span>
    <span class="hljs-keyword">private</span> AccountRepository accountRepository;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">deposit</span><span class="hljs-params">(String accountId, <span class="hljs-keyword">double</span> amount)</span> </span>{
        <span class="hljs-comment">// Database transaction logic</span>
        <span class="hljs-comment">// Call methods from AccountRepository</span>
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">true</span>; <span class="hljs-comment">// Placeholder implementation</span>
    }

    <span class="hljs-comment">// Similar methods for withdrawal and transfer</span>
}
</code></pre>
<pre><code class="lang-java"><span class="hljs-keyword">import</span> org.springframework.data.jpa.repository.JpaRepository;
<span class="hljs-keyword">import</span> org.springframework.stereotype.Repository;

<span class="hljs-meta">@Repository</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">AccountRepository</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">JpaRepository</span>&lt;<span class="hljs-title">Account</span>, <span class="hljs-title">Long</span>&gt; </span>{
    <span class="hljs-comment">// Define methods for interacting with the account database</span>
}
</code></pre>
<pre><code class="lang-java"><span class="hljs-keyword">import</span> org.springframework.stereotype.Controller;
<span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.PostMapping;
<span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.RequestParam;
<span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.ResponseBody;

<span class="hljs-meta">@Controller</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AccountController</span> </span>{

    <span class="hljs-meta">@Autowired</span>
    <span class="hljs-keyword">private</span> AuthorizationService authorizationService;

    <span class="hljs-meta">@Autowired</span>
    <span class="hljs-keyword">private</span> ValidationService validationService;

    <span class="hljs-meta">@Autowired</span>
    <span class="hljs-keyword">private</span> AccountService accountService;

    <span class="hljs-meta">@PostMapping("/deposit")</span>
    <span class="hljs-meta">@ResponseBody</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">deposit</span><span class="hljs-params">(<span class="hljs-meta">@RequestParam("accountId")</span> String accountId, <span class="hljs-meta">@RequestParam("amount")</span> <span class="hljs-keyword">double</span> amount)</span> </span>{
        <span class="hljs-keyword">if</span> (!authorizationService.authorizeUser()) {
            <span class="hljs-keyword">return</span> <span class="hljs-string">"Unauthorized"</span>;
        }

        <span class="hljs-keyword">if</span> (!validationService.validateAmount(amount)) {
            <span class="hljs-keyword">return</span> <span class="hljs-string">"Invalid amount"</span>;
        }

        <span class="hljs-keyword">if</span> (accountService.deposit(accountId, amount)) {
            <span class="hljs-keyword">return</span> <span class="hljs-string">"Deposit successful"</span>;
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-keyword">return</span> <span class="hljs-string">"Deposit failed"</span>;
        }
    }

    <span class="hljs-comment">// Similar methods for withdrawal and transfer</span>
}
</code></pre>
<p>In this refactored version, we've separated the concerns into distinct classes: <code>AuthorizationService</code>, <code>ValidationService</code>, and <code>AccountService</code>. The <code>AccountController</code> now only orchestrates the flow of control by delegating the authorization and validation tasks to their respective services, and the database transaction logic is handled by the <code>AccountService</code>. This separation of concerns adheres to the Single Responsibility Principle, making the codebase more modular, maintainable, and testable.</p>
<hr />
<h1 id="heading-o-openclosed-principle-ocp"><strong>O - Open/Closed Principle (OCP)</strong></h1>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1713598800681/63fd27a9-fe5c-4ca0-8a53-4c1c9cc6cf3b.webp" alt class="image--center mx-auto" /></p>
<h2 id="heading-definition-1">Definition</h2>
<p>Software entities (classes, modules, functions, etc.) should be open for extension but closed for modification.</p>
<h2 id="heading-explanation-1">Explanation</h2>
<p>OCP emphasizes that software entities should allow for extension without requiring changes to their source code. This is achieved through abstraction and polymorphism.</p>
<p>In simpler terms, this principle suggests that once a class (or module or function) is written and tested, it should not be modified to add new behavior or to alter existing behavior. Instead, it should be designed in a way that allows new functionalities to be added without changing its source code.</p>
<p>Here's a detailed explanation of the Open-Closed Principle:</p>
<ol>
<li><p><strong>Open for Extension</strong>: This aspect implies that the behavior of a software entity can be extended without modifying its source code. In practical terms, this means that you should be able to add new functionality to a class or module by creating new code (such as subclasses, new modules, or new functions) rather than changing the existing code.</p>
</li>
<li><p><strong>Closed for Modification</strong>: This aspect implies that the existing source code of a software entity should not be changed. Once a class or module is developed, tested, and considered stable, it should remain untouched. Modifying existing code can introduce bugs and unintended consequences, especially in large systems.</p>
</li>
</ol>
<p>To achieve the Open-Closed Principle, several design patterns and techniques can be applied:</p>
<ul>
<li><p><strong>Abstraction</strong>: The base class provides a common interface, while subclasses can override or extend specific behaviors.</p>
</li>
<li><p><strong>Interfaces</strong>: Define interfaces or abstract classes that specify the behavior expected from different implementations. This allows new implementations to be added without modifying existing code.</p>
</li>
<li><p><strong>Composition over Inheritance</strong>: Instead of using inheritance, use composition to build flexible and extensible systems. This involves creating classes that contain instances of other classes, allowing behavior to be composed dynamically.</p>
</li>
<li><p><strong>Strategy Pattern</strong>: Define a family of algorithms, encapsulate each one as an object, and make them interchangeable. This allows the behavior of a class to vary independently from the class itself, promoting the open-closed principle.</p>
</li>
<li><p><strong>Decorator Pattern</strong>: Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.</p>
</li>
<li><p><strong>Dependency Injection</strong>: Instead of directly creating dependencies within a class, inject them from the outside. This allows different implementations to be provided at runtime, promoting flexibility and extensibility.</p>
</li>
</ul>
<p>By following the Open-Closed Principle, you can create software that is easier to maintain, extend, and test. It encourages modular, reusable, and loosely coupled designs, which are essential for building scalable and adaptable systems.</p>
<h2 id="heading-example-violation-1">Example - Violation</h2>
<p>Suppose we have a <code>AccessControl</code> interface and two concrete implementations: <code>BasicAccessControl</code> and <code>AdminAccessControl</code>. They both provide methods to check access and perform some security-related operations.</p>
<pre><code class="lang-java"><span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">AccessControl</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">boolean</span> <span class="hljs-title">hasAccess</span><span class="hljs-params">(String userId)</span></span>;
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BasicAccessControl</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">AccessControl</span> </span>{
    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">hasAccess</span><span class="hljs-params">(String userId)</span> </span>{
        <span class="hljs-comment">// Basic access control logic</span>
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">true</span>;
    }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AdminAccessControl</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">AccessControl</span> </span>{
    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">hasAccess</span><span class="hljs-params">(String userId)</span> </span>{
        <span class="hljs-comment">// Admin access control logic</span>
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">true</span>;
    }

    <span class="hljs-comment">// New method added violating OCP</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">logAccess</span><span class="hljs-params">(String userId)</span> </span>{
        <span class="hljs-comment">// Log access details</span>
        System.out.println(<span class="hljs-string">"Access logged for user: "</span> + userId);
    }
}
</code></pre>
<p>In this example, <code>AdminAccessControl</code> violates the Open-Closed Principle by adding a new method <code>logAccess()</code> to the class. If we continue adding new methods for different purposes, it would lead to modifying existing classes whenever new functionalities are introduced, which is against the principle.</p>
<h2 id="heading-example-fix-1">Example - Fix</h2>
<p>To adhere to the Open-Closed Principle, we can introduce a new class hierarchy for handling additional functionalities. We'll introduce an <code>AccessControlLogger</code> interface and concrete implementations for logging access details. This way, we can extend the behavior of <code>AccessControl</code> without modifying existing classes.</p>
<pre><code class="lang-java"><span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">AccessControl</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">boolean</span> <span class="hljs-title">hasAccess</span><span class="hljs-params">(String userId)</span></span>;
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BasicAccessControl</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">AccessControl</span> </span>{
    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">hasAccess</span><span class="hljs-params">(String userId)</span> </span>{
        <span class="hljs-comment">// Basic access control logic</span>
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">true</span>;
    }
}

<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">AccessControlLogger</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">logAccess</span><span class="hljs-params">(String userId)</span></span>;
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BasicAccessControlLogger</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">AccessControlLogger</span> </span>{
    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">logAccess</span><span class="hljs-params">(String userId)</span> </span>{
        <span class="hljs-comment">// Log basic access details</span>
        System.out.println(<span class="hljs-string">"Basic access logged for user: "</span> + userId);
    }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AdminAccessControl</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">AccessControl</span>, <span class="hljs-title">AccessControlLogger</span> </span>{
    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">hasAccess</span><span class="hljs-params">(String userId)</span> </span>{
        <span class="hljs-comment">// Admin access control logic</span>
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">true</span>;
    }

    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">logAccess</span><span class="hljs-params">(String userId)</span> </span>{
        <span class="hljs-comment">// Log admin access details</span>
        System.out.println(<span class="hljs-string">"Admin access logged for user: "</span> + userId);
    }
}
</code></pre>
<p>Now, <code>AdminAccessControl</code> implements both <code>AccessControl</code> and <code>AccessControlLogger</code>, allowing it to provide access control and logging functionalities separately. This approach follows the Open-Closed Principle because we can add new functionalities (like logging) without modifying existing classes.</p>
<hr />
<h1 id="heading-l-liskov-substitution-principle-lsp">L - Liskov Substitution Principle (LSP)</h1>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1713598817897/fca50916-12ff-4bbd-a7d8-818c33882c7d.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-definition-2">Definition</h2>
<p>A subclass should be substitutable for its superclass without causing errors or unexpected behavior.</p>
<h2 id="heading-explanation-2">Explanation</h2>
<h3 id="heading-key-points">Key Points:</h3>
<ol>
<li><p><strong>Inheritance Hierarchy</strong>: The principle primarily deals with inheritance relationships, where a subclass inherits from a superclass. The subclass should extend or specialize the behavior of the superclass but not alter its fundamental contract or assumptions.</p>
</li>
<li><p><strong>Behavior Preservation</strong>: When substituting a subclass instance for a superclass instance, the client code should continue to function correctly. This means that the subclass must honor the same contracts, adhere to the same preconditions and postconditions, and respect the same invariants as the superclass.</p>
</li>
<li><p><strong>Type Contracts</strong>: The LSP emphasizes the importance of adhering to the contracts defined by the superclass. This includes method signatures, behavior expectations, and any constraints specified by the superclass. Subclasses can strengthen (but not weaken) these contracts.</p>
</li>
<li><p><strong>Design by Contract</strong>: The principle aligns with the broader concept of "design by contract," where classes explicitly state their preconditions, postconditions, and invariants. Subclasses are expected to adhere to and possibly extend these contracts, ensuring that they maintain the same level of reliability and predictability.</p>
</li>
<li><p><strong>Robustness and Extensibility</strong>: Adhering to the LSP enhances the robustness and extensibility of object-oriented systems. It allows for easy substitution of components, facilitates code reuse, and simplifies maintenance, as changes to subclasses don't break client code relying on superclass behavior.</p>
</li>
</ol>
<h3 id="heading-benefits">Benefits:</h3>
<ul>
<li><p><strong>Maintainability</strong>: Eases maintenance by allowing for easy substitution of objects.</p>
</li>
<li><p><strong>Robustness</strong>: Ensures that changes to subclasses don't inadvertently break client code.</p>
</li>
<li><p><strong>Code Reusability</strong>: Encourages code reuse through inheritance.</p>
</li>
<li><p><strong>Design Clarity</strong>: Promotes clear interfaces and contracts between classes.</p>
</li>
</ul>
<p>By adhering to the Liskov Substitution Principle, developers can create more flexible, robust, and maintainable object-oriented systems.</p>
<h2 id="heading-example-violation-2">Example - Violation</h2>
<p>Let's consider a scenario where we have a caching system with two implementations: a <code>LocalCache</code> and a <code>NetworkCache</code>. We'll demonstrate a violation of the Liskov Substitution Principle and then correct it.</p>
<pre><code class="lang-java"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Cache</span> </span>{
    <span class="hljs-comment">// Common cache methods</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">put</span><span class="hljs-params">(String key, Object value)</span> </span>{
        <span class="hljs-comment">// implementation</span>
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> Object <span class="hljs-title">get</span><span class="hljs-params">(String key)</span> </span>{
        <span class="hljs-comment">// implementation</span>
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;
    }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">LocalCache</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Cache</span> </span>{
    <span class="hljs-comment">// Local cache specific methods and implementations</span>
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NetworkCache</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Cache</span> </span>{
    <span class="hljs-comment">// Network cache specific methods and implementations</span>
}
</code></pre>
<p>Now, let's say the <code>NetworkCache</code> has to make a network call to fetch the data, but the <code>get</code> method in the <code>Cache</code> class is synchronous. To handle the network call, <code>NetworkCache</code> might need an asynchronous <code>get</code> method. In this case, <code>NetworkCache</code> cannot be substituted for <code>Cache</code> without affecting the behavior, violating LSP.</p>
<h2 id="heading-example-fix-2">Example - Fix</h2>
<pre><code class="lang-java"><span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">Cache</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">put</span><span class="hljs-params">(String key, Object value)</span></span>;
    <span class="hljs-function">Object <span class="hljs-title">get</span><span class="hljs-params">(String key)</span></span>;
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">LocalCache</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Cache</span> </span>{
    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">put</span><span class="hljs-params">(String key, Object value)</span> </span>{
        <span class="hljs-comment">// Local cache specific implementation</span>
    }

    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> Object <span class="hljs-title">get</span><span class="hljs-params">(String key)</span> </span>{
        <span class="hljs-comment">// Local cache specific implementation</span>
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;
    }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NetworkCache</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Cache</span> </span>{
    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">put</span><span class="hljs-params">(String key, Object value)</span> </span>{
        <span class="hljs-comment">// Network cache specific implementation</span>
    }

    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> Object <span class="hljs-title">get</span><span class="hljs-params">(String key)</span> </span>{
        <span class="hljs-comment">// Asynchronous network call implementation</span>
        <span class="hljs-comment">// This might involve using callbacks, CompletableFuture, or similar mechanisms</span>
        <span class="hljs-comment">// This method might not return the actual value immediately but instead returns a Future or uses a callback</span>
        <span class="hljs-keyword">return</span> fetchDataAsynchronously(key);
    }

    <span class="hljs-function"><span class="hljs-keyword">private</span> CompletableFuture&lt;Object&gt; <span class="hljs-title">fetchDataAsynchronously</span><span class="hljs-params">(String key)</span> </span>{
        <span class="hljs-comment">// Simulated asynchronous network call</span>
        <span class="hljs-keyword">return</span> CompletableFuture.supplyAsync(() -&gt; {
            <span class="hljs-comment">// Actual network call to fetch data</span>
            <span class="hljs-keyword">return</span> fetchDataFromNetwork(key);
        });
    }

    <span class="hljs-function"><span class="hljs-keyword">private</span> Object <span class="hljs-title">fetchDataFromNetwork</span><span class="hljs-params">(String key)</span> </span>{
        <span class="hljs-comment">// Simulated network data fetch</span>
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;
    }
}
</code></pre>
<p>In this corrected version, both <code>LocalCache</code> and <code>NetworkCache</code> implement the <code>Cache</code> interface. The <code>get</code> method in <code>NetworkCache</code> returns a <code>CompletableFuture</code> representing the asynchronous result of the network call. This allows <code>NetworkCache</code> to be substituted for <code>Cache</code> without altering the behavior expected by client code, thus satisfying the Liskov Substitution Principle.</p>
<hr />
<h1 id="heading-i-interface-segregation-principle-isp">I - <strong>Interface Segregation Principle (ISP)</strong></h1>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1713598835525/a65774d6-5f71-4b4e-8c4a-c4fb6c57308d.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-definition-3">Definition</h2>
<p>Clients should not be forced to depend on interfaces they do not use.</p>
<h2 id="heading-explanation-3">Explanation</h2>
<p>The principle emphasizes the importance of designing software interfaces in a way that clients should not be forced to depend on methods they do not use. In simpler terms, ISP advocates for smaller, cohesive interfaces tailored to specific client requirements rather than large, monolithic ones.</p>
<p>At its core, ISP encourages developers to create specialized interfaces that contain only the necessary methods relevant to a specific client or group of clients. This prevents clients from being burdened with methods they don't need, which in turn promotes cleaner, more maintainable code.</p>
<h3 id="heading-example">Example:</h3>
<p>Consider a scenario where you have an interface called <code>Worker</code> which has methods such as <code>work()</code>, <code>eat()</code>, and <code>sleep()</code>. Now, let's say you have two types of clients: <code>Robot</code> and <code>Human</code>. Robots don't eat or sleep, they only work. Humans, on the other hand, do all three tasks.</p>
<p>With a single <code>Worker</code> interface, both <code>Robot</code> and <code>Human</code> classes would have to implement all three methods. This violates the Interface Segregation Principle because the <code>Robot</code> class would be forced to implement methods it doesn't need.</p>
<p>By segregating the interfaces, you could have an <code>Workable</code> interface containing only the <code>work()</code> method, and a <code>Eatable</code> interface containing only the <code>eat()</code> method. Both <code>Robot</code> and <code>Human</code> classes would then implement only the interfaces relevant to them.</p>
<h3 id="heading-benefits-1">Benefits:</h3>
<ol>
<li><p><strong>Reduced Dependency</strong>: Clients are not forced to depend on methods they don't use, reducing unnecessary dependencies.</p>
</li>
<li><p><strong>Improved Cohesion</strong>: Interfaces become more focused and cohesive, leading to clearer and more maintainable code.</p>
</li>
<li><p><strong>Easier Testing</strong>: Smaller interfaces are easier to test because there are fewer methods to consider in each test case.</p>
</li>
<li><p><strong>Flexibility and Scalability</strong>: It facilitates easier modifications and extensions as new clients can be accommodated without affecting existing ones.</p>
</li>
</ol>
<h3 id="heading-implementation-guidelines">Implementation Guidelines:</h3>
<ol>
<li><p><strong>Identify Clients</strong>: Understand the different types of clients that will interact with your system.</p>
</li>
<li><p><strong>Group Methods</strong>: Group methods based on client requirements and create smaller, focused interfaces.</p>
</li>
<li><p><strong>Prefer Composition over Inheritance</strong>: Sometimes, ISP can be achieved more effectively through composition rather than inheritance.</p>
</li>
<li><p><strong>Refactor Existing Code</strong>: If necessary, refactor existing interfaces to adhere to the ISP.</p>
</li>
</ol>
<p>The Interface Segregation Principle is a fundamental concept in OOP design that promotes flexibility, maintainability, and scalability in software systems. By focusing on the specific needs of clients and avoiding unnecessary dependencies, developers can create more robust and adaptable codebases. Following ISP, along with other SOLID principles, can lead to better-designed, more maintainable, and easier-to-understand software architectures.</p>
<h2 id="heading-example-violation-3">Example - Violation</h2>
<pre><code class="lang-java"><span class="hljs-comment">// MediaPlayer.java</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">MediaPlayer</span> </span>{
    <span class="hljs-function">String <span class="hljs-title">fetchAudioUrl</span><span class="hljs-params">()</span></span>;
    <span class="hljs-function">String <span class="hljs-title">fetchVideoUrl</span><span class="hljs-params">()</span></span>;
}

<span class="hljs-comment">// WindowsMediaPlayer.java</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">WindowsMediaPlayer</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">MediaPlayer</span> </span>{
    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">fetchAudioUrl</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-string">"Fetch audio URL for Windows Media Player"</span>;
    }

    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">fetchVideoUrl</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-string">"Fetch video URL for Windows Media Player"</span>;
    }
}

<span class="hljs-comment">// VlcMediaPlayer.java</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">VlcMediaPlayer</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">MediaPlayer</span> </span>{
    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">fetchAudioUrl</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-string">"Fetch audio URL for VLC Media Player"</span>;
    }

    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">fetchVideoUrl</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-string">"Fetch video URL for VLC Media Player"</span>;
    }
}

<span class="hljs-comment">// SpotifyMediaPlayer.java</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SpotifyMediaPlayer</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">MediaPlayer</span> </span>{
    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">fetchAudioUrl</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-string">"Fetch audio URL for Spotify Media Player"</span>;
    }

    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">fetchVideoUrl</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-comment">// Spotify doesn't support direct fetching of video URLs</span>
        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> UnsupportedOperationException(<span class="hljs-string">"Spotify does not support fetching video URLs"</span>);
    }
}
</code></pre>
<p>The issue here is that all implementations of the <code>MediaPlayer</code> interface are forced to implement both <code>fetchAudioUrl()</code> and <code>fetchVideoUrl()</code> methods, even if some players like <code>SpotifyMediaPlayer</code> don't support fetching audio URLs.</p>
<h2 id="heading-example-fix-3">Example - Fix</h2>
<p>To adhere to the Interface Segregation Principle, we should split the <code>MediaPlayer</code> interface into two separate interfaces, one for audio-related functionalities and another for video-related functionalities.</p>
<pre><code class="lang-java"><span class="hljs-comment">// AudioPlayer.java</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">AudioPlayer</span> </span>{
    <span class="hljs-function">String <span class="hljs-title">fetchAudioUrl</span><span class="hljs-params">()</span></span>;
}

<span class="hljs-comment">// VideoPlayer.java</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">VideoPlayer</span> </span>{
    <span class="hljs-function">String <span class="hljs-title">fetchVideoUrl</span><span class="hljs-params">()</span></span>;
}

<span class="hljs-comment">// WindowsMediaPlayer.java</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">WindowsMediaPlayer</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">AudioPlayer</span>, <span class="hljs-title">VideoPlayer</span> </span>{
    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">fetchAudioUrl</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-string">"Fetch audio URL for Windows Media Player"</span>;
    }

    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">fetchVideoUrl</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-string">"Fetch video URL for Windows Media Player"</span>;
    }
}

<span class="hljs-comment">// VlcMediaPlayer.java</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">VlcMediaPlayer</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">AudioPlayer</span>, <span class="hljs-title">VideoPlayer</span> </span>{
    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">fetchAudioUrl</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-string">"Fetch audio URL for VLC Media Player"</span>;
    }

    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">fetchVideoUrl</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-string">"Fetch video URL for VLC Media Player"</span>;
    }
}

<span class="hljs-comment">// SpotifyMediaPlayer.java</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SpotifyMediaPlayer</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">AudioPlayer</span> </span>{
    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">fetchAudioUrl</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-string">"Fetch audio URL for Spotify Media Player"</span>;
    }
}
</code></pre>
<p>By splitting the <code>MediaPlayer</code> interface into <code>AudioPlayer</code> and <code>VideoPlayer</code>, each class is now only forced to implement the methods that are relevant to it. This adheres to the Interface Segregation Principle, as clients are not forced to depend on interfaces they do not use. Now, <code>SpotifyMediaPlayer</code> doesn't need to implement the <code>fetchAudioUrl()</code> method, thus preventing it from having to throw an <code>UnsupportedOperationException</code>.</p>
<hr />
<h1 id="heading-d-dependency-inversion-principle-dip">D - <strong>Dependency Inversion Principle (DIP)</strong></h1>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1713598852517/a5b7dc15-aa82-4c29-970e-12d0bd2b1680.webp" alt class="image--center mx-auto" /></p>
<h2 id="heading-definition-4">Definition</h2>
<p>High-level modules should not depend on low-level modules; both should depend on abstractions. Abstractions should not depend on details; details should depend on abstractions.</p>
<h2 id="heading-explanation-4">Explanation</h2>
<p>The principle suggests that high-level modules (which contain the more abstract and policy-related aspects of the application) should not depend on low-level modules (which contain the more detailed implementation details). Instead, both should depend on abstractions, which can be interfaces or abstract classes. This decouples modules and makes the code more flexible and easier to maintain.</p>
<p>At its core, the Dependency Inversion Principle suggests two main things:</p>
<ol>
<li><p>High-level modules should not depend on low-level modules. Both should depend on abstractions.</p>
</li>
<li><p>Abstractions should not depend on details. Details should depend on abstractions.</p>
</li>
</ol>
<p>Let's break down these concepts:</p>
<ol>
<li><p><strong>High-level modules should not depend on low-level modules</strong>: This means that classes or modules that implement high-level policy or logic should not depend on the details of low-level components, such as specific implementations or concrete classes. Instead, both high-level and low-level modules should depend on abstractions. For example, rather than a high-level module directly instantiating or depending on a specific database class, it should depend on an interface or an abstract class that defines the behavior expected from the database component. This promotes decoupling and allows for easier substitution of components.</p>
</li>
<li><p><strong>Abstractions should not depend on details</strong>: This suggests that interfaces or abstract classes (abstractions) should define the behavior or contract that components adhere to, without depending on the specific implementation details of those components. In other words, the high-level policy or logic should not be affected by changes to the low-level details. This allows for greater flexibility and extensibility in the system. For example, if you have an interface for a logging service, it should define methods like <code>logInfo</code>, <code>logError</code>, etc., without specifying how those methods are implemented. Concrete logging implementations can then adhere to this interface, allowing for easy swapping between different logging mechanisms without affecting the rest of the codebase.</p>
</li>
</ol>
<p>By adhering to the Dependency Inversion Principle, you create a more modular and flexible design where components can be easily replaced or extended without impacting other parts of the system. It also facilitates easier testing since components can be easily mocked or replaced with stubs or fakes. Overall, DIP promotes a design that is easier to maintain, extend, and understand.</p>
<h2 id="heading-example-violation-4">Example - Violation</h2>
<p>Initially, the <code>NotificationService</code> directly depends on the concrete implementation of the <code>EmailService</code>.</p>
<pre><code class="lang-java"><span class="hljs-comment">// High-level module</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NotificationService</span> </span>{
    <span class="hljs-keyword">private</span> EmailService emailService;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">NotificationService</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">this</span>.emailService = <span class="hljs-keyword">new</span> EmailService();
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">sendNotification</span><span class="hljs-params">(String message)</span> </span>{
        emailService.sendEmail(<span class="hljs-string">"user@example.com"</span>, message);
    }
}

<span class="hljs-comment">// Low-level module</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">EmailService</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">sendEmail</span><span class="hljs-params">(String recipient, String message)</span> </span>{
        <span class="hljs-comment">// Logic to send email</span>
        System.out.println(<span class="hljs-string">"Email sent to "</span> + recipient + <span class="hljs-string">": "</span> + message);
    }
}

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Main</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>{
        NotificationService notificationService = <span class="hljs-keyword">new</span> NotificationService();
        notificationService.sendNotification(<span class="hljs-string">"Hello, this is a notification!"</span>);
    }
}
</code></pre>
<h2 id="heading-example-fix-4">Example - Fix</h2>
<p>To adhere to the Dependency Inversion Principle, we'll introduce an abstraction (interface) <code>NotificationProvider</code> that both <code>NotificationService</code>, <code>EmailService</code>, and <code>SMSService</code> will depend on. This way, <code>NotificationService</code> won't depend directly on the concrete implementations of these services.</p>
<pre><code class="lang-java"><span class="hljs-comment">// Abstraction</span>
<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">NotificationProvider</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">sendNotification</span><span class="hljs-params">(String recipient, String message)</span></span>;
}

<span class="hljs-comment">// Low-level module</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">EmailService</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">NotificationProvider</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">sendNotification</span><span class="hljs-params">(String recipient, String message)</span> </span>{
        <span class="hljs-comment">// Logic to send email</span>
        System.out.println(<span class="hljs-string">"Email sent to "</span> + recipient + <span class="hljs-string">": "</span> + message);
    }
}

<span class="hljs-comment">// Low-level module</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SMSService</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">NotificationProvider</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">sendNotification</span><span class="hljs-params">(String recipient, String message)</span> </span>{
        <span class="hljs-comment">// Logic to send SMS</span>
        System.out.println(<span class="hljs-string">"SMS sent to "</span> + recipient + <span class="hljs-string">": "</span> + message);
    }
}

<span class="hljs-comment">// High-level module</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NotificationService</span> </span>{
    <span class="hljs-keyword">private</span> NotificationProvider notificationProvider;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">NotificationService</span><span class="hljs-params">(NotificationProvider notificationProvider)</span> </span>{
        <span class="hljs-keyword">this</span>.notificationProvider = notificationProvider;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">sendNotification</span><span class="hljs-params">(String recipient, String message)</span> </span>{
        notificationProvider.sendNotification(recipient, message);
    }
}

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Main</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>{
        NotificationProvider emailService = <span class="hljs-keyword">new</span> EmailService(); <span class="hljs-comment">// Dependency injection</span>
        NotificationProvider smsService = <span class="hljs-keyword">new</span> SMSService(); <span class="hljs-comment">// Dependency injection</span>

        NotificationService emailNotificationService = <span class="hljs-keyword">new</span> NotificationService(emailService);
        emailNotificationService.sendNotification(<span class="hljs-string">"user@example.com"</span>, <span class="hljs-string">"Hello, this is an email notification!"</span>);

        NotificationService smsNotificationService = <span class="hljs-keyword">new</span> NotificationService(smsService);
        smsNotificationService.sendNotification(<span class="hljs-string">"1234567890"</span>, <span class="hljs-string">"Hello, this is an SMS notification!"</span>);
    }
}
</code></pre>
<p>In this refactored version, both <code>EmailService</code> and <code>SMSService</code> implement the <code>NotificationProvider</code> interface. This allows the <code>NotificationService</code> to be decoupled from specific implementations of notification providers and to depend on abstractions. This design adheres to the Dependency Inversion Principle, promoting flexibility and easier maintenance of the codebase.</p>
<hr />
<h1 id="heading-conclusion">Conclusion</h1>
<p>In conclusion, SOLID principles serve as guiding beacons in the vast sea of software development, illuminating the path to creating robust, maintainable, and adaptable codebases. By adhering to these principles—Single Responsibility, Open/Closed, Liskov Substitution, Interface Segregation, and Dependency Inversion—developers can foster codebases that are easier to understand, extend, and modify.</p>
<p>As we wrap up our exploration of SOLID principles, it's essential to recognize their significance in shaping not only individual code modules but entire software ecosystems. By embracing SOLID principles, developers empower themselves to write code that not only solves immediate problems but also stands the test of time, evolving gracefully as requirements change and technologies advance.</p>
<p>So, whether you're embarking on a new project or refactoring existing code, remember the SOLID principles as your guiding compass. Let them steer you towards software designs that are not only elegant but also resilient in the face of change. Together, let's build a future where SOLID principles are more than just principles—they're the foundation upon which exceptional software is built.</p>
]]></content:encoded></item><item><title><![CDATA[Object-Oriented Programming Concepts]]></title><description><![CDATA[Object-Oriented Programming (OOP) has emerged as a powerful paradigm in the world of software development, revolutionizing the way we design and build applications. At its core, OOP is a approach that models real-world concepts by creating objects th...]]></description><link>https://blog.saurabhmahajan.com/object-oriented-programming-concepts</link><guid isPermaLink="true">https://blog.saurabhmahajan.com/object-oriented-programming-concepts</guid><category><![CDATA[oop]]></category><category><![CDATA[OOPS]]></category><category><![CDATA[classes]]></category><category><![CDATA[Objects]]></category><category><![CDATA[abstraction]]></category><category><![CDATA[encapsulation]]></category><category><![CDATA[inheritance]]></category><category><![CDATA[polymorphism]]></category><dc:creator><![CDATA[Saurabh Mahajan]]></dc:creator><pubDate>Mon, 08 Apr 2024 18:13:37 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1712599151362/e1bdf63d-f380-4253-811f-228f044c5a4c.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Object-Oriented Programming (OOP) has emerged as a powerful paradigm in the world of software development, revolutionizing the way we design and build applications. At its core, OOP is a approach that models real-world concepts by creating objects that encapsulate both data and the code that operates on that data.</p>
<p>The beauty of OOP lies in its ability to create modular, reusable, and extensible code. By organizing software into objects, programmers can break down complex problems into smaller, more manageable components, each with its own well-defined responsibilities and behaviors.</p>
<p>OOP concepts have been instrumental in the development of robust, scalable, and maintainable software systems across various domains, from web applications and mobile apps to games and scientific simulations. By embracing OOP principles, programmers can create code that is not only functional but also easier to understand, modify, and extend over time.</p>
<p>In this blog, we'll explore the intricacies of OOP concepts, providing examples and real-world use cases to help you grasp their significance and practical applications. Whether you're a beginner or an experienced programmer, mastering OOP will undoubtedly enhance your ability to write clean, efficient, and future-proof code.</p>
<hr />
<h1 id="heading-why-is-oops-required">Why is OOPs required?</h1>
<ol>
<li><p><strong>Modularity</strong>: OOPs promotes modular design, where the program is divided into smaller, reusable components (objects), making it easier to develop, maintain, and modify the code.</p>
</li>
<li><p><strong>Code Reusability</strong>: Through inheritance, objects can reuse code from existing classes, reducing redundancy and promoting code reuse.</p>
</li>
<li><p><strong>Data Abstraction</strong>: OOPs allows for data abstraction, which means that the implementation details of an object are hidden from the outside world, providing better security and flexibility.</p>
</li>
<li><p><strong>Encapsulation</strong>: By encapsulating data and methods within objects, OOPs provides better control over data access and modification, improving code organization and security.</p>
</li>
<li><p><strong>Polymorphism</strong>: Polymorphism allows objects of different classes to be treated as objects of a common superclass, enabling more flexible and extensible code.</p>
</li>
<li><p><strong>Maintainability</strong>: OOPs promotes modularity, which makes it easier to identify and fix errors, as well as add new features or modify existing ones, improving code maintainability.</p>
</li>
<li><p><strong>Real-world Modeling</strong>: OOPs provides a way to model real-world objects and their interactions, making it easier to understand and design complex systems.</p>
</li>
</ol>
<hr />
<h1 id="heading-class">Class</h1>
<p>A class is a blueprint or template for creating objects. It defines a set of properties (attributes) and behaviors (methods) that objects of that class will have. Classes are the fundamental building blocks of Object-Oriented Programming (OOP).</p>
<p>A class is a user-defined data type that encapsulates data (attributes) and code (methods) that operate on that data.</p>
<p>Example:-</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BankAccount</span> </span>{
    <span class="hljs-comment">// Attributes (Properties)</span>
    <span class="hljs-keyword">private</span> String accountNumber;
    <span class="hljs-keyword">private</span> String accountHolderName;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">double</span> balance;

    <span class="hljs-comment">// Constructor</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">BankAccount</span><span class="hljs-params">(String accountNumber, String accountHolderName, 
                           <span class="hljs-keyword">double</span> initialBalance)</span> </span>{
        <span class="hljs-keyword">this</span>.accountNumber = accountNumber;
        <span class="hljs-keyword">this</span>.accountHolderName = accountHolderName;
        <span class="hljs-keyword">this</span>.balance = initialBalance;
    }

    <span class="hljs-comment">// Methods (Behaviors)</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">deposit</span><span class="hljs-params">(<span class="hljs-keyword">double</span> amount)</span> </span>{
        balance += amount;
        System.out.println(
            <span class="hljs-string">"Deposited $"</span> + amount + <span class="hljs-string">". New balance: $"</span> + balance);
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">withdraw</span><span class="hljs-params">(<span class="hljs-keyword">double</span> amount)</span> </span>{
        <span class="hljs-keyword">if</span> (balance &gt;= amount) {
            balance -= amount;
            System.out.println(
                <span class="hljs-string">"Withdrew $"</span> + amount + <span class="hljs-string">". New balance: $"</span> + balance);
        } <span class="hljs-keyword">else</span> {
            System.out.println(<span class="hljs-string">"Insufficient funds."</span>);
        }
    }

    <span class="hljs-comment">// Getter and Setter methods for attributes</span>
    <span class="hljs-comment">// ...</span>
}
</code></pre>
<p>In this example, the <code>BankAccount</code> class has three attributes (<code>accountNumber</code>, <code>accountHolderName</code>, and <code>balance</code>) that define the state of a bank account object. It also has a constructor that initializes these attributes when creating a new <code>BankAccount</code> object. Additionally, the class has two methods (<code>deposit()</code> and <code>withdraw()</code>) that define the behavior of a bank account object.</p>
<p><strong>Components of a Class:</strong></p>
<ol>
<li><p><strong>Modifiers</strong>: These specify the access level of the class, such as <code>public</code>, <code>private</code>, <code>protected</code>, or default (no modifier).</p>
</li>
<li><p><strong>Class Name</strong>: The name of the class, following the naming conventions (e.g., <code>BankAccount</code>).</p>
</li>
<li><p><strong>Superclass (if any)</strong>: If the class inherits from another class, the name of the superclass is specified using the <code>extends</code> keyword.</p>
</li>
<li><p><strong>Interfaces (if any)</strong>: If the class implements one or more interfaces, they are specified using the <code>implements</code> keyword.</p>
</li>
<li><p><strong>Body</strong>: The class body is enclosed within curly braces <code>{ }</code>, containing the class members (attributes and methods).</p>
</li>
</ol>
<hr />
<h1 id="heading-object">Object</h1>
<p>An object is an instance of a class. It is a real-world entity that has its own state (attributes) and behavior (methods) defined by the class it belongs to.</p>
<p>An object is a single instance of a class that encapsulates data and the code that operates on that data.</p>
<p>Example:-</p>
<pre><code class="lang-java">BankAccount account1 = <span class="hljs-keyword">new</span> BankAccount(<span class="hljs-string">"123456789"</span>, <span class="hljs-string">"John Doe"</span>, <span class="hljs-number">1000.0</span>);
BankAccount account2 = <span class="hljs-keyword">new</span> BankAccount(<span class="hljs-string">"987654321"</span>, <span class="hljs-string">"Jane Smith"</span>, <span class="hljs-number">5000.0</span>);

account1.deposit(<span class="hljs-number">500.0</span>); <span class="hljs-comment">// Output: Deposited $500.0. New balance: $1500.0</span>
account2.withdraw(<span class="hljs-number">1000.0</span>); <span class="hljs-comment">// Output: Withdrew $1000.0. New balance: $4000.0</span>
</code></pre>
<p>In this example, <code>account1</code> and <code>account2</code> are two separate objects of the <code>BankAccount</code> class, each with its own set of attribute values (<code>accountNumber</code>, <code>accountHolderName</code>, and <code>balance</code>). We can invoke the <code>deposit()</code> and <code>withdraw()</code> methods on these objects, and they will behave according to their respective states.</p>
<p><strong>Components of an Object:</strong></p>
<ol>
<li><p><strong>State</strong>: The state of an object is defined by its attributes or properties (e.g., <code>accountNumber</code>, <code>accountHolderName</code>, and <code>balance</code> in the <code>BankAccount</code> class).</p>
</li>
<li><p><strong>Behavior</strong>: The behavior of an object is defined by its methods (e.g., <code>deposit()</code> and <code>withdraw()</code> in the <code>BankAccount</code> class).</p>
</li>
<li><p><strong>Identity</strong>: Each object has a unique identity, which is typically represented by its memory address or reference.</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712599278042/2d950434-cc5e-4e22-bfbd-8bd2edc9fe90.webp" alt class="image--center mx-auto" /></p>
<hr />
<h1 id="heading-major-pillars-of-oops">Major Pillars of OOPs</h1>
<h2 id="heading-abstraction">Abstraction</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712599469196/64ce0685-ac6c-4bb7-b6b2-fcf7c035beb4.png" alt class="image--center mx-auto" /></p>
<p>Abstraction is the process of hiding unnecessary details and exposing only the essential features of an object. It allows you to define the interface (how an object should behave) without revealing the implementation details (how the object works internally).</p>
<p>Abstraction is a way of representing complex real-world entities in a simplified manner by focusing on their essential features and ignoring unnecessary details.</p>
<p>Example:-</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Main</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>{
        Animal dog = <span class="hljs-keyword">new</span> Dog(<span class="hljs-string">"Buddy"</span>);
        System.out.println(<span class="hljs-string">"Name: "</span> + dog.getName()); <span class="hljs-comment">// Output: Name: Buddy</span>
        dog.makeSound(); <span class="hljs-comment">// Output: Woof!</span>
    }
}

<span class="hljs-keyword">abstract</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Animal</span> </span>{
    <span class="hljs-keyword">private</span> String name;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Animal</span><span class="hljs-params">(String name)</span> </span>{
        <span class="hljs-keyword">this</span>.name = name;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">getName</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> name;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">void</span> <span class="hljs-title">makeSound</span><span class="hljs-params">()</span></span>;
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Dog</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Animal</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Dog</span><span class="hljs-params">(String name)</span> </span>{
        <span class="hljs-keyword">super</span>(name);
    }

    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">makeSound</span><span class="hljs-params">()</span> </span>{
        System.out.println(<span class="hljs-string">"Woof!"</span>);
    }
}
</code></pre>
<p>In this example, the <code>Animal</code> class is an abstract class that defines the common behavior of animals (e.g., having a name) but leaves the implementation of <code>makeSound()</code> to its concrete subclasses (e.g., <code>Dog</code>). The <code>Dog</code> class provides the implementation for the <code>makeSound()</code> method.</p>
<h2 id="heading-encapsulation">Encapsulation</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712599670417/a4131492-0d34-439b-8fac-a83116b02f24.jpeg" alt class="image--center mx-auto" /></p>
<p>Encapsulation is the bundling of data (properties) and methods (behaviors) together within a single unit, known as a class. It helps in achieving data abstraction and controlling the access to the object's internal state.</p>
<p>Encapsulation is the mechanism of binding data and the code that operates on that data into a single unit, known as a class. It restricts direct access to the object's internal state and provides controlled access through public methods.</p>
<p>Example:-</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Main</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>{
        BankAccount account = <span class="hljs-keyword">new</span> BankAccount();
        System.out.println(<span class="hljs-string">"Initial balance: "</span> + account.getBalance()); <span class="hljs-comment">// Output: Initial balance: 0.0</span>

        account.deposit(<span class="hljs-number">1000.0</span>);
        System.out.println(<span class="hljs-string">"Balance after deposit: "</span> + account.getBalance()); <span class="hljs-comment">// Output: Balance after deposit: 1000.0</span>

        account.withdraw(<span class="hljs-number">500.0</span>);
        System.out.println(<span class="hljs-string">"Balance after withdrawal: "</span> + account.getBalance()); <span class="hljs-comment">// Output: Balance after withdrawal: 500.0</span>

        account.withdraw(<span class="hljs-number">600.0</span>); <span class="hljs-comment">// Output: Insufficient funds.</span>
    }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BankAccount</span> </span>{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">double</span> balance;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> <span class="hljs-title">getBalance</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> balance;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">deposit</span><span class="hljs-params">(<span class="hljs-keyword">double</span> amount)</span> </span>{
        balance += amount;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">withdraw</span><span class="hljs-params">(<span class="hljs-keyword">double</span> amount)</span> </span>{
        <span class="hljs-keyword">if</span> (balance &gt;= amount)
            balance -= amount;
        <span class="hljs-keyword">else</span>
            System.out.println(<span class="hljs-string">"Insufficient funds."</span>);
    }
}
</code></pre>
<p>In this example, the <code>BankAccount</code> class encapsulates the <code>balance</code> field by making it private and providing public methods (<code>getBalance</code>, <code>deposit</code>, and <code>withdraw</code>) to access and modify the balance in a controlled manner.</p>
<h2 id="heading-inheritance"><strong>Inheritance</strong></h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712599682846/978869aa-c11b-470a-a5a0-7a56c1cb063e.png" alt class="image--center mx-auto" /></p>
<p>Inheritance is a mechanism that allows a new class (child or derived class) to be based on an existing class (parent or base class). The child class inherits properties and methods from the parent class, promoting code reuse and enabling the creation of hierarchical relationships.</p>
<p>Inheritance is a concept in OOP that allows a new class (derived class) to inherit properties and behaviors from an existing class (base class), forming an "is-a" relationship between the classes.</p>
<p>Example:-</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Main</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>{
        Vehicle vehicle = <span class="hljs-keyword">new</span> Vehicle(<span class="hljs-string">"Toyota"</span>, <span class="hljs-string">"Corolla"</span>);
        vehicle.start(); <span class="hljs-comment">// Output: Vehicle started.</span>

        Car car = <span class="hljs-keyword">new</span> Car(<span class="hljs-string">"Honda"</span>, <span class="hljs-string">"Civic"</span>, <span class="hljs-number">4</span>);
        car.start(); <span class="hljs-comment">// Output: Vehicle started.</span>
        car.openTrunk(); <span class="hljs-comment">// Output: Trunk opened.</span>
    }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Vehicle</span> </span>{
    <span class="hljs-keyword">protected</span> String make;
    <span class="hljs-keyword">protected</span> String model;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Vehicle</span><span class="hljs-params">(String make, String model)</span> </span>{
        <span class="hljs-keyword">this</span>.make = make;
        <span class="hljs-keyword">this</span>.model = model;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">start</span><span class="hljs-params">()</span> </span>{
        System.out.println(<span class="hljs-string">"Vehicle started."</span>);
    }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Car</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Vehicle</span> </span>{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> numDoors;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Car</span><span class="hljs-params">(String make, String model, <span class="hljs-keyword">int</span> numDoors)</span> </span>{
        <span class="hljs-keyword">super</span>(make, model);
        <span class="hljs-keyword">this</span>.numDoors = numDoors;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">openTrunk</span><span class="hljs-params">()</span> </span>{
        System.out.println(<span class="hljs-string">"Trunk opened."</span>);
    }
}
</code></pre>
<p>In this example, the <code>Car</code> class inherits from the <code>Vehicle</code> class. It inherits the <code>make</code>, <code>model</code>, and <code>start()</code> method from the <code>Vehicle</code> class and adds its own <code>numDoors</code> attribute and <code>openTrunk()</code> method.</p>
<h2 id="heading-polymorphism">Polymorphism</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712599698185/6939d78c-fb2f-4c39-a17f-1140e16248cc.webp" alt class="image--center mx-auto" /></p>
<p>Polymorphism is a concept in OOP that allows objects of different classes to be treated as objects of a common superclass, enabling code reusability and flexibility. It can be achieved through method overriding (runtime polymorphism) or method overloading (compile-time polymorphism).</p>
<h3 id="heading-runtime-polymorphism-method-overriding"><strong>Runtime Polymorphism (Method Overriding)</strong></h3>
<p>Runtime polymorphism, also known as method overriding, occurs when a subclass provides its own implementation of a method that is already defined in its superclass.</p>
<p>Example:-</p>
<pre><code class="lang-java"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Animal</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">makeSound</span><span class="hljs-params">()</span> </span>{
        System.out.println(<span class="hljs-string">"Animal sound"</span>);
    }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Dog</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Animal</span> </span>{
    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">makeSound</span><span class="hljs-params">()</span> </span>{
        System.out.println(<span class="hljs-string">"Woof!"</span>);
    }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Cat</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Animal</span> </span>{
    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">makeSound</span><span class="hljs-params">()</span> </span>{
        System.out.println(<span class="hljs-string">"Meow!"</span>);
    }
}

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Main</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>{
        Animal animal1 = <span class="hljs-keyword">new</span> Animal();
        Animal animal2 = <span class="hljs-keyword">new</span> Dog();
        Animal animal3 = <span class="hljs-keyword">new</span> Cat();

        animal1.makeSound(); <span class="hljs-comment">// Output: Animal sound</span>
        animal2.makeSound(); <span class="hljs-comment">// Output: Woof!</span>
        animal3.makeSound(); <span class="hljs-comment">// Output: Meow!</span>
    }
}
</code></pre>
<p>In this example, the <code>Dog</code> and <code>Cat</code> classes override the <code>makeSound()</code> method of the <code>Animal</code> class, exhibiting runtime polymorphism. The <code>makeSound()</code> method behaves differently based on the actual object type (Animal, Dog, or Cat) at runtime.</p>
<p>Rules:-</p>
<ul>
<li><p>Methods of child and parent class must have the same name.</p>
</li>
<li><p>Methods of child and parent class must have the same parameters.</p>
</li>
<li><p>IS-A relationship is mandatory (inheritance).</p>
</li>
<li><p>One cannot override the private methods of a parent class.</p>
</li>
<li><p>One cannot override Final methods.</p>
</li>
<li><p>One cannot override static methods.</p>
</li>
</ul>
<h3 id="heading-compile-time-polymorphism-method-overloading"><strong>Compile-time Polymorphism (Method Overloading)</strong></h3>
<p>Compile-time polymorphism, also known as method overloading, occurs when a class has multiple methods with the same name but different parameter lists (different number of parameters, different types of parameters, or both).</p>
<p>Example:-</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Main</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>{
        Calculator calculator = <span class="hljs-keyword">new</span> Calculator();

        <span class="hljs-keyword">int</span> sum1 = calculator.add(<span class="hljs-number">2</span>, <span class="hljs-number">3</span>); <span class="hljs-comment">// Output: 5</span>
        <span class="hljs-keyword">double</span> sum2 = calculator.add(<span class="hljs-number">2.5</span>, <span class="hljs-number">3.7</span>); <span class="hljs-comment">// Output: 6.2</span>
        <span class="hljs-keyword">int</span> sum3 = calculator.add(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>); <span class="hljs-comment">// Output: 6</span>
    }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Calculator</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">add</span><span class="hljs-params">(<span class="hljs-keyword">int</span> a, <span class="hljs-keyword">int</span> b)</span> </span>{
        <span class="hljs-keyword">return</span> a + b;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> <span class="hljs-title">add</span><span class="hljs-params">(<span class="hljs-keyword">double</span> a, <span class="hljs-keyword">double</span> b)</span> </span>{
        <span class="hljs-keyword">return</span> a + b;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">add</span><span class="hljs-params">(<span class="hljs-keyword">int</span> a, <span class="hljs-keyword">int</span> b, <span class="hljs-keyword">int</span> c)</span> </span>{
        <span class="hljs-keyword">return</span> a + b + c;
    }
}
</code></pre>
<p>In this example, we create an instance of the <code>Calculator</code> class and call different overloaded versions of the <code>add()</code> method. The compiler determines the correct method to call based on the number and types of arguments provided, demonstrating compile-time polymorphism.</p>
<p>Types:-</p>
<ul>
<li><p>By changing number of parameters</p>
</li>
<li><p>By changing data type of any parameter</p>
</li>
<li><p>By changing sequence of parameters</p>
</li>
</ul>
<hr />
<h1 id="heading-minor-pillars-of-oops">Minor Pillars of OOPs</h1>
<h2 id="heading-typing">Typing</h2>
<p>In a strongly typed language like Java, every variable and expression must have a well-defined data type. The compiler enforces type safety by ensuring that operations are performed only on compatible data types. This helps catch type-related errors at compile-time, making the code more robust and reliable.</p>
<p>Example:-</p>
<pre><code class="lang-java"><span class="hljs-keyword">int</span> age = <span class="hljs-number">25</span>; <span class="hljs-comment">// Valid</span>
age = <span class="hljs-string">"thirty"</span>; <span class="hljs-comment">// Compiler error: Incompatible types</span>

String name = <span class="hljs-string">"John"</span>;
<span class="hljs-keyword">int</span> length = name.length(); <span class="hljs-comment">// Valid</span>
</code></pre>
<p>In the above example, the variable <code>age</code> is declared as an <code>int</code>, so you cannot assign a string value like <code>"thirty"</code> to it. The compiler will raise an error. However, you can call the <code>length()</code> method on the <code>String</code> object <code>name</code> and assign the result (an <code>int</code> value) to the <code>length</code> variable.</p>
<h2 id="heading-persistance">Persistance</h2>
<p>Persistence refers to the ability of an object to survive beyond the lifetime of the program or process that created it. In other words, persistent objects can be stored and retrieved from non-volatile storage, such as a file system or a database, without losing their state.</p>
<p>Example:-</p>
<p>Consider a <code>Student</code> class that represents a student's information:</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Student</span> </span>{
    <span class="hljs-keyword">private</span> String name;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> age;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">double</span> gpa;

    <span class="hljs-comment">// Constructors, getters, and setters</span>
}
</code></pre>
<p>To make <code>Student</code> objects persistent, you can use serialization, which is the process of converting an object's state to a byte stream that can be saved to a file or sent over a network. Java provides built-in support for serialization through the <code>Serializable</code> interface.</p>
<pre><code class="lang-java"><span class="hljs-keyword">import</span> java.io.*;

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PersistenceExample</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>{
        Student student = <span class="hljs-keyword">new</span> Student(<span class="hljs-string">"John"</span>, <span class="hljs-number">20</span>, <span class="hljs-number">3.8</span>);

        <span class="hljs-comment">// Serialize the object to a file</span>
        <span class="hljs-keyword">try</span> (ObjectOutputStream oos = <span class="hljs-keyword">new</span> ObjectOutputStream(<span class="hljs-keyword">new</span> FileOutputStream(<span class="hljs-string">"student.dat"</span>))) {
            oos.writeObject(student);
        } <span class="hljs-keyword">catch</span> (IOException e) {
            e.printStackTrace();
        }

        <span class="hljs-comment">// Later, deserialize the object from the file</span>
        Student deserializedStudent = <span class="hljs-keyword">null</span>;
        <span class="hljs-keyword">try</span> (ObjectInputStream ois = <span class="hljs-keyword">new</span> ObjectInputStream(<span class="hljs-keyword">new</span> FileInputStream(<span class="hljs-string">"student.dat"</span>))) {
            deserializedStudent = (Student) ois.readObject();
        } <span class="hljs-keyword">catch</span> (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }

        <span class="hljs-comment">// The deserializedStudent object has the same state as the original student object</span>
        System.out.println(deserializedStudent.getName()); <span class="hljs-comment">// Output: John</span>
        System.out.println(deserializedStudent.getAge()); <span class="hljs-comment">// Output: 20</span>
        System.out.println(deserializedStudent.getGpa()); <span class="hljs-comment">// Output: 3.8</span>
    }
}
</code></pre>
<p>In this example, a <code>Student</code> object is serialized to a file named <code>student.dat</code>. Later, the object is deserialized from the same file, and its state is preserved, allowing you to work with the same object even after the program has terminated and restarted.</p>
<h2 id="heading-concurrency">Concurrency</h2>
<p>Concurrency refers to the ability of multiple computations or threads to execute simultaneously and potentially interact with each other.</p>
<p>In Java, you can create and manage threads to achieve concurrency. However, concurrent access to shared resources (e.g., objects or data structures) can lead to race conditions and other synchronization issues.</p>
<p>Example:-</p>
<p>Consider a <code>BankAccount</code> class that represents a bank account with a balance:</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BankAccount</span> </span>{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">double</span> balance;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">BankAccount</span><span class="hljs-params">(<span class="hljs-keyword">double</span> initialBalance)</span> </span>{
        <span class="hljs-keyword">this</span>.balance = initialBalance;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">synchronized</span> <span class="hljs-keyword">void</span> <span class="hljs-title">deposit</span><span class="hljs-params">(<span class="hljs-keyword">double</span> amount)</span> </span>{
        <span class="hljs-keyword">double</span> newBalance = balance + amount;
        <span class="hljs-comment">// Simulate a delay to illustrate the potential for race conditions</span>
        <span class="hljs-keyword">try</span> {
            Thread.sleep(<span class="hljs-number">100</span>);
        } <span class="hljs-keyword">catch</span> (InterruptedException e) {
            e.printStackTrace();
        }
        balance = newBalance;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">synchronized</span> <span class="hljs-keyword">void</span> <span class="hljs-title">withdraw</span><span class="hljs-params">(<span class="hljs-keyword">double</span> amount)</span> </span>{
        <span class="hljs-keyword">double</span> newBalance = balance - amount;
        <span class="hljs-comment">// Simulate a delay to illustrate the potential for race conditions</span>
        <span class="hljs-keyword">try</span> {
            Thread.sleep(<span class="hljs-number">100</span>);
        } <span class="hljs-keyword">catch</span> (InterruptedException e) {
            e.printStackTrace();
        }
        balance = newBalance;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> <span class="hljs-title">getBalance</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> balance;
    }
}
</code></pre>
<p>Now, let's create two threads that both try to deposit and withdraw money from the same <code>BankAccount</code> object:</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ConcurrencyExample</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>{
        BankAccount account = <span class="hljs-keyword">new</span> BankAccount(<span class="hljs-number">1000.0</span>);

        Runnable depositTask = () -&gt; {
            <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">1000</span>; i++) {
                account.deposit(<span class="hljs-number">10.0</span>);
            }
        };

        Runnable withdrawTask = () -&gt; {
            <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">1000</span>; i++) {
                account.withdraw(<span class="hljs-number">10.0</span>);
            }
        };

        Thread depositThread = <span class="hljs-keyword">new</span> Thread(depositTask);
        Thread withdrawThread = <span class="hljs-keyword">new</span> Thread(withdrawTask);

        depositThread.start();
        withdrawThread.start();

        <span class="hljs-keyword">try</span> {
            depositThread.join();
            withdrawThread.join();
        } <span class="hljs-keyword">catch</span> (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(<span class="hljs-string">"Final balance: "</span> + account.getBalance());
    }
}
</code></pre>
<p>In this example, two threads (<code>depositThread</code> and <code>withdrawThread</code>) are created to perform 1000 deposit and withdrawal operations, respectively, on the same <code>BankAccount</code> object. Without proper synchronization, the balance may not be accurately updated due to race conditions.</p>
<p>To prevent race conditions, the <code>deposit()</code> and <code>withdraw()</code> methods in the <code>BankAccount</code> class are marked as <code>synchronized</code>. This ensures that only one thread can execute these methods at a time, preventing concurrent access to the <code>balance</code> field and ensuring data consistency.</p>
<p>When you run this program, the final balance printed should be 1000.0 (the initial balance), since the number of deposits and withdrawals is equal.</p>
<p>These examples illustrate how Java's strong typing, persistence capabilities, and concurrency support help in building robust and reliable applications. Strong typing enforces type safety, persistence allows objects to survive beyond program execution, and concurrency enables parallel execution while providing mechanisms to handle shared resources safely.</p>
<hr />
<h1 id="heading-conclusion">Conclusion</h1>
<p>Throughout this blog, we've explored the fundamental concepts that underpin Object-Oriented Programming (OOP). We've delved into the building blocks of OOP, such as classes and objects, and how they enable the creation of modular, reusable, and extensible code.</p>
<p>We've examined the principles of abstraction and encapsulation, which provide a structured approach to managing complexity and ensuring data integrity. Abstraction allows us to focus on the essential features of an object, while encapsulation protects an object's internal state from unintended modifications.</p>
<p>Inheritance, a powerful mechanism in OOP, enables code reuse and the creation of hierarchical class relationships. By inheriting properties and methods from existing classes, we can create more specialized classes that extend and enhance the functionality of their parent classes.</p>
<p>Polymorphism, both compile-time and runtime, adds flexibility to our code by allowing objects of different classes to be treated as objects of a common superclass. This versatility enables methods to work with a wide range of object types without needing to know their specific implementations.</p>
<p>We've also explored the concept of strong typing, which enforces type safety and helps catch errors during compilation, leading to more robust and reliable code.</p>
<p>Additionally, we've discussed persistence, which allows objects to persist beyond the lifetime of the program, enabling data storage and retrieval across multiple sessions.</p>
<p>Finally, we've touched upon concurrency, a crucial aspect of modern software development, where multiple threads or processes can execute simultaneously, facilitating efficient utilization of system resources and improving application responsiveness.</p>
<p>By mastering these OOP concepts and applying them effectively, developers can create software that is not only functional but also maintainable, scalable, and adaptable to changing requirements. OOP provides a solid foundation for building complex systems, fostering collaboration, and promoting code reuse across projects.</p>
<p>As we continue our journey in OOP, remember to embrace best practices, such as writing clean and self-documenting code, adhering to design patterns, and leveraging the power of object-oriented principles to create efficient and elegant solutions.</p>
]]></content:encoded></item><item><title><![CDATA[Code, Cloud and Coffee: Deploying a MySQL, Spring and React application on AWS Free Tier with CI/CD through GitHub Actions]]></title><description><![CDATA[Introduction
Embarking on the AWS Free Tier journey, I set out to weave a tapestry of technology by deploying a full-stack application, combining the power of MySQL, Spring, and React. This blog serves as a chronicle of my exploration into the world ...]]></description><link>https://blog.saurabhmahajan.com/code-cloud-and-coffee-deploying-a-mysql-spring-and-react-application-on-aws-free-tier-with-cicd-through-github-actions</link><guid isPermaLink="true">https://blog.saurabhmahajan.com/code-cloud-and-coffee-deploying-a-mysql-spring-and-react-application-on-aws-free-tier-with-cicd-through-github-actions</guid><category><![CDATA[MySQL]]></category><category><![CDATA[Java]]></category><category><![CDATA[Springboot]]></category><category><![CDATA[Spring]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[TypeScript]]></category><category><![CDATA[React]]></category><category><![CDATA[AWS]]></category><category><![CDATA[rds]]></category><category><![CDATA[ec2]]></category><category><![CDATA[amplify]]></category><category><![CDATA[GitHub]]></category><category><![CDATA[github-actions]]></category><category><![CDATA[Docker]]></category><dc:creator><![CDATA[Saurabh Mahajan]]></dc:creator><pubDate>Sun, 03 Mar 2024 09:28:45 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1706989675414/41a953d6-441f-4ab8-853f-df958649a6c5.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<hr />
<h3 id="heading-introduction">Introduction</h3>
<p>Embarking on the AWS Free Tier journey, I set out to weave a tapestry of technology by deploying a full-stack application, combining the power of MySQL, Spring, and React. This blog serves as a chronicle of my exploration into the world of cloud computing, where budget constraints met the ambition to create a robust and dynamic web application.</p>
<p>In the realm of databases, I opted for Amazon RDS to host my MySQL database, leveraging its managed services to streamline administration tasks. On the backend, an EC2 instance powered by Spring provided the backbone for my application's logic and data processing. For the frontend, the user interface found its home on AWS Amplify, simplifying the deployment of my React application with a focus on scalability and ease of use.</p>
<p>This journey wasn't just about deploying code; it was a navigation through the intricate landscape of AWS services, striking a balance between functionality and frugality. Join me as I unravel the threads of my experience, sharing the triumphs, challenges, and lessons learned in the pursuit of a fully functional, cost-effective full-stack application on the AWS Free Tier. Let this be a guide for those venturing into the cloud, where innovation meets the constraints of a tight budget. Welcome to the story of MySQL, Spring, and React on AWS Free Tier.</p>
<hr />
<h3 id="heading-aws-services-used">AWS Services used</h3>
<p>For the database, I chose Amazon RDS (Relational Database Service) to manage the MySQL database. RDS simplifies database management with automated backups, patching, and scalability features. The benefits include reduced operational overhead, easy scalability, and enhanced security through encryption. However, the AWS Free Tier imposes limitations on instance types and storage, which may require monitoring to avoid additional charges.</p>
<p>On the server side, Amazon EC2 (Elastic Compute Cloud) was employed for hosting the Spring application on a docker container. EC2 provides scalable compute capacity with full control over virtual machines. This allows customization and flexibility in choosing instance types based on application needs. While the AWS Free Tier offers limited hours of t2.micro instances per month, additional charges may apply for data transfer and storage beyond the allotted limits.</p>
<p>For the frontend, AWS Amplify was selected to streamline React application deployment. Amplify simplifies the development process with automatic deployment, hosting on a global CDN, and a user-friendly CI/CD pipeline. Its benefits include quick setup and integration with other AWS services. However, limitations in build minutes and storage on the Free Tier, along with potential charges for data transfer out of the hosting environment, should be considered when utilizing Amplify for hosting the frontend.</p>
<hr />
<h3 id="heading-architecture">Architecture</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706990797454/2fee6cb6-abd1-4db3-b59d-f5713039e8be.png" alt class="image--center mx-auto" /></p>
<p>Our application's architecture is a sophisticated ecosystem designed for seamless interaction between its integral parts. The backbone of our backend data storage is the MySQL database hosted on Amazon RDS, offering scalability and managed services. Meanwhile, the application's logic resides in a Spring backend, encapsulated within a Docker container on an EC2 instance. This environment is orchestrated by Docker, intricately configuring the MySQL and the Spring application to communicate flawlessly over the EC2 and RDS.</p>
<p>The orchestration reaches its crescendo with the Continuous Integration and Continuous Deployment (CI/CD) workflow facilitated by GitHub Actions. Whenever code changes are pushed to our GitHub repository, the orchestrated symphony begins. A self-hosted runner on the EC2 instance takes center stage, fetching the latest changes and seamlessly updating our Spring backend. This ensures that our backend remains cutting-edge with every push.</p>
<p>Simultaneously, the frontend undergoes a transformation of its own. The React frontend code, residing in our GitHub repository, is automatically deployed to AWS Amplify, a platform offering scalable and managed hosting for our frontend. This dynamic deployment process guarantees that our users experience the most up-to-date version of our application without any manual intervention.</p>
<p>The Github Actions will utilize 3 workflows. First for Continuous Integration which will be triggered on every push to the repository, second for building the back-end app docker image and pushing it to our private dockerhub repository and the last one for continuous delivery which will begin execution when the second workflow completes execution. The continuous delivery workflow will be run on a self-hosted runner which will be running on the ec2 instance. It will pull the lastest uploaded backend app image and run it in a container.</p>
<p>In essence, this intricate dance of technologies integrates AWS services, Docker containerization, and robust CI/CD practices into a harmonious system. Each component plays a crucial role, contributing to the continuous deployment and enhancement of our full-stack application. This carefully orchestrated architecture not only ensures a smooth and automated workflow but also lays the foundation for a scalable and efficient application ecosystem.</p>
<hr />
<h3 id="heading-repository-structure">Repository Structure</h3>
<p>Link - <a target="_blank" href="https://github.com/saurabhthecodewizard/opus">https://github.com/saurabhthecodewizard/opus</a></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706993760577/b3cce7d5-eca4-4982-b4fe-69f68a0a74b4.png" alt class="image--center mx-auto" /></p>
<p>This is how the folder structure will look like for this example.</p>
<ol>
<li><p>The <code>server</code> folder will have spring application code.</p>
</li>
<li><p>The <code>client</code> folder will have react app code.</p>
</li>
<li><p>The <code>.github/workflows</code> will have the CI/CD workflows</p>
</li>
</ol>
<hr />
<h3 id="heading-rds-setup-for-database">RDS Setup for Database</h3>
<ol>
<li><p>Navigate to the AWS Management Console and open the Amazon RDS dashboard.</p>
</li>
<li><p>Click on the "Create database" button.</p>
</li>
<li><p>Choose the "Standard create" method.</p>
</li>
<li><p>In the "Engine options" section, select "MySQL" as the database engine and choose the latest engine version available.</p>
</li>
<li><p>Under "Templates," select "Free Tier" to ensure the usage falls within the free tier limits.</p>
</li>
<li><p>Provide a unique DB instance identifier of your choice.</p>
</li>
<li><p>Set a username and password for the database credentials, as these will be needed for connecting to the database.</p>
</li>
<li><p>Choose the "db.t4g.micro" instance type under "Free tier" to stay within the free tier limits.</p>
</li>
<li><p>For storage, select "gp2" as the storage type and select 20 GB storage since 20 GB is allocated for free tier, and uncheck the "Enable storage auto scaling" option.</p>
</li>
<li><p>In the "Connectivity" section, choose "Don't connect to an EC2 compute resource" and allow public access, as the database will be accessed locally and later from the EC2 instance.</p>
</li>
<li><p>Select the security group with EC2, RDS and AdministratorAccess.</p>
</li>
<li><p>Under the "Database authentication" section, choose "Password authentication."</p>
</li>
<li><p>In the "Additional configuration" section, uncheck "Automated backups," "Encryption," and "Minor version upgrade."</p>
</li>
<li><p>It may show you estimated cost, but we should be good as long as we are on free tier.</p>
</li>
<li><p>Finally, click on the "Create database" button to initiate the creation of the MySQL RDS instance.</p>
</li>
</ol>
<hr />
<h3 id="heading-development-setup">Development Setup</h3>
<ol>
<li><p>Develop a Spring application in the <code>server</code> folder with a simple API fetching data from the database, using the RDS database configuration (The RDS database url can be take from endpoint from RDS instance details and the username and password should be the one you setup during the RDS instance creation).</p>
</li>
<li><p>This project uses flyway migrations for versioning the database. More information can be found here - <a target="_blank" href="https://www.baeldung.com/database-migrations-with-flyway">https://www.baeldung.com/database-migrations-with-flyway</a></p>
</li>
</ol>
<pre><code class="lang-plaintext"># application.properties

# Database configuration
spring.datasource.url=${SPRING_DATASOURCE_URL}
spring.datasource.username=${SPRING_DATASOURCE_USERNAME}
spring.datasource.password=${SPRING_DATASOURCE_PASSWORD}
spring.jpa.show-sql=true
# Flyway configuration
spring.flyway.baseline-on-migrate=true
spring.flyway.locations=classpath:db/migration
</code></pre>
<ol>
<li>I have added a <code>clients</code> table and a single entity to it in the migration.</li>
</ol>
<pre><code class="lang-sql"><span class="hljs-comment">-- V1697817392__add_opus_to_clients.sql</span>
<span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> clients (
    <span class="hljs-keyword">id</span> <span class="hljs-built_in">SERIAL</span> PRIMARY <span class="hljs-keyword">KEY</span>,
    <span class="hljs-keyword">name</span> <span class="hljs-built_in">VARCHAR</span>(<span class="hljs-number">255</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
    create_date <span class="hljs-built_in">DATE</span>,
    <span class="hljs-keyword">status</span> <span class="hljs-built_in">TINYINT</span>(<span class="hljs-number">1</span>), <span class="hljs-comment">-- 1 for true (active), 0 for false (inactive)</span>
    website <span class="hljs-built_in">VARCHAR</span>(<span class="hljs-number">255</span>),
    picture_url <span class="hljs-built_in">VARCHAR</span>(<span class="hljs-number">255</span>)
);

<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> clients (<span class="hljs-keyword">name</span>, create_date, <span class="hljs-keyword">status</span>, website, picture_url)
<span class="hljs-keyword">VALUES</span> (<span class="hljs-string">'Opus'</span>, <span class="hljs-string">'2023-10-20'</span>, <span class="hljs-number">1</span>, <span class="hljs-string">'https://www.opus.com'</span>, <span class="hljs-string">'https://www.opus.com/image.jpg'</span>);
</code></pre>
<ol>
<li>Add an endpoint for us to test the application</li>
</ol>
<pre><code class="lang-java"><span class="hljs-comment">// Controller.java</span>

<span class="hljs-meta">@GetMapping("/")</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> ClientDTO <span class="hljs-title">getOpus</span><span class="hljs-params">()</span> </span>{
    <span class="hljs-keyword">return</span> clientService.getClientById(<span class="hljs-number">1L</span>);
}
</code></pre>
<p>The api should be working now which will fetch our client entity from the rds instance</p>
<hr />
<h3 id="heading-docker-setup-backend">Docker Setup - Backend</h3>
<ol>
<li>Create a <code>Dockerfile</code> to <code>./server</code> directory.</li>
</ol>
<pre><code class="lang-dockerfile"><span class="hljs-comment"># ./server/Dockerfile</span>
<span class="hljs-comment"># Use the Maven 3.9.5 image as the build environment</span>
<span class="hljs-keyword">FROM</span> maven:<span class="hljs-number">3.9</span>.<span class="hljs-number">5</span> AS build

<span class="hljs-comment"># Set the working directory within the container to /app</span>
<span class="hljs-keyword">WORKDIR</span><span class="bash"> /app</span>

<span class="hljs-comment"># Copy the content of the current directory into the /app directory in the container</span>
<span class="hljs-keyword">COPY</span><span class="bash"> . .</span>

<span class="hljs-comment"># Run Maven to clean and install dependencies</span>
<span class="hljs-keyword">RUN</span><span class="bash"> mvn clean install</span>

<span class="hljs-comment"># Use the OpenJDK 21 image as the base image for the final container</span>
<span class="hljs-keyword">FROM</span> openjdk:<span class="hljs-number">21</span>

<span class="hljs-comment"># Set the working directory within the container to /app</span>
<span class="hljs-keyword">WORKDIR</span><span class="bash"> /app</span>

<span class="hljs-comment"># Copy the compiled JAR file from the build stage to the /app directory in the final container</span>
<span class="hljs-keyword">COPY</span><span class="bash"> --from=build /app/target/*.jar server.jar</span>

<span class="hljs-comment"># Expose port 8080 to allow external connections</span>
<span class="hljs-keyword">EXPOSE</span> <span class="hljs-number">8080</span>

<span class="hljs-comment"># Define the default command to run the Java application</span>
<span class="hljs-keyword">CMD</span><span class="bash"> [<span class="hljs-string">"java"</span>, <span class="hljs-string">"-jar"</span>, <span class="hljs-string">"server.jar"</span>]</span>
</code></pre>
<p>You can test this by running the image locally by the following commands in the <code>./server</code> directory</p>
<ol>
<li>Build the server image</li>
</ol>
<pre><code class="lang-bash">docker build -t server .
</code></pre>
<ol>
<li><p>You can see if the image is built successfully by running <code>docker image ls</code> or in docker desktop app.</p>
</li>
<li><p>Run the image in container with appropriate port mapping and appropriate environment variables in the command</p>
</li>
</ol>
<pre><code class="lang-bash">docker run -d -p 8080:8080 -e SPRING_DATASOURCE_URL=<span class="hljs-variable">${DB_URL}</span> -e SPRING_DATASOURCE_USERNAME=<span class="hljs-variable">${DB_USERNAME}</span> -e SPRING_DATASOURCE_PASSWORD=<span class="hljs-variable">${DB_PASSWORD}</span> -e SPRING_MAIL_USERNAME=<span class="hljs-variable">${SPRING_MAIL_USERNAME}</span> -e SPRING_MAIL_PASSWORD=<span class="hljs-variable">${SPRING_MAIL_PASSWORD}</span> --name server-container server
</code></pre>
<p>You can see the container running <code>docker container ls</code> or in the docker desktop app.</p>
<hr />
<h3 id="heading-github-secrets">Github Secrets</h3>
<p>Add the following github secrets which we will be using in our workflows for CI/CD as shown in the picture below.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1707042491827/844c9778-028d-42bb-b10f-c1a9c508652e.png" alt class="image--center mx-auto" /></p>
<hr />
<h3 id="heading-github-actions-setup">Github Actions Setup</h3>
<p>We will be creating 3 files in the <code>.github/workflows</code> directory.</p>
<ol>
<li><p>Continuous Integration - <code>server-intergartion.yml</code> :-</p>
<p> This GitHub Actions workflow file named "Server Integration" is triggered on each push event. The workflow runs on the latest version of Ubuntu and is configured to execute within the 'server/' directory. It sets environment variables for sensitive information such as database connection details and email credentials using GitHub Secrets. The workflow consists of three main steps: it checks out the source code, sets up Java 17 using the Temurin distribution, and builds the project using Maven. The Maven build command includes parameters for configuring the Spring datasource URL, username, password, as well as the email username and password, all sourced from the environment variables. This workflow is designed for integrating and building a Java server application with secure and customizable database and email configurations.</p>
<pre><code class="lang-yaml"> <span class="hljs-comment"># .github/workflows/server-intergartion.yml</span>

 <span class="hljs-attr">name:</span> <span class="hljs-string">Server</span> <span class="hljs-string">Integration</span>

 <span class="hljs-attr">on:</span> [<span class="hljs-string">push</span>]

 <span class="hljs-attr">jobs:</span>

   <span class="hljs-attr">build:</span>

     <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>
     <span class="hljs-attr">defaults:</span>
       <span class="hljs-attr">run:</span>
         <span class="hljs-attr">working-directory:</span> <span class="hljs-string">server/</span>
     <span class="hljs-attr">env:</span>
         <span class="hljs-attr">DB_URL:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.DB_URL</span> <span class="hljs-string">}}</span>
         <span class="hljs-attr">DB_USERNAME:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.DB_USERNAME</span> <span class="hljs-string">}}</span>
         <span class="hljs-attr">DB_PASSWORD:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.DB_PASSWORD</span> <span class="hljs-string">}}</span>
         <span class="hljs-attr">SPRING_MAIL_USERNAME:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.SPRING_MAIL_USERNAME</span> <span class="hljs-string">}}</span>
         <span class="hljs-attr">SPRING_MAIL_PASSWORD:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.SPRING_MAIL_PASSWORD</span> <span class="hljs-string">}}</span>
     <span class="hljs-attr">steps:</span>
     <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Checkout</span> <span class="hljs-string">source</span>
       <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v3</span>
     <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Setup</span> <span class="hljs-string">Java</span>
       <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/setup-java@v3</span>
       <span class="hljs-attr">with:</span>
         <span class="hljs-attr">distribution:</span> <span class="hljs-string">'temurin'</span>
         <span class="hljs-attr">java-version:</span> <span class="hljs-string">'17'</span>
     <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Build</span> <span class="hljs-string">Project</span>
       <span class="hljs-attr">run:</span> <span class="hljs-string">mvn</span> <span class="hljs-string">clean</span> <span class="hljs-string">install</span> <span class="hljs-string">-D</span> <span class="hljs-string">spring.datasource.url=${DB_URL}</span> <span class="hljs-string">-D</span> <span class="hljs-string">spring.datasource.username=${DB_USERNAME}</span> <span class="hljs-string">-D</span> <span class="hljs-string">spring.datasource.password=${DB_PASSWORD}</span> <span class="hljs-string">-D</span> <span class="hljs-string">spring.mail.username=${SPRING_MAIL_USERNAME}</span> <span class="hljs-string">-D</span> <span class="hljs-string">spring.mail.password=${SPRING_MAIL_PASSWORD}</span> <span class="hljs-string">-B</span>
</code></pre>
</li>
<li><p>Server Build - <code>server-build.yml</code> :-</p>
<p> This GitHub Actions workflow file, named "Server Build," is configured to run on a manual workflow_dispatch event. The workflow is designed to build a Java server application and deploy it as a Docker image to Docker Hub. It runs on the latest version of Ubuntu, within the 'server/' directory. It utilizes environment variables, sourced from GitHub Secrets, for sensitive information such as Docker Hub credentials, database connection details, and email credentials. The workflow includes several steps: it checks out the source code, sets up Java 17 using the Temurin distribution, builds the project with Maven, logs in to Docker Hub, builds a Docker image tagged as 'skmahajan4998/opus-app:latest,' pushes the image to Docker Hub, and finally, deletes dangling Docker images to free up space. This workflow automates the process of building and deploying the server application with Docker, ensuring secure and efficient deployment practices.</p>
<pre><code class="lang-yaml"> <span class="hljs-comment"># .github/workflows/server-build.yml</span>

 <span class="hljs-attr">name:</span> <span class="hljs-string">Server</span> <span class="hljs-string">Build</span>

 <span class="hljs-attr">on:</span> <span class="hljs-string">workflow_dispatch</span>

 <span class="hljs-attr">jobs:</span>

   <span class="hljs-attr">build:</span>

     <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>
     <span class="hljs-attr">defaults:</span>
       <span class="hljs-attr">run:</span>
         <span class="hljs-attr">working-directory:</span> <span class="hljs-string">server/</span>
     <span class="hljs-attr">env:</span>
       <span class="hljs-attr">DOCKER_USERNAME:</span> <span class="hljs-string">${{secrets.DOCKER_USERNAME}}</span>
       <span class="hljs-attr">DOCKER_PASSWORD:</span> <span class="hljs-string">${{secrets.DOCKER_PASSWORD}}</span>
       <span class="hljs-attr">DB_URL:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.DB_URL</span> <span class="hljs-string">}}</span>
       <span class="hljs-attr">DB_USERNAME:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.DB_USERNAME</span> <span class="hljs-string">}}</span>
       <span class="hljs-attr">DB_PASSWORD:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.DB_PASSWORD</span> <span class="hljs-string">}}</span>
     <span class="hljs-attr">steps:</span>
     <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Checkout</span> <span class="hljs-string">source</span>
       <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v3</span>
     <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Setup</span> <span class="hljs-string">Java</span>
       <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/setup-java@v3</span>
       <span class="hljs-attr">with:</span>
         <span class="hljs-attr">distribution:</span> <span class="hljs-string">'temurin'</span>
         <span class="hljs-attr">java-version:</span> <span class="hljs-string">'17'</span>
     <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Build</span> <span class="hljs-string">Project</span>
       <span class="hljs-attr">run:</span> <span class="hljs-string">mvn</span> <span class="hljs-string">clean</span> <span class="hljs-string">install</span> <span class="hljs-string">-D</span> <span class="hljs-string">spring.datasource.url=${DB_URL}</span> <span class="hljs-string">-D</span> <span class="hljs-string">spring.datasource.username=${DB_USERNAME}</span> <span class="hljs-string">-D</span> <span class="hljs-string">spring.datasource.password=${DB_PASSWORD}</span> <span class="hljs-string">-B</span>
     <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Login</span> <span class="hljs-string">Dockerhub</span>
       <span class="hljs-attr">run:</span> <span class="hljs-string">docker</span> <span class="hljs-string">login</span> <span class="hljs-string">-u</span> <span class="hljs-string">$DOCKER_USERNAME</span> <span class="hljs-string">-p</span> <span class="hljs-string">$DOCKER_PASSWORD</span>
     <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Build</span> <span class="hljs-string">the</span> <span class="hljs-string">Docker</span> <span class="hljs-string">image</span>
       <span class="hljs-attr">run:</span> <span class="hljs-string">docker</span> <span class="hljs-string">build</span> <span class="hljs-string">-t</span> <span class="hljs-string">skmahajan4998/opus-app</span> <span class="hljs-string">.</span>
     <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Push</span> <span class="hljs-string">to</span> <span class="hljs-string">Dockerhub</span>
       <span class="hljs-attr">run:</span> <span class="hljs-string">docker</span> <span class="hljs-string">push</span> <span class="hljs-string">skmahajan4998/opus-app:latest</span>
     <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Delete</span> <span class="hljs-string">Dangling</span> <span class="hljs-string">docker</span> <span class="hljs-string">images</span>
       <span class="hljs-attr">run:</span> <span class="hljs-string">docker</span> <span class="hljs-string">image</span> <span class="hljs-string">prune</span> <span class="hljs-string">-f</span>
</code></pre>
</li>
<li><p>Continuous Deployment - <code>server-deploy.yml</code> :-</p>
<p> This GitHub Actions workflow file, named "Server Deploy," is triggered on the completion of the "Server Build" workflow. It runs on a self-hosted runner which will be hosted on our ec2 instance and is responsible for pulling the latest Docker image of the server application from Docker Hub, stopping and removing any existing container with the name 'opus-app-container,' and then running a new container with the pulled image. The environment variables for database connection details and email credentials are provided to the Docker container during the run. Specifically, the Docker container is started in detached mode (-d), mapped to port 8080 on the host, and named 'opus-app-container.' This workflow facilitates the deployment of the server application by updating the running container with the latest version of the application, ensuring a smooth and automated deployment process after the successful completion of the build workflow.</p>
<pre><code class="lang-yaml"> <span class="hljs-comment"># </span>
 <span class="hljs-attr">name:</span> <span class="hljs-string">Server</span> <span class="hljs-string">Deploy</span>

 <span class="hljs-attr">on:</span>
   <span class="hljs-attr">workflow_run:</span>
     <span class="hljs-attr">workflows:</span> [<span class="hljs-string">"Server Build"</span>]
     <span class="hljs-attr">types:</span>
       <span class="hljs-bullet">-</span> <span class="hljs-string">completed</span>

 <span class="hljs-attr">jobs:</span>

   <span class="hljs-attr">pull:</span>
     <span class="hljs-attr">runs-on:</span> <span class="hljs-string">self-hosted</span>
     <span class="hljs-attr">env:</span>
       <span class="hljs-attr">DB_URL:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.DB_URL</span> <span class="hljs-string">}}</span>
       <span class="hljs-attr">DB_USERNAME:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.DB_USERNAME</span> <span class="hljs-string">}}</span>
       <span class="hljs-attr">DB_PASSWORD:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.DB_PASSWORD</span> <span class="hljs-string">}}</span>
     <span class="hljs-attr">steps:</span>
     <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Pull</span> <span class="hljs-string">Docker</span> <span class="hljs-string">Image</span>
       <span class="hljs-attr">run:</span> <span class="hljs-string">sudo</span> <span class="hljs-string">docker</span> <span class="hljs-string">pull</span> <span class="hljs-string">skmahajan4998/opus-app:latest</span>
     <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Delete</span> <span class="hljs-string">Old</span> <span class="hljs-string">Docker</span> <span class="hljs-string">Container</span>
       <span class="hljs-attr">run:</span> <span class="hljs-string">sudo</span> <span class="hljs-string">docker</span> <span class="hljs-string">rm</span> <span class="hljs-string">-f</span> <span class="hljs-string">opus-app-container</span> <span class="hljs-string">||</span> <span class="hljs-literal">true</span>
     <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Run</span> <span class="hljs-string">Docker</span> <span class="hljs-string">Container</span>
       <span class="hljs-attr">run:</span> <span class="hljs-string">sudo</span> <span class="hljs-string">docker</span> <span class="hljs-string">run</span> <span class="hljs-string">-d</span> <span class="hljs-string">-p</span> <span class="hljs-number">8080</span><span class="hljs-string">:8080</span> <span class="hljs-string">-e</span> <span class="hljs-string">SPRING_DATASOURCE_URL=${DB_URL}</span> <span class="hljs-string">-e</span> <span class="hljs-string">SPRING_DATASOURCE_USERNAME=${DB_USERNAME}</span> <span class="hljs-string">-e</span> <span class="hljs-string">SPRING_DATASOURCE_PASSWORD=${DB_PASSWORD}</span> <span class="hljs-string">--name</span> <span class="hljs-string">opus-app-container</span> <span class="hljs-string">skmahajan4998/opus-app</span>
</code></pre>
</li>
</ol>
<hr />
<h3 id="heading-ec2-setup-for-back-end">EC2 setup for back-end</h3>
<ol>
<li><p>Sign in to the AWS Management Console.</p>
</li>
<li><p>Open the EC2 dashboard.</p>
</li>
<li><p>Click on the "Instances" link in the left navigation pane.</p>
</li>
<li><p>Click the "Launch Instances" button.</p>
</li>
<li><p>Select Ubuntu Server</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706992111058/128edecb-11ec-4a83-9caf-181e4eb56509.png" alt class="image--center mx-auto" /></p>
<ol>
<li>Select <code>t2.micro</code> to stay in the free tier</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706992298709/54c736ed-2711-4b12-9308-4b95fd083de4.png" alt class="image--center mx-auto" /></p>
<ol>
<li>Create a Key pair of <code>.pem</code> type so we can login through SSH</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706992135304/66bc21bc-a789-4b45-b3da-688d66af97ae.png" alt class="image--center mx-auto" /></p>
<ol>
<li><p>Allow HTTP/HTTPS traffic from internet.</p>
</li>
<li><p>Launch the instance.</p>
</li>
<li><p>Change the inbound rules as given below</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706992174841/82482db0-f4b8-47bd-87f6-e06d0bd8a15b.png" alt class="image--center mx-auto" /></p>
<hr />
<h3 id="heading-github-runner-setup-on-ec2">Github Runner setup on EC2</h3>
<ol>
<li><p>Navigate to <code>.pem</code> file</p>
<pre><code class="lang-bash"> <span class="hljs-built_in">cd</span> /path/to/directory/with/pem/file
</code></pre>
</li>
<li><p>Connect to EC2 instance through SSH client</p>
<p> Replace <code>your-instance-ip</code> with the actual public IP address of your EC2 instance and <code>your-key-file.pem</code> with the name of your .pem file. You can find this command when you click on connect instance and navigate to SSH client on AWS management console.</p>
<pre><code class="lang-bash"> chmod 400 <span class="hljs-string">"your-key-file.pem"</span>
 ssh -i <span class="hljs-string">"your-key-file.pem"</span> ubuntu@your-instance-ip
</code></pre>
<p> If there are no errors, you should successfully establish a connection to your EC2 instance.</p>
</li>
<li><p>Update the package list on your EC2 instance</p>
<pre><code class="lang-bash"> sudo apt update
</code></pre>
</li>
<li><p>Upgrade the installed packages on your EC2 instance. The <code>-y</code> flag automatically confirms the upgrade.</p>
<pre><code class="lang-bash"> sudo apt-get upgrade -y
</code></pre>
<p> The upgrade process should now be complete, and your EC2 instance is up-to-date.</p>
</li>
<li><p>Create Github Runner</p>
<ul>
<li><p>Navigate to Github Repository -&gt; <code>Settings</code> -&gt; <code>Actions</code> -&gt; <code>Runners</code>.</p>
</li>
<li><p>Click on <code>Add a runner</code> and select <code>linux</code> OS</p>
</li>
<li><p>You should be able to see commands in 2 sections, namely, <code>Download</code> and <code>Configure</code></p>
</li>
<li><p>Ensure that you have Github secrets setup as shown in the Github Secrets section</p>
</li>
</ul>
</li>
<li><p>Run all the commands provided through the <code>Downlaod</code> and <code>Configure</code> section of the github runner on our EC2 instance that we previously connected through SSH client.</p>
</li>
<li><p>Run the <code>./</code><a target="_blank" href="http://run.sh"><code>run.sh</code></a> script in the background using the <code>&amp;</code> operator to keep the process running in the background while freeing up the terminal.</p>
</li>
<li><p>Confirm runner connection</p>
<ul>
<li><p>Go back to your GitHub repository.</p>
</li>
<li><p>Navigate to <code>Settings</code> -&gt; <code>Actions</code> -&gt; <code>Runners</code>.</p>
</li>
<li><p>Refresh the page to check if the runner is connected.</p>
</li>
<li><p>The runner status should show as <code>Idle</code> with a green dot, indicating that it is ready to execute workflows.</p>
</li>
<li><p>You can also check the terminal where you ran the runner script to ensure there are no errors and that the runner is connected successfully.</p>
</li>
<li><p>Your GitHub Runner should now be set up, configured, and connected to your repository. It is ready to execute workflows when triggered.</p>
</li>
</ul>
</li>
<li><p>Install Docker on EC2 instance</p>
<ul>
<li><p>Run the commands provided on the documentation - <a target="_blank" href="https://docs.docker.com/engine/install/ubuntu/">https://docs.docker.com/engine/install/ubuntu/</a></p>
</li>
<li><p>Login to docker with your credentials</p>
<pre><code class="lang-bash">  sudo docker login
</code></pre>
</li>
<li><p>No containers will be present currently. You can check by the below command.</p>
<pre><code class="lang-bash">  sudo docker ps
</code></pre>
</li>
</ul>
</li>
<li><p>Trigger the CI/CD flow</p>
</li>
</ol>
<ul>
<li><p>Push our code to the repository (This should automatically trigger the <code>Server Build</code> workflow).</p>
</li>
<li><p>Trigger the <code>Server Build</code> workflow manually through github actions.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1707044748054/ec6b5308-d90b-4dae-817a-cbbd7e2711f3.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>The successful completion of <code>Server Build</code> workflow should automatically trigger the <code>Server Deploy</code> workflow.<br />  Note: If you have any errors in the server build or server integration, you will have to solve those locally and then trigger the CI/CD again.</p>
</li>
<li><p>Your latest server build should now be successfully deployed on the EC2 instance and you can check by triggering the api we provided.</p>
<pre><code class="lang-bash">  curl 0.0.0.0:8080/
</code></pre>
</li>
<li><p>You can also check the depoloyment by calling the api through browser with appropriate url. You can get the public IP from instance details and the rest of the api url as you configured in the spring application.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1707045211041/30f0a4f3-1287-4b4b-948b-3a70af1bc5cb.png" alt class="image--center mx-auto" /></p>
</li>
</ul>
<hr />
<h3 id="heading-setup-nginx-server-on-ec2-for-proxy">Setup nginx server on EC2 for proxy</h3>
<p>Run the following commands on EC2 instance</p>
<ol>
<li><p>Install nginx</p>
<pre><code class="lang-bash"> sudo apt update
 sudo apt install -y nginx
</code></pre>
</li>
<li><p>Get Docker container IP<br /> Find the IP address of your Docker container using the following command. Replace <code>containerId</code> with the actual ID. You can find the docker container id by running <code>docker container ps</code>.</p>
<pre><code class="lang-bash"> docker inspect -f <span class="hljs-string">'{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}'</span> containerId
</code></pre>
</li>
<li><p>Navigate to nginx sites-available directory</p>
<pre><code class="lang-bash"> <span class="hljs-built_in">cd</span> /etc/nginx/sites-available/
</code></pre>
</li>
<li><p>Edit the default configuration</p>
<pre><code class="lang-bash"> sudo nano default
</code></pre>
</li>
<li><p>In the <code>location / { ... }</code> block, add the following line with the appropriate IP address and port:</p>
<pre><code class="lang-bash"> location / {
     proxy_pass http://172.17.0.2:8080;  <span class="hljs-comment"># Replace with your Docker container's IP and port</span>
     <span class="hljs-comment"># Other proxy settings can be added here if needed</span>
 }
</code></pre>
</li>
<li><p>Restart nginx</p>
<pre><code class="lang-bash"> sudo systemctl restart nginx
</code></pre>
</li>
<li><p>Check the Nginx configuration for syntax errors</p>
<pre><code class="lang-bash"> sudo nginx -t
</code></pre>
<p> If there are no errors, you should see <code>nginx: configuration file /etc/nginx/nginx.conf test is successful</code>.</p>
</li>
<li><p>Nginx is now configured as a reverse proxy for your Docker container. Requests to the Nginx server will be forwarded to the Docker container. Make sure to replace the placeholder IP address and port with the actual values from step 2.</p>
</li>
</ol>
<hr />
<h3 id="heading-setup-https-on-ec2">Setup HTTPS on EC2</h3>
<p>You can setup HTTPS on EC2 if you have custom domain. Follow this process if you do not have custom domain.</p>
<ol>
<li><p>Now, install <a target="_blank" href="https://caddyserver.com/">Caddy</a> on the server. Instructions can be <a target="_blank" href="https://caddyserver.com/docs/install">found here</a>. Caddy 2 is a powerful open source web server with automatic HTTPS. Caddy simplifies your infrastructure and takes care of TLS certificate renewals.</p>
<pre><code class="lang-bash"> yum install yum-plugin-copr
 yum copr <span class="hljs-built_in">enable</span> @caddy/caddy
 yum install caddy
</code></pre>
</li>
<li><p>Next we'll create a <code>Caddyfile</code> with the following contents(Insert your ec2 public ip).</p>
<pre><code class="lang-bash"> &lt;EC2 Public IP&gt;.nip.io {
     reverse_proxy localhost:8080
 }
</code></pre>
<p> Over here, we are using <a target="_blank" href="http://nip.io">nip.io</a> as a DNS. nip.io allows you to map any IP Address to a hostname without the need to edit a hosts file or create rules in DNS management. <a target="_blank" href="http://nip.io">nip.io</a> maps <a target="_blank" href="http://.nip.io">.</a><a target="_blank" href="http://nip.io">nip.io</a> in "dot", "dash" or "hexadecimal" notation to the corresponding .</p>
<p> What we are doing here is basically setting up a proxy to forward all requests to port 8000 of our instance. Save the file as <code>Caddyfile</code> and run the command <code>caddy run</code>.</p>
<p> This will start Caddy certificate management service and download a certificate for the indentifier <code>&lt;IP&gt;.</code><a target="_blank" href="http://nip.io"><code>nip.io</code></a>.</p>
<p> Now if you go to your address <code>&lt;IP&gt;.</code><a target="_blank" href="http://nip.io"><code>nip.io</code></a> with the ec2 url in the browser you'll see that the connection is secure and the browser no longer complains about insecure connections.</p>
<p> If you want to run Caddy in background all you have to do is run <code>caddy start</code>.</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1707046510274/a78df149-1b9f-464c-ac70-f8300593c71a.png" alt class="image--center mx-auto" /></p>
</li>
</ol>
<hr />
<h3 id="heading-front-end-setup-on-aws-amplify">Front-end setup on AWS Amplify</h3>
<ol>
<li><p>Create a basic react app and consume the api we created in the Spring application with the ec2 URL</p>
</li>
<li><p>Navigate to AWS Amplify on AWS management console.</p>
</li>
<li><p>New app -&gt; Host a web app</p>
</li>
<li><p>Select Github</p>
</li>
<li><p>Authorize the repository -&gt; Select your repository -&gt; Select your branch</p>
</li>
<li><p>(Optional) -&gt; If the frontend application is not in the root directory, mention the correct directory of the app in the folder section</p>
</li>
<li><p>Next -&gt; Next -&gt; Save and Deploy</p>
</li>
</ol>
<p>Note: You may need to make changes to the build commands or your react app based on the packages and libraries you are using</p>
<ol>
<li><p>You can setup the backend url in environment variables in amplify if you want</p>
</li>
<li><p>Your app is now live</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1707047088890/d6c3a53b-7705-4a54-8396-55b22780073b.png" alt class="image--center mx-auto" /></p>
<hr />
<h3 id="heading-conclusion">Conclusion</h3>
<p>In conclusion, the journey of deploying a full-stack application on AWS Free Tier was a dynamic exploration that delved into the intricacies of cloud architecture and development. The experience not only involved the successful deployment of MySQL on RDS, Spring on EC2, and React on AWS Amplify but also incorporated a streamlined CI/CD pipeline. The backend server benefited from GitHub Actions, ensuring continuous integration and deployment, while AWS Amplify seamlessly handled the CI/CD for the frontend.</p>
<p>As I reflect on the project, it's clear that the CI/CD setup significantly contributed to the overall efficiency of development and deployment processes. GitHub Actions provided a robust solution for automating backend deployments, while AWS Amplify's integration with the frontend codebase streamlined the continuous delivery workflow. The synergy between these tools not only enhanced the development speed but also facilitated a more consistent and reliable release cycle.</p>
<p>While navigating through the intricacies of AWS services, I gained insights into best practices for cloud development, security considerations, and the critical role of scalability. The process wasn't without its hurdles, but each challenge presented an opportunity for growth and learning.</p>
<p>Sharing these experiences serves not only as a documentation of my journey but also as a guide for fellow developers venturing into the realm of AWS. By reflecting on the lessons learned and embracing the continuous learning ethos of cloud development, I believe the community can benefit from a shared knowledge pool that empowers developers to make informed decisions and build robust, scalable applications on AWS Free Tier.</p>
]]></content:encoded></item><item><title><![CDATA[Dockerizing a Fullstack Application crafted in MySQL, Spring Boot & React with Docker Compose]]></title><description><![CDATA[Welcome to the core of modern development practices, where Docker Compose orchestrates a symphony for your fullstack app. As a dynamic Fullstack Software Engineer, you grasp the pivotal role containerization plays in shaping software development.
Thi...]]></description><link>https://blog.saurabhmahajan.com/dockerizing-a-fullstack-application-crafted-in-mysql-spring-boot-react-with-docker-compose</link><guid isPermaLink="true">https://blog.saurabhmahajan.com/dockerizing-a-fullstack-application-crafted-in-mysql-spring-boot-react-with-docker-compose</guid><category><![CDATA[MySQL]]></category><category><![CDATA[Java]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[TypeScript]]></category><category><![CDATA[Springboot]]></category><category><![CDATA[Spring framework]]></category><category><![CDATA[React]]></category><category><![CDATA[Docker]]></category><category><![CDATA[Docker compose]]></category><category><![CDATA[Dockerfile]]></category><category><![CDATA[docker-network]]></category><category><![CDATA[containers]]></category><category><![CDATA[images]]></category><dc:creator><![CDATA[Saurabh Mahajan]]></dc:creator><pubDate>Wed, 14 Feb 2024 20:10:10 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1706115113114/727a9d78-9507-4b47-8c1d-8a260ea96abb.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Welcome to the core of modern development practices, where Docker Compose orchestrates a symphony for your fullstack app. As a dynamic Fullstack Software Engineer, you grasp the pivotal role containerization plays in shaping software development.</p>
<p>This blog is your guide to unlocking Docker Compose's potential in building a fullstack app with MySQL, Spring Boot, and React. Docker Compose acts as the linchpin, streamlining the encapsulation, and management of each component.</p>
<p>We'll navigate setting up a development environment within Docker containers, explore the relationship between database design and Dockerized Spring Boot backends, and witness the magic of containerized React frontends. At every step, Docker Compose ensures cohesion and consistency across the development lifecycle.</p>
<p>Whether you're refining containerization skills or demystifying Docker, this blog empowers both seasoned developers and curious enthusiasts. Join us as we unravel Docker Compose's potential, elevating your fullstack development experience.</p>
<p>Fasten your seatbelt, and let’s sail through the realms of Docker Compose-driven fullstack development. 🚢✨</p>
<hr />
<h3 id="heading-what-are-containers-and-how-docker-comes-into-picture">What are containers and how docker comes into picture?</h3>
<p>Containers are lightweight, portable, and self-sufficient units that encapsulate software and its dependencies. They provide a consistent and isolated environment for running applications, allowing developers to package an application along with its dependencies, libraries, and runtime into a single container image. Containers are designed to be easily deployable across various environments, ensuring consistency from development to production.</p>
<p>Docker is a platform that enables the creation, deployment, and management of containers. It utilizes containerization technology to package applications and their dependencies into containers. Docker provides a set of tools and a runtime environment to build, ship, and run containers efficiently.</p>
<p>The typical Docker workflow involves creating a Dockerfile, which defines the steps to build a container image, and then using Docker commands to build, tag, and run containers based on that image. Docker Hub is a registry service provided by Docker, where container images can be stored and shared publicly or privately.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706117242052/8a50e986-4204-4b20-b6df-9c8e0aad4417.png" alt class="image--center mx-auto" /></p>
<hr />
<h3 id="heading-what-does-docker-compose-do">What does docker compose do?</h3>
<p>Docker Compose is a tool for defining and running multi-container Docker applications. It allows you to define a multi-container environment using a simple YAML file, often named <code>docker-compose.yml</code>, and then use a single command to start and run the entire application stack. Docker Compose is particularly useful for managing the orchestration of complex applications that require multiple services and containers to work together.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706117354917/eb68b9a2-cc7c-430a-a12e-e8af5734be6e.png" alt class="image--center mx-auto" /></p>
<p>Here are some key aspects and functionalities of Docker Compose:</p>
<ol>
<li><p><strong>Declarative Configuration:</strong> Docker Compose uses a declarative YAML file to define the services, networks, and volumes required for your application. This file specifies how containers should be configured and how they should interact.</p>
</li>
<li><p><strong>Service Definition:</strong> Each containerized component of your application is defined as a service in the <code>docker-compose.yml</code> file. Services can include information such as the base Docker image, container name, ports to expose, environment variables, and more.</p>
</li>
<li><p><strong>Networking:</strong> Docker Compose automatically creates a network for your services, allowing containers within the same <code>docker-compose.yml</code> file to communicate with each other using service names as hostnames.</p>
</li>
<li><p><strong>Volume Sharing:</strong> You can define volumes in the <code>docker-compose.yml</code> file, enabling data persistence and sharing between containers. This is useful for scenarios where you want to persist data beyond the lifecycle of a single container.</p>
</li>
<li><p><strong>Environment Variables:</strong> Docker Compose allows you to set environment variables for each service, making it easy to configure different aspects of your application without modifying the container images.</p>
</li>
<li><p><strong>Orchestration and Scaling:</strong> Docker Compose simplifies the process of orchestrating multiple containers. You can start, stop, and scale your entire application with a single command. This makes it convenient for development, testing, and even production environments.</p>
</li>
<li><p><strong>Ease of Use:</strong> Docker Compose provides a user-friendly command-line interface, making it accessible to both developers and system administrators. Common operations like starting, stopping, and inspecting the status of services are straightforward.</p>
</li>
</ol>
<hr />
<h3 id="heading-pre-requisites">Pre-requisites</h3>
<ol>
<li><p>Install Docker</p>
<ul>
<li><p><a target="_blank" href="https://docs.docker.com/desktop/install/windows-install/">Windows</a></p>
</li>
<li><p><a target="_blank" href="https://docs.docker.com/desktop/install/mac-install/">Mac</a></p>
</li>
<li><p><a target="_blank" href="https://docs.docker.com/engine/install/ubuntu/">Ubuntu</a></p>
</li>
</ul>
</li>
<li><p>Install Docker Compose if not already installed through the Docker installation above</p>
<pre><code class="lang-bash"> &gt;docker -v 
 Docker version 24.0.7, build afdd53b
 &gt;docker-compose -v
 Docker Compose version v2.23.3-desktop.2
</code></pre>
</li>
<li><p>Java &amp; Maven - The example in this blog uses Java v21 and Maven v3.9.5</p>
</li>
<li><p>Node - The example in this blog uses node v18</p>
</li>
<li><p>The project structure used for the example in this blog is as follows:-</p>
<p> <a target="_blank" href="https://github.com/saurabhthecodewizard/docker-compose-demo">docker-compose-demo</a></p>
<p> |</p>
<p> |____bac<a target="_blank" href="https://github.com/saurabhthecodewizard/docker-compose-demo">kend</a></p>
<p> <a target="_blank" href="https://github.com/saurabhthecodewizard/docker-compose-demo">|</a></p>
<p> <a target="_blank" href="https://github.com/saurabhthecodewizard/docker-compose-demo">|____frontend</a></p>
</li>
</ol>
<hr />
<h3 id="heading-shttpsgithubcomsaurabhthecodewizarddocker-compose-demoetup-a-spring-application-with-docker-configuration"><a target="_blank" href="https://github.com/saurabhthecodewizard/docker-compose-demo">S</a>etup a spring application with docker configuration</h3>
<ol>
<li><p>Create a Spring project with appropriate dependencies like Spring Web, Spring Data JPA and MySQL Driver.</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706132460301/0c4de3df-2600-4370-b722-739bfb8dba2a.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>Insert your MySQL configuration in the application properties</p>
<pre><code class="lang-plaintext"> spring.datasource.url=jdbc:mysql://localhost:3306/product
 spring.datasource.username=product
 spring.datasource.password=password
 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
 spring.jpa.hibernate.ddl-auto=update
</code></pre>
<pre><code class="lang-java"> <span class="hljs-comment">// Product.java</span>
 <span class="hljs-meta">@Entity</span>
 <span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Product</span> </span>{

     <span class="hljs-meta">@Id</span>
     <span class="hljs-meta">@GeneratedValue(strategy = GenerationType.IDENTITY)</span>
     <span class="hljs-keyword">private</span> Long id;
     <span class="hljs-keyword">private</span> String name;
     <span class="hljs-keyword">private</span> <span class="hljs-keyword">double</span> price;

     <span class="hljs-comment">// constructors, getters and setters</span>
 }
</code></pre>
<pre><code class="lang-java"> <span class="hljs-comment">// ProductController.java</span>

 <span class="hljs-meta">@RestController</span>
 <span class="hljs-meta">@RequestMapping("/api/products")</span>
 <span class="hljs-meta">@CrossOrigin("*")</span>
 <span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ProductController</span> </span>{

     <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> ProductService productService;

     <span class="hljs-meta">@Autowired</span>
     <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">ProductController</span><span class="hljs-params">(ProductService productService)</span> </span>{
         <span class="hljs-keyword">this</span>.productService = productService;
     }

     <span class="hljs-meta">@GetMapping</span>
     <span class="hljs-function"><span class="hljs-keyword">public</span> List&lt;ResponseProductDTO&gt; <span class="hljs-title">getAllProducts</span><span class="hljs-params">()</span> </span>{
         <span class="hljs-keyword">return</span> productService.getAllProducts();
     }

     <span class="hljs-meta">@GetMapping("/{id}")</span>
     <span class="hljs-function"><span class="hljs-keyword">public</span> ResponseProductDTO <span class="hljs-title">getProductById</span><span class="hljs-params">(<span class="hljs-meta">@PathVariable</span> Long id)</span> </span>{
         <span class="hljs-keyword">return</span> productService.getProductById(id);
     }

     <span class="hljs-meta">@PostMapping</span>
     <span class="hljs-function"><span class="hljs-keyword">public</span> ResponseProductDTO <span class="hljs-title">saveProduct</span><span class="hljs-params">(<span class="hljs-meta">@RequestBody</span> RequestProductDTO product)</span> </span>{
         <span class="hljs-keyword">return</span> productService.saveProduct(product);
     }

     <span class="hljs-meta">@DeleteMapping("/{id}")</span>
     <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">deleteProduct</span><span class="hljs-params">(<span class="hljs-meta">@PathVariable</span> Long id)</span> </span>{
         productService.deleteProduct(id);
     }
 }
</code></pre>
</li>
<li><p>The back-end should be running at http://localhost:8080</p>
</li>
</ol>
<hr />
<h3 id="heading-setup-a-react-application-with-docker-configuration">Setup a React application with docker configuration</h3>
<ol>
<li><p>Create a react app and install axios to call apis</p>
<pre><code class="lang-bash"> npm create vite@latest .
 <span class="hljs-comment"># Select React + TypeScript </span>
 npm install
 npm install axios
 npm run dev
</code></pre>
</li>
<li><p>The example in this blog uses a react project created by Vite, so we need to modify the <code>vite.config.ts</code>to run the app on fixed port 3000 in our machine as well as in the container. Ignore this step if you are not using vite.</p>
<pre><code class="lang-typescript"> <span class="hljs-comment">// vite.config.ts</span>
 <span class="hljs-keyword">import</span> { defineConfig } <span class="hljs-keyword">from</span> <span class="hljs-string">'vite'</span>
 <span class="hljs-keyword">import</span> react <span class="hljs-keyword">from</span> <span class="hljs-string">'@vitejs/plugin-react'</span>

 <span class="hljs-comment">// https://vitejs.dev/config/</span>
 <span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> defineConfig({
   plugins: [react()],
   server: {
     port: <span class="hljs-number">3000</span>
   },
   <span class="hljs-comment">// To allow the host to be exposed from container</span>
   preview: {
     host: <span class="hljs-literal">true</span>,
     port: <span class="hljs-number">3000</span>
   }
 })
</code></pre>
</li>
<li><p>Create a basic html table with Edit and Delete button for each row and add new product form below the table</p>
<pre><code class="lang-typescript"> <span class="hljs-comment">// App.tsx</span>
 <span class="hljs-keyword">import</span> { useEffect, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
 <span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">'axios'</span>;

 <span class="hljs-keyword">type</span> Product = {
   id: <span class="hljs-built_in">number</span>;
   name: <span class="hljs-built_in">string</span>;
   price: <span class="hljs-built_in">number</span>;
 };

 <span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
   <span class="hljs-keyword">const</span> apiUrl = <span class="hljs-string">'http://localhost:8080/api/products'</span>;

   <span class="hljs-keyword">const</span> [products, setProducts] = useState&lt;Product[]&gt;([]);
   <span class="hljs-keyword">const</span> [newProductName, setNewProductName] = useState(<span class="hljs-string">''</span>);
   <span class="hljs-keyword">const</span> [newProductPrice, setNewProductPrice] = useState(<span class="hljs-string">''</span>);
   <span class="hljs-keyword">const</span> [editProductId, setEditProductId] = useState&lt;<span class="hljs-built_in">number</span> | <span class="hljs-literal">null</span>&gt;(<span class="hljs-literal">null</span>);
   <span class="hljs-keyword">const</span> [editProductName, setEditProductName] = useState(<span class="hljs-string">''</span>);
   <span class="hljs-keyword">const</span> [editProductPrice, setEditProductPrice] = useState(<span class="hljs-string">''</span>);

   useEffect(<span class="hljs-function">() =&gt;</span> {
     fetchProducts();
   }, []);

   <span class="hljs-keyword">const</span> fetchProducts = <span class="hljs-keyword">async</span> () =&gt; {
     <span class="hljs-keyword">try</span> {
       <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> axios.get(apiUrl);
       setProducts(response.data);
     } <span class="hljs-keyword">catch</span> (error) {
       <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error fetching products:'</span>, error);
     }
   };

   <span class="hljs-keyword">const</span> addProduct = <span class="hljs-keyword">async</span> () =&gt; {
     <span class="hljs-keyword">try</span> {
       <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> axios.post(apiUrl, {
         name: newProductName,
         price: <span class="hljs-built_in">parseFloat</span>(newProductPrice),
       });
       setProducts(<span class="hljs-function">(<span class="hljs-params">prevProducts</span>) =&gt;</span> [...prevProducts, response.data]);
       setNewProductName(<span class="hljs-string">''</span>);
       setNewProductPrice(<span class="hljs-string">''</span>);
     } <span class="hljs-keyword">catch</span> (error) {
       <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error adding product:'</span>, error);
     }
   };

   <span class="hljs-keyword">const</span> deleteProduct = <span class="hljs-keyword">async</span> (id: <span class="hljs-built_in">number</span>) =&gt; {
     <span class="hljs-keyword">try</span> {
       <span class="hljs-keyword">await</span> axios.delete(<span class="hljs-string">`<span class="hljs-subst">${apiUrl}</span>/<span class="hljs-subst">${id}</span>`</span>);
       setProducts(<span class="hljs-function">(<span class="hljs-params">prevProducts</span>) =&gt;</span> prevProducts.filter(<span class="hljs-function">(<span class="hljs-params">product</span>) =&gt;</span> product.id !== id));
     } <span class="hljs-keyword">catch</span> (error) {
       <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error deleting product:'</span>, error);
     }
   };

   <span class="hljs-keyword">const</span> startEditingProduct = <span class="hljs-function">(<span class="hljs-params">id: <span class="hljs-built_in">number</span>, name: <span class="hljs-built_in">string</span>, price: <span class="hljs-built_in">number</span></span>) =&gt;</span> {
     setEditProductId(id);
     setEditProductName(name);
     setEditProductPrice(price.toString());
   };

   <span class="hljs-keyword">const</span> cancelEditingProduct = <span class="hljs-function">() =&gt;</span> {
     setEditProductId(<span class="hljs-literal">null</span>);
     setEditProductName(<span class="hljs-string">''</span>);
     setEditProductPrice(<span class="hljs-string">''</span>);
   };

   <span class="hljs-keyword">const</span> updateProduct = <span class="hljs-keyword">async</span> () =&gt; {
     <span class="hljs-keyword">try</span> {
       <span class="hljs-keyword">await</span> axios.put(<span class="hljs-string">`<span class="hljs-subst">${apiUrl}</span>/<span class="hljs-subst">${editProductId}</span>`</span>, {
         name: editProductName,
         price: <span class="hljs-built_in">parseFloat</span>(editProductPrice),
       });
       fetchProducts();
       cancelEditingProduct();
     } <span class="hljs-keyword">catch</span> (error) {
       <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error updating product:'</span>, error);
     }
   };

   <span class="hljs-keyword">return</span> (
     &lt;div style={{ display: <span class="hljs-string">'flex'</span>, flexDirection: <span class="hljs-string">'column'</span>, alignItems: <span class="hljs-string">'center'</span>, justifyContent: <span class="hljs-string">'center'</span>}}&gt;
       &lt;h1 style={{ fontSize: <span class="hljs-string">'2rem'</span>, fontWeight: <span class="hljs-string">'bold'</span>, marginBottom: <span class="hljs-string">'1rem'</span> }}&gt;Product List&lt;/h1&gt;
       &lt;table style={{ borderCollapse: <span class="hljs-string">'collapse'</span>, width: <span class="hljs-string">'80%'</span>, margin: <span class="hljs-string">'auto'</span> }}&gt;
         &lt;thead&gt;
           &lt;tr style={{ borderBottom: <span class="hljs-string">'1px solid #ccc'</span> }}&gt;
             &lt;th style={{ padding: <span class="hljs-string">'8px'</span>, textAlign: <span class="hljs-string">'left'</span> }}&gt;ID&lt;/th&gt;
             &lt;th style={{ padding: <span class="hljs-string">'8px'</span>, textAlign: <span class="hljs-string">'left'</span> }}&gt;Name&lt;/th&gt;
             &lt;th style={{ padding: <span class="hljs-string">'8px'</span>, textAlign: <span class="hljs-string">'left'</span> }}&gt;Price&lt;/th&gt;
             &lt;th style={{ padding: <span class="hljs-string">'8px'</span>, textAlign: <span class="hljs-string">'left'</span> }}&gt;Action&lt;/th&gt;
           &lt;/tr&gt;
         &lt;/thead&gt;
         &lt;tbody&gt;
           {products.map(<span class="hljs-function">(<span class="hljs-params">product</span>) =&gt;</span> (
             &lt;tr key={product.id} style={{ borderBottom: <span class="hljs-string">'1px solid #ccc'</span> }}&gt;
               &lt;td style={{ padding: <span class="hljs-string">'8px'</span>, textAlign: <span class="hljs-string">'left'</span> }}&gt;{product.id}&lt;/td&gt;
               {editProductId === product.id ? (
                 &lt;&gt;
                   &lt;td style={{ padding: <span class="hljs-string">'8px'</span>, textAlign: <span class="hljs-string">'left'</span> }}&gt;
                     &lt;input
                       style={{ border: <span class="hljs-string">'1px solid #ccc'</span>, padding: <span class="hljs-string">'6px'</span> }}
                       <span class="hljs-keyword">type</span>=<span class="hljs-string">"text"</span>
                       value={editProductName}
                       onChange={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> setEditProductName(e.target.value)}
                     /&gt;
                   &lt;/td&gt;
                   &lt;td style={{ padding: <span class="hljs-string">'8px'</span>, textAlign: <span class="hljs-string">'left'</span> }}&gt;
                     &lt;input
                       style={{ border: <span class="hljs-string">'1px solid #ccc'</span>, padding: <span class="hljs-string">'6px'</span> }}
                       <span class="hljs-keyword">type</span>=<span class="hljs-string">"text"</span>
                       value={editProductPrice}
                       onChange={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> setEditProductPrice(e.target.value)}
                     /&gt;
                   &lt;/td&gt;
                 &lt;/&gt;
               ) : (
                 &lt;&gt;
                   &lt;td style={{ padding: <span class="hljs-string">'8px'</span>, textAlign: <span class="hljs-string">'left'</span> }}&gt;{product.name}&lt;/td&gt;
                   &lt;td style={{ padding: <span class="hljs-string">'8px'</span>, textAlign: <span class="hljs-string">'left'</span> }}&gt;{product.price}&lt;/td&gt;
                 &lt;/&gt;
               )}
               &lt;td style={{ padding: <span class="hljs-string">'8px'</span>, textAlign: <span class="hljs-string">'left'</span> }}&gt;
                 {editProductId === product.id ? (
                   &lt;&gt;
                     &lt;button
                       style={{ backgroundColor: <span class="hljs-string">'#4CAF50'</span>, color: <span class="hljs-string">'white'</span>, padding: <span class="hljs-string">'6px'</span>, borderRadius: <span class="hljs-string">'4px'</span>, marginRight: <span class="hljs-string">'4px'</span> }}
                       onClick={updateProduct}
                     &gt;
                       Update
                     &lt;/button&gt;
                     &lt;button
                       style={{ backgroundColor: <span class="hljs-string">'#ccc'</span>, padding: <span class="hljs-string">'6px'</span>, borderRadius: <span class="hljs-string">'4px'</span> }}
                       onClick={cancelEditingProduct}
                     &gt;
                       Cancel
                     &lt;/button&gt;
                   &lt;/&gt;
                 ) : (
                   &lt;&gt;
                     &lt;button
                       style={{ backgroundColor: <span class="hljs-string">'#2196F3'</span>, color: <span class="hljs-string">'white'</span>, padding: <span class="hljs-string">'6px'</span>, borderRadius: <span class="hljs-string">'4px'</span>, marginRight: <span class="hljs-string">'4px'</span> }}
                       onClick={<span class="hljs-function">() =&gt;</span>
                         startEditingProduct(product.id, product.name, product.price)
                       }
                     &gt;
                       Edit
                     &lt;/button&gt;
                     &lt;button
                       style={{ backgroundColor: <span class="hljs-string">'#f44336'</span>, color: <span class="hljs-string">'white'</span>, padding: <span class="hljs-string">'6px'</span>, borderRadius: <span class="hljs-string">'4px'</span> }}
                       onClick={<span class="hljs-function">() =&gt;</span> deleteProduct(product.id)}
                     &gt;
                       Delete
                     &lt;/button&gt;
                   &lt;/&gt;
                 )}
               &lt;/td&gt;
             &lt;/tr&gt;
           ))}
         &lt;/tbody&gt;
       &lt;/table&gt;
       &lt;div style={{ marginTop: <span class="hljs-string">'1rem'</span> }}&gt;
         &lt;h2 style={{ fontSize: <span class="hljs-string">'1.5rem'</span>, fontWeight: <span class="hljs-string">'bold'</span>, marginBottom: <span class="hljs-string">'0.5rem'</span> }}&gt;Add Product&lt;/h2&gt;
         &lt;label style={{ display: <span class="hljs-string">'block'</span>, marginBottom: <span class="hljs-string">'0.5rem'</span> }}&gt;
           Name:
           &lt;input
             style={{ border: <span class="hljs-string">'1px solid #ccc'</span>, padding: <span class="hljs-string">'6px'</span> }}
             <span class="hljs-keyword">type</span>=<span class="hljs-string">"text"</span>
             value={newProductName}
             onChange={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> setNewProductName(e.target.value)}
           /&gt;
         &lt;/label&gt;
         &lt;label style={{ display: <span class="hljs-string">'block'</span>, marginBottom: <span class="hljs-string">'0.5rem'</span> }}&gt;
           Price:
           &lt;input
             style={{ border: <span class="hljs-string">'1px solid #ccc'</span>, padding: <span class="hljs-string">'6px'</span> }}
             <span class="hljs-keyword">type</span>=<span class="hljs-string">"text"</span>
             value={newProductPrice}
             onChange={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> setNewProductPrice(e.target.value)}
           /&gt;
         &lt;/label&gt;
         &lt;button
           style={{ backgroundColor: <span class="hljs-string">'#2196F3'</span>, color: <span class="hljs-string">'white'</span>, padding: <span class="hljs-string">'6px'</span>, borderRadius: <span class="hljs-string">'4px'</span> }}
           onClick={addProduct}
         &gt;
           Add Product
         &lt;/button&gt;
       &lt;/div&gt;
     &lt;/div&gt;
   );
 };

 <span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
</li>
<li><p>The front-end should be running at http://localhost:3000</p>
<p> Add some demo data to test the connection</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706132782818/81be9450-1ef9-42fb-8507-2d9217145bf2.png" alt class="image--center mx-auto" /></p>
</li>
</ol>
<hr />
<h3 id="heading-docker-compose-config">Docker Compose Config</h3>
<ol>
<li><p>Create a <code>Dockerfile</code> in backend directory</p>
<pre><code class="lang-dockerfile"> <span class="hljs-comment"># Stage 1: Build the application using Maven</span>
 <span class="hljs-keyword">FROM</span> maven:<span class="hljs-number">3.9</span>.<span class="hljs-number">5</span> AS build

 <span class="hljs-comment"># Set the working directory within the container to /app</span>
 <span class="hljs-keyword">WORKDIR</span><span class="bash"> /app</span>

 <span class="hljs-comment"># Copy all files from the current directory (.) to the container's working directory (/app)</span>
 <span class="hljs-keyword">COPY</span><span class="bash"> . .</span>

 <span class="hljs-comment"># Run the Maven clean install command</span>
 <span class="hljs-keyword">RUN</span><span class="bash"> mvn clean install</span>

 <span class="hljs-comment"># Stage 2: Create a lightweight container with only the necessary artifacts</span>
 <span class="hljs-keyword">FROM</span> openjdk:<span class="hljs-number">21</span>

 <span class="hljs-comment"># Set the working directory within the container to /app</span>
 <span class="hljs-keyword">WORKDIR</span><span class="bash"> /app</span>

 <span class="hljs-comment"># Copy the built JAR file from the previous stage into the current stage</span>
 <span class="hljs-keyword">COPY</span><span class="bash"> --from=build /app/target/*.jar server.jar</span>

 <span class="hljs-comment"># Expose port 8080 to allow external connections to the application</span>
 <span class="hljs-keyword">EXPOSE</span> <span class="hljs-number">8080</span>

 <span class="hljs-comment"># Specify the command to run when the container starts - run the Java application using the JAR file</span>
 <span class="hljs-keyword">CMD</span><span class="bash"> [<span class="hljs-string">"java"</span>, <span class="hljs-string">"-jar"</span>, <span class="hljs-string">"server.jar"</span>]</span>
</code></pre>
</li>
<li><p>Create a <code>Dockerfile</code> in frontend directory</p>
<pre><code class="lang-dockerfile"> <span class="hljs-comment"># Stage 1: Build the Node.js application</span>
 <span class="hljs-keyword">FROM</span> node:<span class="hljs-number">18</span>-alpine as BUILD

 <span class="hljs-comment"># Set the working directory within the container to /app</span>
 <span class="hljs-keyword">WORKDIR</span><span class="bash"> /app</span>

 <span class="hljs-comment"># Copy package.json to the container's working directory</span>
 <span class="hljs-keyword">COPY</span><span class="bash"> package.json .</span>

 <span class="hljs-comment"># Install dependencies based on package.json</span>
 <span class="hljs-keyword">RUN</span><span class="bash"> npm install</span>

 <span class="hljs-comment"># Copy all files from the current directory (.) to the container's working directory (/app)</span>
 <span class="hljs-keyword">COPY</span><span class="bash"> . .</span>

 <span class="hljs-comment"># Build the application</span>
 <span class="hljs-keyword">RUN</span><span class="bash"> npm run build</span>

 <span class="hljs-comment"># Stage 2: Create a lightweight container for production</span>
 <span class="hljs-keyword">FROM</span> node:<span class="hljs-number">18</span>-alpine as PROD

 <span class="hljs-comment"># Set the working directory within the container to /app</span>
 <span class="hljs-keyword">WORKDIR</span><span class="bash"> /app</span>

 <span class="hljs-comment"># Copy the build artifacts (dist folder) from the BUILD stage to the current stage</span>
 <span class="hljs-keyword">COPY</span><span class="bash"> --from=BUILD /app/dist/ /app/dist/</span>

 <span class="hljs-comment"># Expose port 3000 to allow external connections to the application</span>
 <span class="hljs-keyword">EXPOSE</span> <span class="hljs-number">3000</span>

 <span class="hljs-comment"># Copy package.json and vite.config.ts to the container's working directory</span>
 <span class="hljs-keyword">COPY</span><span class="bash"> package.json .</span>
 <span class="hljs-keyword">COPY</span><span class="bash"> vite.config.ts .</span>

 <span class="hljs-comment"># Install TypeScript</span>
 <span class="hljs-keyword">RUN</span><span class="bash"> npm install typescript</span>

 <span class="hljs-comment"># Specify the command to run when the container starts - run the application in preview mode</span>
 <span class="hljs-keyword">CMD</span><span class="bash"> [ <span class="hljs-string">"npm"</span>, <span class="hljs-string">"run"</span>, <span class="hljs-string">"preview"</span> ]</span>
</code></pre>
</li>
<li><p>Add a .dockerignore in the frontend directory to restrict node_modules directory to hold up space</p>
<pre><code class="lang-json"> node_modules/
</code></pre>
</li>
<li><p>We can update the <code>application.properties</code> in the backend to support dynamic environment variables now.</p>
<pre><code class="lang-plaintext"> spring.datasource.url=${SPRING_DATASOURCE_URL}
 spring.datasource.username=${SPRING_DATASOURCE_USERNAME}
 spring.datasource.password=${SPRING_DATASOURCE_PASSWORD}
 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
 spring.jpa.hibernate.ddl-auto=update
</code></pre>
</li>
</ol>
<p>In the project source directory i.e. <a target="_blank" href="https://github.com/saurabhthecodewizard/docker-compose-demo">docker-compose-demo</a> directory, we need to add a <code>docker-compose.yml</code>. The environment variables should be appropriately used in the <code>docker-compose.yml</code> and <code>application.properties</code>.</p>
<pre><code class="lang-yaml"><span class="hljs-comment"># Specify the version of the Docker Compose file format</span>
<span class="hljs-attr">version:</span> <span class="hljs-string">'3.8'</span>

<span class="hljs-comment"># Define the services that will run in your application</span>
<span class="hljs-attr">services:</span>

  <span class="hljs-comment"># Configuration for the MySQL database service</span>
  <span class="hljs-attr">database:</span>
    <span class="hljs-comment"># Use the MySQL 8 Docker image</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">mysql:8</span>
    <span class="hljs-attr">environment:</span>
      <span class="hljs-comment"># Set the root password for MySQL</span>
      <span class="hljs-attr">MYSQL_ROOT_PASSWORD:</span> <span class="hljs-string">password</span>
      <span class="hljs-comment"># Specify the name of the database to be created</span>
      <span class="hljs-attr">MYSQL_DATABASE:</span> <span class="hljs-string">product</span>
      <span class="hljs-comment"># Specify the MySQL user and its password</span>
      <span class="hljs-attr">MYSQL_USER:</span> <span class="hljs-string">product</span>
      <span class="hljs-attr">MYSQL_PASSWORD:</span> <span class="hljs-string">password</span>
    <span class="hljs-attr">volumes:</span>
      <span class="hljs-comment"># Mount a volume to persist MySQL data</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">mysql_data:/var/lib/mysql</span>

  <span class="hljs-comment"># Configuration for the backend application</span>
  <span class="hljs-attr">server:</span>
    <span class="hljs-comment"># Build the server image using the Dockerfile in the ./server directory</span>
    <span class="hljs-attr">build:</span>
      <span class="hljs-attr">context:</span> <span class="hljs-string">./backend</span>
    <span class="hljs-comment"># Expose port 8080 on the host and map it to port 8080 in the container</span>
    <span class="hljs-attr">ports:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">"8080:8080"</span>
    <span class="hljs-attr">environment:</span>
      <span class="hljs-comment"># Set the Spring DataSource URL to connect to the MySQL database service</span>
      <span class="hljs-attr">SPRING_DATASOURCE_URL:</span> <span class="hljs-string">jdbc:mysql://database:3306/product</span>
      <span class="hljs-comment"># Set the username for connecting to the MySQL database</span>
      <span class="hljs-attr">SPRING_DATASOURCE_USERNAME:</span> <span class="hljs-string">product</span>
      <span class="hljs-comment"># Set the password for connecting to the MySQL database</span>
      <span class="hljs-attr">SPRING_DATASOURCE_PASSWORD:</span> <span class="hljs-string">password</span>
    <span class="hljs-comment"># Depend on the database service, ensuring it starts before the server</span>
    <span class="hljs-attr">depends_on:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">database</span>

  <span class="hljs-comment"># Configuration for the frontend application</span>
  <span class="hljs-attr">client:</span>
    <span class="hljs-comment"># Build the client image using the Dockerfile in the ./client directory</span>
    <span class="hljs-attr">build:</span>
      <span class="hljs-attr">context:</span> <span class="hljs-string">./frontend</span>
    <span class="hljs-comment"># Expose port 3000 on the host and map it to port 5173 in the container</span>
    <span class="hljs-attr">ports:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">"3000:3000"</span>
    <span class="hljs-comment"># Depend on the server service, ensuring it starts before the client</span>
    <span class="hljs-attr">depends_on:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">server</span>

<span class="hljs-comment"># Define a volume named mysql_data for persisting MySQL data</span>
<span class="hljs-attr">volumes:</span>
  <span class="hljs-attr">mysql_data:</span>
</code></pre>
<hr />
<h3 id="heading-running-the-database-back-end-and-front-end-containers-in-the-docker-network">Running the database, back-end and front-end containers in the docker network</h3>
<ol>
<li><p>Run the following command to create images of mysql, server and client services provided in <code>docker-compose.yml</code>, create and run the images in containers in a single network in detached mode i.e. run the containers in the background, detached from the terminal</p>
<pre><code class="lang-bash"> docker-compose up -d
</code></pre>
<p> The command line should look something like this which shows the execution of the <code>docker-compose.yml</code> file by the configuration we provide by properties like <code>ports</code>, <code>depends_on</code>, etc.</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706135048683/c017d386-a31c-46fe-978a-1fb297d14593.png" alt class="image--center mx-auto" /></p>
<p> We should be able to see the containers running in a single network in out Docker desktop app.</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706134668282/aada3f17-f204-4b81-9a8c-f60f201682dd.png" alt class="image--center mx-auto" /></p>
<p> The backend and frontend servers should be running on the ports we assigned in the <code>docker-compose.yml</code> file.</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706134953152/b6b498cc-f65d-4c2a-a51a-657c34bc2985.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>We can use the following command to stop and remove the containers.</p>
<pre><code class="lang-bash"> docker-compose down
</code></pre>
</li>
<li><p>If we restart our containers again by <code>docker-compose up -d</code>, we should have our inserted data from before since we provided a volume named <code>mysql_data</code> in <code>docker-compose.yml</code> for persisting MySQL data.</p>
</li>
</ol>
<hr />
<h3 id="heading-resources">Resources</h3>
<ol>
<li><p>Github repository to the provided example - <a target="_blank" href="https://github.com/saurabhthecodewizard/docker-compose-demo">Docker Compose Demo</a></p>
</li>
<li><p><a target="_blank" href="https://docs.docker.com/">Docker documentation</a></p>
</li>
<li><p><a target="_blank" href="https://docs.docker.com/compose/">Docker Compose documentation</a></p>
</li>
</ol>
<hr />
<h3 id="heading-conclusion">Conclusion</h3>
<p>In conclusion, this blog covered the fundamental concepts of containers and how Docker facilitates their creation, deployment, and management. It delved into the role of Docker Compose as a tool for orchestrating multi-container Docker applications, emphasizing its declarative configuration, service definition, networking, volume sharing, environment variable setup, and ease of use.</p>
<p>The blog provides streamlined steps for configuring a Spring backend and a React frontend application with Docker, along with Dockerfiles for building container images. The Docker Compose configuration file is introduced briefly, emphasizing service setups and volume usage for data persistence.</p>
<p>The concluding section briefly guides readers on running the entire application stack with Docker Compose, underscoring the importance of volumes in persisting data.</p>
<p>In essence, this blog serves as a quick reference for developers seeking practical insights into containerization using Docker and Docker Compose, offering a simplified guide for a multi-container application environment.</p>
]]></content:encoded></item><item><title><![CDATA[Navigating the Coding Odyssey: My 100DaysOfCode Challenge Journey]]></title><description><![CDATA[Embarking on a journey of self-improvement was a path often paved with challenges, victories, and the relentless pursuit of growth. In the realm of coding, this journey took the form of the 100DaysOfCode challenge - a commitment to spend a dedicated ...]]></description><link>https://blog.saurabhmahajan.com/navigating-the-coding-odyssey-my-100daysofcode-challenge-journey</link><guid isPermaLink="true">https://blog.saurabhmahajan.com/navigating-the-coding-odyssey-my-100daysofcode-challenge-journey</guid><category><![CDATA[100DaysOfCode]]></category><category><![CDATA[AWS]]></category><category><![CDATA[Springboot]]></category><category><![CDATA[data structure and algorithms ]]></category><category><![CDATA[SQL]]></category><category><![CDATA[Java]]></category><category><![CDATA[OpenApi]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[React]]></category><category><![CDATA[Next.js]]></category><category><![CDATA[Tailwind CSS]]></category><category><![CDATA[vite]]></category><category><![CDATA[ci-cd]]></category><category><![CDATA[Vercel]]></category><dc:creator><![CDATA[Saurabh Mahajan]]></dc:creator><pubDate>Sat, 03 Feb 2024 14:06:32 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1706466884968/d7d80bc0-0384-4618-9d07-d906e3ed701c.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Embarking on a journey of self-improvement was a path often paved with challenges, victories, and the relentless pursuit of growth. In the realm of coding, this journey took the form of the 100DaysOfCode challenge - a commitment to spend a dedicated hour each day for a hundred days, learning and honing coding skills. What began as a personal challenge soon evolved into a transformative odyssey through the vast landscape of web development.</p>
<p>As the first lines of code were written, and the initial hurdles were overcome, I found myself immersed in a world of algorithms, languages, and the sheer joy of creation. This blog is a reflection on those 100 days, a chronicle of the lessons learned, technologies embraced, and the triumphs and tribulations that came with them.</p>
<p>Join me as I navigated through the intricacies of different technologies, unraveling the threads of database management, front-end development, back-end development and Cloud computing, and discovering the fascinating world that lies beneath the surface of our favorite websites and applications. This was not just a coding challenge; it was a personal exploration, a commitment to growth, and a testament to the transformative power of perseverance in the face of complexity.</p>
<p>So, let's dive into the code and explore the milestones, the discoveries, and the unexpected joys that the 100DaysOfCode challenge brought into my coding journey.</p>
<hr />
<h3 id="heading-introduction-to-the-challenge">Introduction to the Challenge</h3>
<p>In the ever-evolving landscape of technology, the need for continuous learning and skill enhancement has become paramount. Recognizing this, the 100DaysOfCode challenge has emerged as a powerful and popular initiative within the coding community. The premise is simple yet transformative: dedicate at least one hour each day to coding for a consecutive 100 days.</p>
<p>This challenge serves as a catalyst for personal and professional growth, aiming to instill discipline, consistency, and a genuine love for coding. Whether you're a seasoned developer looking to expand your skill set or a novice eager to embark on a coding journey, the 100DaysOfCode challenge provides a structured and supportive framework to achieve your coding goals.</p>
<p>Beyond the mere act of coding, this challenge fosters a sense of community by connecting participants worldwide through social media platforms. Sharing progress, challenges, and insights with the hashtag #100DaysOfCode creates a collaborative atmosphere that encourages and motivates individuals throughout their coding odyssey.</p>
<p>Joining the 100DaysOfCode challenge isn't just about completing a hundred days of coding—it's about embracing a mindset of continuous improvement, breaking through barriers, and celebrating the small victories that collectively lead to significant progress. As countless developers have discovered, this challenge isn't just a commitment to code; it's a commitment to personal and professional development, one day at a time.</p>
<p>For more information on the origin of the challenge:-</p>
<p><a target="_blank" href="https://www.100daysofcode.com/">https://www.100daysofcode.com/</a></p>
<hr />
<h3 id="heading-before-the-challenge">Before the Challenge</h3>
<p>Before embarking on the 100DaysOfCode challenge, my coding journey was characterized by a foundation of curiosity and a desire to learn. While confident in the front-end and back-end coding aspects, there were notable gaps in my knowledge, particularly in design, database management, and certain cloud computing and data structure concepts. Though comfortable with technologies like Java, Spring, React, and SQL, I didn't categorize myself a full-stack development professional due to these knowledge gaps.</p>
<p>My goals were aspirational, yet there was a noticeable gap between where I stood and where I envisioned myself in the ever-evolving world of technology. The prospect of handling back-end processes, understanding databases, and seamlessly integrating front-end and back-end development seemed daunting but immensely exciting.</p>
<p>In essence, I was at the foothills of a vast mountain of knowledge, eager to ascend and explore the panoramic views that awaited me in the realm of full-stack development.</p>
<hr />
<h3 id="heading-planning">Planning</h3>
<p>Embarking on the 100DaysOfCode challenge requires thoughtful planning and a clear roadmap to navigate the coding journey successfully. Before diving into the daily coding sessions, I took the time to establish a structured plan, ensuring that the next 100 days would be both productive and rewarding.</p>
<ul>
<li><p>I outlined clear and ambitious goals centered around mastering key domains in full stack development and expanding my existing knowledge. My focus was on becoming proficient in Database Management, Back-end Development, Front-end Development, and Cloud Computing. Additionally, I aimed to delve into essential concepts like Data Structures, Containerization, and Linux.</p>
</li>
<li><p>Recognizing the need for consistency, I divided my overarching goals into manageable sprints of 15 days each. Each sprint was dedicated to a specific topic or domain, ensuring a focused and immersive learning experience. This structured approach allowed me to balance depth and breadth in my coding journey.</p>
</li>
<li><p>Selecting the right tools and technologies required meticulous research, considering various parameters such as industry relevance, personal interest, and scalability. Each choice was made with the goal of acquiring practical skills and knowledge that would contribute to my full-stack development proficiency.</p>
</li>
<li><p>To track progress effectively, I established milestones to be completed at the end of every second sprint. These milestones served as checkpoints for significant achievements, whether it was successfully implementing a feature, completing a comprehensive tutorial, or building a functional project. Celebrating these milestones provided motivation and a sense of accomplishment.</p>
</li>
<li><p>Flexibility was a key component of the plan. Recognizing that unexpected challenges could arise, I built in the flexibility to adapt the schedule and goals as needed. This adaptive approach allowed me to navigate unforeseen obstacles without derailing the overall progress.</p>
</li>
<li><p>Regular reflection on my progress became a fundamental aspect of the planning process. This allowed me to assess what was working well, identify areas for improvement, and make necessary adjustments. The ability to adapt and refine the plan ensured that it remained dynamic and responsive to evolving learning needs.</p>
</li>
</ul>
<p>In essence, the planning phase was not just about setting goals; it was about crafting a roadmap for a comprehensive and successful 100DaysOfCode challenge. As I moved through the meticulously planned sprints and milestones, each day became a purposeful step toward achieving mastery in full-stack development and beyond.</p>
<hr />
<h3 id="heading-tools-and-technologies-learned">Tools and Technologies learned</h3>
<p>General concepts:-</p>
<ul>
<li><p>Basics of Data Structures: Array, LinkedList, Stack, Queues</p>
</li>
<li><p>Leetcode problems related to String, Arrays, HashMap, Linked List, Interval, backtracking, Stack, Sliding window &amp; 2D matrix.</p>
</li>
<li><p>Algorithms: Stack, Queue, Resize Arrays, Dequeue(Randomized), Union Find, Knuth Shuffle, Convex Hull, Selection Sort, Bubble sort, Insertion sort, Shell sort, Merge sort, Quick sort, Dijkstra Threeway, Heap sort, Heapify.</p>
</li>
<li><p>Reversed heap, Binary Tree, Binary Search Tree, AVL Trees, Red Black Trees.</p>
</li>
<li><p>Implementation of Symbol Tables, Kadanes algorithm.</p>
</li>
<li><p>Containerization with Docker and Docker Compose.</p>
</li>
<li><p>Docker compose a full-stack application.</p>
</li>
</ul>
<p>Database management:-</p>
<ul>
<li><p>MySQL and Flyway Migration</p>
</li>
<li><p>Indexing</p>
</li>
<li><p>Database Principles</p>
</li>
</ul>
<p>Backend Development</p>
<ul>
<li><p>Technologies: Java 17/21, Springboot 3, Python</p>
</li>
<li><p>OpenAPI code generation</p>
</li>
<li><p>RBAC system for user Authorization</p>
</li>
<li><p>Data structures and algorithms with Python</p>
</li>
</ul>
<p>Frontend Development</p>
<ul>
<li><p>OpenAPI Integration</p>
</li>
<li><p>React Routing</p>
</li>
<li><p>Common reusable components in React suitable for multiple projects</p>
</li>
<li><p>Hands-on with React libraries like Framer Motion, Three.js</p>
</li>
<li><p>NextJs, Tailwind CSS, Swiper.Js, and Framer Motion for the latest portfolio website</p>
</li>
<li><p>Vite vs CRA (Create React App) concept</p>
</li>
<li><p>Migration of a React application from CRA to Vite</p>
</li>
</ul>
<p>Cloud Computing and DevOps</p>
<ul>
<li><p>AWS services like IAM, EC2, S3, ELB, ALB, ECR, ECS, EKS, RDS, AWS Amplify, etc.</p>
</li>
<li><p>Deployment on various platforms like AWS EC2, S3, Netlify, Vercel, Render, etc.</p>
</li>
<li><p>Proxy_pass with Nginx in EC2</p>
</li>
<li><p>Setting AWS Cloudwatch logs with RDS, EC2, and ECS</p>
</li>
<li><p>Full-stack project deployment with CI/CD</p>
</li>
<li><p>Spring app CI/CD through Github Actions &amp; deployment on EC2 instance (Free SSL with Caddy for testing) as a Docker container</p>
</li>
<li><p>MySQL on AWS RDS with AWS Cloudwatch logs enabled &amp; React app on AWS Amplify &amp; Vercel</p>
</li>
<li><p>Implemented a full-stack app in containers with Docker compose</p>
</li>
<li><p>AWS Database and Analytics, Compute services, ECS, Lambda, Batch, Lightsail</p>
</li>
<li><p>Cloud integrations, Cloud Monitoring, VPC and Networking, Security and Compliance &amp; Machine Learning</p>
</li>
</ul>
<hr />
<h3 id="heading-projects-showcase">Projects Showcase</h3>
<ol>
<li><p>Opus - A corporate management system</p>
<p> <a target="_blank" href="https://github.com/saurabhthecodewizard/opus">Source code</a></p>
</li>
<li><p>Docker containers running in a single docker network with docker compose</p>
<p> <a target="_blank" href="https://github.com/saurabhthecodewizard/docker-compose-demo">Source code</a></p>
</li>
<li><p>CI/CD of a fullstack application</p>
<p> <a target="_blank" href="https://github.com/saurabhthecodewizard/opus">Source code</a></p>
</li>
<li><p>3d portfolio developer website</p>
<p> <a target="_blank" href="https://github.com/saurabhthecodewizard/3d-portfolio-for-dev">Source code</a></p>
<p> <a target="_blank" href="https://saurabh-the-dev.netlify.app/">Live Demo</a></p>
</li>
<li><p>Portfolio website</p>
<p> <a target="_blank" href="https://github.com/saurabhthecodewizard/portfolio">Source code</a></p>
<p> <a target="_blank" href="https://portfolio.saurabhmahajan.com/">Live Demo</a></p>
</li>
<li><p>Data Structure and Algorithms</p>
<p> <a target="_blank" href="https://github.com/saurabhthecodewizard/coding">Source code</a></p>
<p> <a target="_blank" href="https://github.com/saurabhthecodewizard/algorithms">Source code</a></p>
</li>
<li><p>Python</p>
<p> <a target="_blank" href="https://github.com/saurabhthecodewizard/python-django-quest">Source code</a></p>
</li>
</ol>
<hr />
<h3 id="heading-learning-moments">Learning Moments</h3>
<ul>
<li><p>CSS layout was a significant challenge, especially when working on responsive designs. On Day 68, I dedicated time to master CSS Flexbox and Grid. The "aha" moment came when I realized how these tools could simplify complex layouts and streamline the design process. This newfound knowledge immediately translated into more visually appealing and structurally sound web pages.</p>
</li>
<li><p>As the complexity of my projects increased, so did moments of self-doubt. Day 82 became a turning point when I faced and conquered imposter syndrome. Connecting with the coding community, sharing my struggles, and receiving encouragement helped me realize that setbacks were a natural part of the learning journey. It was okay not to have all the answers immediately.</p>
</li>
<li><p>On Day 94, I built and deployed my first full-stack application, integrating server-side logic, databases, and client-side functionality. Simultaneously, I embraced continuous integration, setting up automated testing and deployment pipelines. This streamlined my development process, reinforcing the importance of code quality. Witnessing my code undergo automated testing and deployment with each push to the repository was a gratifying and efficient improvement, marking a significant step in enhancing the efficiency and reliability of my coding projects.</p>
</li>
<li><p>As the 100DaysOfCode challenge concluded, the final learning moment was a reflective one. Looking back at the journey, I celebrated the accumulation of knowledge, the growth in problem-solving skills, and the newfound confidence in tackling diverse coding tasks. The challenge may have ended, but the learning journey continues.</p>
</li>
</ul>
<hr />
<h3 id="heading-building-consistency">Building Consistency</h3>
<p>Consistency was the cornerstone of my 100DaysOfCode journey. Tracking and maintaining a consistent coding schedule not only kept me on course but also played a crucial role in my overall progress.</p>
<ul>
<li><p>Daily time commitment - I dedicated an average of at least 3-4 hours per day to coding, ensuring a balance between depth of learning and sustainable progress. On weekends, I adjusted my schedule, dedicating longer blocks of time (18-20 hours) to accommodate more complex projects and deep dives into challenging topics.</p>
</li>
<li><p>Progress tracking - Each day, I maintained a coding journal, documenting the topics covered, challenges faced, and solutions discovered. This practice not only served as a reflection tool but also helped identify patterns in my learning journey. I organized my code repositories on platforms like GitHub, creating a visual timeline of my projects. This allowed me to track the evolution of my coding skills and revisit past projects for reinforcement.</p>
</li>
<li><p>Learning resources - To maintain variety and avoid monotony, I diversified my learning resources. This included online courses, documentation, coding challenges, and community forums. Leveraging different formats kept the learning experience engaging and dynamic.</p>
</li>
<li><p>Community engagement - Regular updates on social media platforms, using the #100DaysOfCode hashtag, allowed me to connect with the coding community. Sharing achievements, challenges, and insights fostered a sense of accountability and support.</p>
</li>
<li><p>Adaptation &amp; Flexibility - Recognizing that life can be unpredictable, I developed contingency plans for busy days or unexpected commitments. This ensured that even on challenging days, I could meet my minimum coding commitment. As the challenge progressed, I adapted my schedule based on peak productivity times. Identifying when I was most focused and adjusting my coding hours accordingly contributed to sustained consistency.</p>
</li>
</ul>
<p>Building consistency was not just about meeting a daily coding quota; it was a holistic approach that considered time management, resource diversity, community engagement, and adaptability. These elements collectively formed the framework for a successful and rewarding 100DaysOfCode journey.</p>
<hr />
<h3 id="heading-community-engagement">Community Engagement</h3>
<ul>
<li><p>Consistent daily updates on Twitter (X) using the #100DaysOfCode hashtag played a crucial role in fostering accountability, connecting with a global coding community, and documenting my coding journey, turning social media into a platform for shared learning and encouragement.</p>
</li>
<li><p>Regular GitHub contributions not only showcased my evolving skills through a visual timeline but also served as a personal portfolio, demonstrating coding proficiency and collaboration in open-source projects, thus enhancing my credibility as a developer.</p>
</li>
<li><p>Utilizing Discord for real-time guidance provided immediate solutions to coding challenges, while engagement in discussions and project showcases facilitated constructive feedback and exposure to diverse coding perspectives, emphasizing the importance of collaborative learning.</p>
</li>
<li><p>Sharing solutions to LeetCode challenges on both Discord and GitHub not only demonstrated problem-solving skills but also allowed me to actively participate in coding discussions, expanding my understanding of optimal strategies and enriching my problem-solving toolkit.</p>
</li>
</ul>
<p>This multifaceted community engagement strategy, spanning Twitter (X), GitHub, Discord, and LeetCode, proved essential in transforming the 100DaysOfCode challenge into a dynamic and collaborative experience. It went beyond personal progress documentation, creating a supportive network and fostering shared enthusiasm for coding.</p>
<hr />
<h3 id="heading-issues-faced">Issues Faced</h3>
<ul>
<li><p>Juggling full-time work, personal commitments, and the 100DaysOfCode challenge required careful planning and adaptability to establish a consistent coding schedule.</p>
</li>
<li><p>Intense daily coding sessions, particularly during challenging project phases, led to burnout and mental fatigue. Implementing breaks, relaxation techniques, and adjusting the daily workload helped mitigate these issues.</p>
</li>
<li><p>Engaging with the coding community triggered impostor syndrome, especially when comparing progress with others. Recognizing this mindset and refocusing on personal goals played a crucial role in overcoming self-doubt.</p>
</li>
<li><p>Long challenges led to monotony and plateaus in motivation. Implementing variety in coding tasks, exploring new projects, and occasionally participating in coding events helped reignite enthusiasm.</p>
</li>
<li><p>External factors, such as family emergencies or unexpected work demands, disrupted the daily coding routine. Developing contingency plans and the ability to adapt became crucial in mitigating these disruptions.</p>
</li>
<li><p>The abundance of coding resources sometimes led to decision paralysis. Selecting high-quality, relevant resources became crucial to avoid information overload and maintain a focused learning path.</p>
</li>
</ul>
<hr />
<h3 id="heading-benefits-amp-impact">Benefits &amp; Impact</h3>
<ul>
<li><p>Consistent daily coding sessions led to quantifiable progress, including faster problem-solving, efficient coding practices, and proficiency in various languages and frameworks.</p>
</li>
<li><p>GitHub contributions created a visible portfolio, showcasing growth and proficiency, demonstrating adaptability and skills in diverse areas of web development.</p>
</li>
<li><p>Active participation on Twitter (formerly known as X) and GitHub garnered recognition, evident through likes &amp; retweets, providing motivation and a sense of accomplishment.</p>
</li>
<li><p>Discord channels provided real-time problem resolution, with engagement from experienced developers and mentors offering insights and valuable advice.</p>
</li>
<li><p>Regular participation in LeetCode challenges honed problem-solving skills and exposed diverse coding approaches, influencing real-world problem-solving strategies.</p>
</li>
<li><p>Active participation in Discord project showcases offered constructive feedback, alternative perspectives, and collaborative learning experiences, refining coding practices.</p>
</li>
<li><p>Public sharing of code snippets and project updates on social media contributed to increased confidence, with positive feedback reinforcing a sense of achievement.</p>
</li>
</ul>
<p>The combination of daily Twitter updates, GitHub contributions, Discord engagement, and LeetCode challenges created a multifaceted learning experience, extending beyond technical skills to include community interaction, collaboration, and shared passion for coding.</p>
<hr />
<h3 id="heading-after-the-challenge">After the Challenge</h3>
<p>The 100DaysOfCode challenge fueled a substantial transformation in my skill set. Originating as a software engineer with proficiency in frontend and backend development, I strategically closed knowledge gaps during the challenge.</p>
<p>I enhanced my grasp of Data Structures, tackling Leetcode problems related to Array, LinkedList, Stack, Queues, and more. Projects evolved into industry-grade solutions, incorporating Java 17/21, Springboot 3, MySQL, Flyway Migration, OpenAPI, React, TypeScript, and Material UI. I explored RBAC system implementation, alongside frontend concepts like React Routing and reusable components.</p>
<p>Diverse topics, including SMPT server concepts &amp; setup, Leetcode String problems, advanced JavaScript concepts, and Python basics for Data Structures and Algorithms, were covered. I revisited fundamental concepts like basic Linux commands and delved into Tree data structures, JavaScript topics like Parcel, Babel, and npm, as well as OOP with C++.</p>
<p>I showcased my skills with a cutting-edge portfolio project using NextJs, Tailwind CSS, Swiper.Js, and Framer motion. Migrating a React app from CRA to Vite and hands-on experience with AWS services (IAM, EC2, S3, ELB, ALB, ECR, ECS, EKS, RDS, AWS Amplify) marked key milestones. Deployments on AWS platforms, Netlify, Vercel, Render, and Docker/Docker Compose for containerization added to the journey.</p>
<p>This expertise significantly elevated my role as a developer, paving the way for continued growth in the dynamic technology landscape.</p>
<hr />
<h3 id="heading-resources">Resources</h3>
<ul>
<li><p><a target="_blank" href="https://whimsical.com/dsa-in-90-days-EmPkf5utoFGRMnRqJjM6YV">DSA Roadmap in 90 Days</a></p>
</li>
<li><p><a target="_blank" href="https://takeuforward.org/strivers-a2z-dsa-course/strivers-a2z-dsa-course-sheet-2/">DSA A2Z Sheet</a></p>
</li>
<li><p><a target="_blank" href="https://www.coursera.org/learn/algorithms-part1">Algorithms - I</a></p>
</li>
<li><p><a target="_blank" href="https://namastedev.com/learn/namaste-react">Namaste React</a></p>
</li>
<li><p><a target="_blank" href="https://www.udemy.com/course/complete-python-bootcamp/">The Complete Python Bootcamp From Zero to Hero in Python</a></p>
</li>
<li><p><a target="_blank" href="https://www.udemy.com/course/aws-certified-cloud-practitioner-new/">Ultimate AWS Certified Cloud Practitioner CLF-C02</a></p>
</li>
<li><p><a target="_blank" href="https://www.docker.com/">Docker</a></p>
</li>
<li><p><a target="_blank" href="https://docs.github.com/en/actions">Github Actions</a></p>
</li>
<li><p><a target="_blank" href="https://nextjs.org/">NextJs</a></p>
</li>
<li><p><a target="_blank" href="https://www.100daysofcode.com/">100 Days of Code</a></p>
</li>
</ul>
<hr />
<h3 id="heading-conclusion">Conclusion</h3>
<p>As the 100DaysOfCode challenge concludes, it leaves behind a trail of accomplishments and a profound sense of achievement. This coding odyssey, though challenging, was undeniably transformative.</p>
<p>Reflecting on these past hundred days, I'm reminded of the power of consistency and the incremental nature of learning. Beyond the syntax and frameworks, this journey strengthened my technical skills and instilled in me a sense of discipline and continuous learning.</p>
<p>Through the ups and downs, I've gained proficiency in various technologies and become part of a supportive coding community. The camaraderie with fellow learners added an invaluable layer to this experience, emphasizing that the journey is as important as the destination.</p>
<p>As this chapter concludes, I look forward to the next set of challenges and opportunities for growth. The 100DaysOfCode challenge was not just a commitment to code—it was a commitment to self-discovery and a reminder that learning is a lifelong journey.</p>
<p>To anyone considering a similar challenge, embrace the challenges, celebrate the victories, and, most importantly, enjoy the process. Happy coding!</p>
]]></content:encoded></item></channel></rss>