<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Bilal Arshad</title>
    <description>The latest articles on Forem by Bilal Arshad (@bilalarxd).</description>
    <link>https://forem.com/bilalarxd</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F156651%2F6dd7411e-07ea-4724-86a6-46350fb932bb.jpg</url>
      <title>Forem: Bilal Arshad</title>
      <link>https://forem.com/bilalarxd</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/bilalarxd"/>
    <language>en</language>
    <item>
      <title>Become a C# Pro and Write Clean Code Like a Boss with These SOLID Principles Best Practices</title>
      <dc:creator>Bilal Arshad</dc:creator>
      <pubDate>Wed, 21 Dec 2022 08:00:00 +0000</pubDate>
      <link>https://forem.com/bilalarxd/become-a-c-pro-and-write-clean-code-like-a-boss-with-these-solid-principles-best-practices-4bg8</link>
      <guid>https://forem.com/bilalarxd/become-a-c-pro-and-write-clean-code-like-a-boss-with-these-solid-principles-best-practices-4bg8</guid>
      <description>&lt;p&gt;Clean code is code that is easy to read, understand, and maintain. It is a critical aspect of software development, as it can have a major impact on the quality, reliability, and performance of a project. In this article, we will explore some key principles of clean code and how they can be applied to C# development.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code Smells and the Clean Code Principles
&lt;/h2&gt;

&lt;p&gt;One key concept in clean code is the idea of "code smells." A code smell is a symptom of a deeper problem in the code, such as poor design, complexity, or lack of maintainability. Identifying and addressing code smells is an important step in writing clean code.&lt;/p&gt;

&lt;p&gt;One way to identify code smells is to use the principles outlined in Robert C. Martin's book "Clean Code." These principles include:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Meaningful names: Use clear, descriptive names for variables, functions, and other elements of your code. Avoid using abbreviations or acronyms unless they are widely known and used in your field.&lt;/li&gt;
&lt;li&gt;Simplicity: Avoid unnecessary complexity and strive for simplicity in your code. Use the simplest solution that meets your needs and avoid adding unnecessary features or functionality.&lt;/li&gt;
&lt;li&gt;Comments: Use comments sparingly and only to provide additional context or clarify your intentions. Avoid using comments to describe what the code is doing, as this should be evident from the code itself.&lt;/li&gt;
&lt;li&gt;Formatting: Use indentation, whitespace, and other formatting techniques to make your code easy to read and navigate. Group related code together and use clear, consistent formatting throughout the project.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The SOLID Principles
&lt;/h2&gt;

&lt;p&gt;Another key concept in clean code is the SOLID principles, a set of guidelines for object-oriented design developed by Robert C. Martin for designing object-oriented software that aims to make code more flexible, maintainable, and scalable. The SOLID principles consist of the following:&lt;/p&gt;

&lt;h3&gt;
  
  
  Single Responsibility Principle (SRP)
&lt;/h3&gt;

&lt;p&gt;Each class should have a single, well-defined responsibility. This helps prevent unnecessary complexity and makes the code easier to understand and maintain.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
// Bad
public class Customer
{
    public string Name { get; set; }
    public double TotalPurchases { get; set; }
    public bool IsEligibleForDiscount()
    {
        return TotalPurchases &amp;gt;= 100;
    }
    public double CalculateDiscount()
    {
        if (TotalPurchases &amp;gt;= 100)
        {
            return TotalPurchases * 0.1;
        }
        else
        {
            return 0;
        }
    }
    public void ApplyDiscount(double discount)
    {
        TotalPurchases -= discount;
    }
}

// Good
public class Customer
{
    public string Name { get; set; }
    public double TotalPurchases { get; set; }

    public bool IsEligibleForDiscount()
    {
        return TotalPurchases &amp;gt;= 100;
    }
}

public class DiscountCalculator
{
    public static double CalculateDiscount(double totalPurchases)
    {
        if (totalPurchases &amp;gt;= 100)
        {
            return totalPurchases * 0.1;
        }
        else
        {
            return 0;
        }
    }
}

public class Order
{
    public Customer Customer { get; set; }
    public double Total { get; set; }

    public void ApplyDiscount()
    {
        if (Customer.IsEligibleForDiscount())
        {
            double discount = DiscountCalculator.CalculateDiscount(Total);
            Total -= discount;
        }
    }
}


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

&lt;/div&gt;



&lt;p&gt;In this example, the Customer class violates the Single Responsibility Principle because it has multiple responsibilities. It stores customer information and also contains logic for calculating and applying discounts.&lt;/p&gt;

&lt;p&gt;By separating these responsibilities into separate classes, we can better adhere to the Single Responsibility Principle. The Customer class now only has a single responsibility: storing customer information. The DiscountCalculator class has the responsibility of calculating discounts, and the Order class has the responsibility of applying discounts to orders. This makes the code easier to understand and maintain.&lt;/p&gt;

&lt;h3&gt;
  
  
  Open/Closed Principle (OCP)
&lt;/h3&gt;

&lt;p&gt;Classes should be open for extension, but closed for modification. This means that you should be able to add new functionality to a class without changing its existing code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Bad
public class Rectangle
{
    public double Width { get; set; }
    public double Height { get; set; }

    public double CalculateArea()
    {
        return Width * Height;
    }
}

public class Circle
{
    public double Radius { get; set; }

    public double CalculateArea()
    {
        return Math.PI * Radius * Radius;
    }
}

public class AreaCalculator
{
    public double CalculateArea(object shape)
    {
        if (shape is Rectangle)
        {
            return ((Rectangle)shape).CalculateArea();
        }
        else if (shape is Circle)
        {
            return ((Circle)shape).CalculateArea();
        }
        else
        {
            throw new ArgumentException("Invalid shape");
        }
    }
}

// Good
public interface IShape
{
    double CalculateArea();
}

public class Rectangle : IShape
{
    public double Width { get; set; }
    public double Height { get; set; }

    public double CalculateArea()
    {
        return Width * Height;
    }
}

public class Circle : IShape
{
    public double Radius { get; set; }

    public double CalculateArea()
    {
        return Math.PI * Radius * Radius;
    }
}

public class AreaCalculator
{
    public double CalculateArea(IShape shape)
    {
        return shape.CalculateArea();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, the AreaCalculator class is now "closed" for modification, as it does not need to be modified when new shapes are added. Instead, we can simply create new classes that implement the IShape interface and pass them to the CalculateArea method. This allows us to extend the functionality of the AreaCalculator class without modifying its code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Liskov Substitution Principle (LSP)
&lt;/h3&gt;

&lt;p&gt;Subtypes should be substitutable for their base types. This means that if you have a base class and a subclass, the subclass should be able to be used in the same way as the base class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Bad
public class Rectangle
{
    public double Width { get; set; }
    public double Height { get; set; }

    public virtual double CalculateArea()
    {
        return Width * Height;
    }
}

public class Square : Rectangle
{
    public new double Width
    {
        get { return base.Width; }
        set
        {
            base.Width = value;
            base.Height = value;
        }
    }

    public new double Height
    {
        get { return base.Height; }
        set
        {
            base.Width = value;
            base.Height = value;
        }
    }
}

public class AreaCalculator
{
    public double CalculateArea(Rectangle shape)
    {
        return shape.CalculateArea();
    }
}

// Good
public class Rectangle
{
    public virtual double Width { get; set; }
    public virtual double Height { get; set; }

    public virtual double CalculateArea()
    {
        return Width * Height;
    }
}

public class Square : Rectangle
{
    public override double Width
    {
        get { return base.Width; }
        set
        {
            base.Width = value;
            base.Height = value;
        }
    }

    public override double Height
    {
        get { return base.Height; }
        set
        {
            base.Width = value;
            base.Height = value;
        }
    }
}

public class AreaCalculator
{
    public double CalculateArea(Rectangle shape)
    {
        return shape.CalculateArea();
    }
}

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

&lt;/div&gt;



&lt;p&gt;In this example, the Square class violates the Liskov Substitution Principle because it has different behavior than the base Rectangle class. Specifically, setting the Width or Height of a Square also sets the other dimension, which is not the case for a Rectangle. This can cause issues when using the Square class in code that expects a Rectangle.&lt;/p&gt;

&lt;p&gt;By making the Width and Height properties virtual and overridden in the Square class, we ensure that the Square class behaves correctly as a substitute for the Rectangle class. This allows us to use the Square class in the AreaCalculator without any issues.&lt;/p&gt;

&lt;h3&gt;
  
  
  Interface Segregation Principle (ISP)
&lt;/h3&gt;

&lt;p&gt;Clients should not be forced to depend on interfaces they do not use. This means that you should create specific, focused interfaces rather than large, general ones.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Bad
public interface IShape
{
    double Width { get; set; }
    double Height { get; set; }
    double CalculateArea();
    double CalculatePerimeter();
}

public class Rectangle : IShape
{
    public double Width { get; set; }
    public double Height { get; set; }

    public double CalculateArea()
    {
        return Width * Height;
    }

    public double CalculatePerimeter()
    {
        return 2 * (Width + Height);
    }
}

public class Circle : IShape
{
    public double Width { get; set; }
    public double Height { get; set; }

    public double CalculateArea()
    {
        return Math.PI * Width * Height;
    }

    public double CalculatePerimeter()
    {
        return 2 * Math.PI * Math.Sqrt((Width * Width + Height * Height) / 2);
    }
}

// Good
public interface IShape
{
    double CalculateArea();
}

public interface IHasPerimeter
{
    double CalculatePerimeter();
}

public class Rectangle : IShape, IHasPerimeter
{
    public double Width { get; set; }
    public double Height { get; set; }

    public double CalculateArea()
    {
        return Width * Height;
    }

    public double CalculatePerimeter()
    {
        return 2 * (Width + Height);
    }
}

public class Circle : IShape, IHasPerimeter
{
    public double Width { get; set; }
    public double Height { get; set; }

    public double CalculateArea()
    {
        return Math.PI * Width * Height;
    }

    public double CalculatePerimeter()
    {
        return 2 * Math.PI * Math.Sqrt((Width * Width + Height * Height) / 2);
    }
}

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

&lt;/div&gt;



&lt;p&gt;In this example, the IShape interface violates the Interface Segregation Principle because it has both area and perimeter calculation methods. This means that any class that implements IShape must also implement both of these methods, even if it only needs one of them.&lt;/p&gt;

&lt;p&gt;By breaking the IShape interface into two separate interfaces, IShape and IHasPerimeter, we can ensure that classes only need to implement the methods that they actually need. This allows us to create more flexible and maintainable code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dependency Inversion Principle (DIP)
&lt;/h3&gt;

&lt;p&gt;High-level modules should not depend on low-level modules. Instead, both should depend on abstractions. This helps promote flexibility and maintainability.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
// Bad
public class Database
{
    public void Save(object obj)
    {
        // Save object to database
    }
}

public class CustomerService
{
    private readonly Database _database;

    public CustomerService(Database database)
    {
        _database = database;
    }

    public void SaveCustomer(Customer customer)
    {
        _database.Save(customer);
    }
}

// Good
public interface IDatabase
{
    void Save(object obj);
}

public class Database : IDatabase
{
    public void Save(object obj)
    {
        // Save object to database
    }
}

public class CustomerService
{
    private readonly IDatabase _database;

    public CustomerService(IDatabase database)
    {
        _database = database;
    }

    public void SaveCustomer(Customer customer)
    {
        _database.Save(customer);
    }
}


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

&lt;/div&gt;



&lt;p&gt;In this example, the CustomerService class violates the Dependency Inversion Principle because it depends on a concrete implementation of the Database class. This makes it difficult to change the implementation of the database without modifying the CustomerService class.&lt;/p&gt;

&lt;p&gt;By using an interface (IDatabase) and injecting it into the CustomerService class, we invert the dependency. Now, the CustomerService class depends on the abstraction (the interface) rather than the concrete implementation. This allows us to change the implementation of the database without modifying the CustomerService class, making the code more flexible and maintainable.&lt;/p&gt;

&lt;p&gt;By following these principles, you can write clean code and design object-oriented software that is easier to understand, maintain, and extend.&lt;/p&gt;

&lt;p&gt;I would love to hear from you! If you have any tips or experiences that you would like to share with our community, please leave a comment below. Your insights and stories can be incredibly valuable to others who may be struggling through their software engineering careers.&lt;/p&gt;

&lt;p&gt;Thank you in advance for contributing to this discussion!&lt;/p&gt;

</description>
      <category>cleancode</category>
      <category>csharp</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Optimize Your C# Skills: A Comprehensive Guide to Best Practices and Tips</title>
      <dc:creator>Bilal Arshad</dc:creator>
      <pubDate>Tue, 20 Dec 2022 09:46:16 +0000</pubDate>
      <link>https://forem.com/bilalarxd/5-game-changing-c-11-tips-and-tricks-you-need-to-know-with-examples-2cm6</link>
      <guid>https://forem.com/bilalarxd/5-game-changing-c-11-tips-and-tricks-you-need-to-know-with-examples-2cm6</guid>
      <description>&lt;p&gt;C# is a popular programming language that is widely used for developing a variety of applications, including desktop applications, mobile apps, and web applications. To write high-quality C# code, it is important to follow best practices that ensure the code is maintainable, efficient, and easy to understand. In this article, we will discuss some of the best practices for writing C# code, along with examples to illustrate each point.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Use null-coalescing operator to simplify null checks: The null-coalescing operator (??) can be used to simplify null checks by providing a default value if the object is null. For example:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;int? x = null;
int y = x ?? 5; // y will be 5
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use string interpolation for easier string formatting, which allows you to embed expressions in a string using the $ symbol. This can make string formatting easier and more readable. For example:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;string name = "John";
int age = 30;
string message = $"{name} is {age} years old."; // message will be "John is 30 years old."
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use async/await to simplify asynchronous code: Asynchronous programming can be complex, but async/await feature makes it much easier. The "async" keyword can be used to mark a method as asynchronous, and the "await" keyword can be used to pause the execution of the method until an asynchronous task is completed. For example:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private async void Button_Click(object sender, RoutedEventArgs e)
{
    await DoSomethingAsync();
    // Other code here will execute after DoSomethingAsync is completed
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use PascalCase for naming methods, variables, and properties. For example:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public void CalculateTotal()
{
  int studentCount = 10;
  string studentName = "John";
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use camelCase for local variables. For example:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public void CalculateTotal()
{
  int studentCount = 10;
  string studentName = "John";
  double totalMarks = CalculateMarks(studentCount, studentName);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use the var keyword when the type of the variable is obvious from the initialization expression. For example:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var list = new List&amp;lt;int&amp;gt; { 1, 2, 3 };
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use proper indentation and white space to make the code more readable. For example:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (x &amp;gt; 0)
{
  y = x + 1;
}
else
{
  y = x - 1;
}

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

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use proper commenting to document the code. For example:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// This method calculates the total marks for a student
public double CalculateMarks(int studentCount, string studentName)
{
  // Calculate the marks
  double marks = studentCount * 50;

  // Return the marks
  return marks;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use the using statement when working with disposable objects, such as database connections and file streams. This will ensure that the objects are properly disposed of when they are no longer needed. For example:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;using (SqlConnection connection = new SqlConnection(connectionString))
{
  // Perform database operations
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use exception handling to handle runtime errors and prevent the application from crashing. For example:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;try
{
  // Code that may throw an exception
}
catch (Exception ex)
{
  // Code to handle the exception
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use the async and await keywords to perform asynchronous operations and improve the performance of the application. For example:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private async Task&amp;lt;int&amp;gt; CalculateTotalAsync()
{
  int result = await GetDataAsync();
  return result;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By using these best practices and tips, C# developers can write cleaner, more efficient code and take full advantage of the features offered by C#. &lt;/p&gt;

&lt;p&gt;I would love to hear from you! If you have any tips or experiences that you would like to share with our community, please leave a comment below. Your insights and stories can be incredibly valuable to others who may be struggling through their software engineering careers. &lt;/p&gt;

&lt;p&gt;Thank you in advance for contributing to this discussion! I will try to get this article up to date with new stuff. &lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Overcoming Struggles in Your Software Engineering Career</title>
      <dc:creator>Bilal Arshad</dc:creator>
      <pubDate>Mon, 19 Dec 2022 12:22:40 +0000</pubDate>
      <link>https://forem.com/bilalarxd/overcoming-struggles-6-tips-for-software-engineers-looking-to-thrive-in-their-career-4i89</link>
      <guid>https://forem.com/bilalarxd/overcoming-struggles-6-tips-for-software-engineers-looking-to-thrive-in-their-career-4i89</guid>
      <description>&lt;p&gt;If you are a software engineer struggling through your career, here are some tips that might help you get back on track:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Seek guidance and mentorship from experienced professionals. Don't be afraid to ask for help or advice from your colleagues or mentors. They can provide valuable insights and guidance that can help you overcome your struggles.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;One of the most important things you can do as a software engineer is to stay current with the latest technologies and trends in the industry. This means continuously learning and improving your skills. Consider taking online courses or attending conferences and meetups to learn new technologies and keep your skills sharp.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Networking is a powerful tool that can help you advance your career. Attend industry events, join professional organizations, and connect with other professionals in your field. Building relationships with others in your industry can open up new opportunities and help you make valuable connections.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Take breaks and prfioritize self-care. It's important to take care of your physical and mental health to avoid burnout. Make sure to take breaks, exercise regularly, and practice healthy habits to keep yourself energised and focused.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Be proactive and take ownership of your career. Don't wait for opportunities to come to you – seek them out and take charge of your career development. Set goals, create a plan, and work towards them consistently.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Stay positive and don't give up. Struggles are a natural part of any career, and it's important to stay resilient and not get discouraged. Remember that setbacks are temporary and can be overcome with hard work and determination.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If you're feeling stuck in your current role, it might be time to consider seeking out new challenges. This could mean taking on more responsibility within your current organization, or seeking out a new position with a company that offers more opportunities for growth and development.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Participating in the software engineering community can be a great way to learn from others, share your own knowledge, and make a positive impact. Consider contributing to open source projects, participating in hackathons, or joining a local meetup group.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Your portfolio is a powerful tool that can help you stand out in the job market and showcase your skills and experience. Consider building a strong portfolio of your work, including projects you've completed and any contributions you've made to open source projects.&lt;br&gt;
By following these tips, you can overcome your struggles and continue to grow and succeed in your software engineering career.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I would love to hear from you! If you have any tips or experiences that you would like to share with our community, please leave a comment below. Your insights and stories can be incredibly valuable to others who may be struggling through their software engineering careers. Thank you in advance for contributing to this discussion!&lt;/p&gt;

</description>
      <category>testing</category>
      <category>automation</category>
      <category>devops</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>Why you should consider Mono Repo and Single Build? The Silver Bullet</title>
      <dc:creator>Bilal Arshad</dc:creator>
      <pubDate>Tue, 16 Apr 2019 19:41:36 +0000</pubDate>
      <link>https://forem.com/bilalarxd/why-you-should-consider-mono-repo-and-single-build-the-silver-bullet-case-study-31j0</link>
      <guid>https://forem.com/bilalarxd/why-you-should-consider-mono-repo-and-single-build-the-silver-bullet-case-study-31j0</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--703rSqrZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/o3nxkz8ay312w50o6n3n.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--703rSqrZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/o3nxkz8ay312w50o6n3n.jpg" alt="Merge Hell" title="Merge Hell" width="880" height="413"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you have come on this blog by just reading the title and have some weird thoughts about something&lt;/p&gt;

&lt;p&gt;specific, let me clarify that first, NO! I am not going to share 100 ways to kill a Wolf, not even a tip to knock out one. In fact, my title is inspired by a paper No Silver Bullet by Frederick P. Brooks, Jr. which I read during my graduation.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;There is no single development, in either technology or management technique, which by itself promises even one order of magnitude improvement within a decade in productivity, in reliability, in simplicity. &lt;a href="http://faculty.salisbury.edu/~xswang/Research/Papers/SERelated/no-silver-bullet.pdf"&gt;- No Silver Bullet by Frederick P. Brooks, Jr.&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;br&gt;
In this blog, I will explain how we started with existing workflow with First Project, what kind of problems we had, how can we solve them and what we are doing now for the Second Project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Drift with the current
&lt;/h2&gt;

&lt;p&gt;Its been eight months we are working on our first project in PolarBears, Our target was to deliver the First Project as the web app, android app, and iOS App. To support these platforms we decided to develop an API, to have a shared implementation for both clients. So, we ended up creating three repositories for mobile, web and server. To maintain these repositories we divided our team into smaller teams according to available skills and knowledge for each platform. It was time to decide our development workflow, how we will handle branches, builds, deployments and environments.&lt;/p&gt;

&lt;p&gt;We were a newly formed squad and most of the members didn't work with each other previously, our first challenge was to take the team to perform phase as described by Tuckman in his stages of group development. The second challenge was to deliver the project on time, by researching for best approaches or to study how the industry is tackling these issues, we might miss the deadline. So these two in mind we decided to adopt the existing workflow model for our project, which is used by most of the projects in my organization.&lt;/p&gt;

&lt;p&gt;Let me explain that model, there are four environments Development, Quality, Staging, and Production, I will refer them as D, Q, S, and P. To support these environments you have four long-lived (always open) branches Default, Quality, Stable and Production. Every branch is configured with the Bamboo Build Plan which then triggers the Bamboo Deployment Plan for each environment. D is for daily development, Q is for testing by QA, S is for testing by PO and then P is for clients.&lt;/p&gt;

&lt;h2&gt;
  
  
  Merge Hell
&lt;/h2&gt;

&lt;p&gt;Let's dive into a known use-case with this workflow. If you want to promote your D environment to Q environment you just have to merge D branch into Q, by doing this the bamboo will trigger a build on a merge commit if that build results in success, it will then deployed to Q. Same flow for promoting Q to S and S to P. So, by this model if you need to release a new feature X to P environment. You have to develop it on D and then promote it via Q and S to P.The journey from D to P is not that simple as I have described, there are a number of caveats. There would be environment specific issues, and you'll note that these are not present in any other environment. (e.g. Client will report an issue which is working fine on D, Q, and S). I am sure most readers can tell the same story happened to them. So, the question is why this happened? Let me try to answer that question as my best knowledge, Remember that we have branches configured with the Bamboo Builds and whenever you commit code or merge a branch it triggers the Bamboo Build. So if you merge D to Q, Q to S, or S to P the Bamboo will build a new binary for each environment. Which means every time you merge, it seems like you have the same code on D and Q but actually, both builds are different and result in different binaries and deploy-able assets. This is the reason behind these magic words every developer have said once in his life.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;But, it's working on myMachine. [where myMachine = [D,Q,S] //in our case]&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's say we find the issue somehow on other environment and need to fix that. So the question is how should we fix it? you may think that fix it on D and then promote it to Q, S, and P. Yes that's an option but won't it take too much time to fix a bug? Yes, it will take too much time. Why don't we just fix it on P and merge back to S, Q, and D? Yes, we usually use this option to hot-fix issues/bugs on P and sometimes on S and after that, our branches look like the image below also known as merge-hell.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JkGaryyZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/dq1lr666hds97xekp7wc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JkGaryyZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/dq1lr666hds97xekp7wc.png" alt="Merge Hell" title="Merge Hell" width="851" height="702"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The crux of the matter
&lt;/h2&gt;

&lt;p&gt;If we analyze the chosen workflow model and count numbers we'll know what's wrong in it. So, we got three repositories mobile, web and server, each with 4 branches, 4 builds, 4 deployments and 4 environments. In total, we need to take care of 48 things just for a single project. And we did for eight months, It's not just maintenance but time, effort and cost related to this.&lt;/p&gt;

&lt;p&gt;Apart from this cost, imagine if you have to release a new feature which spans across all platforms, with this workflow surely it will result in higher development to production time. With this model, it would be difficult for a developer to work across multiple platforms, which should not happen. We are not just making daily tasks painful but making the whole model less transparent. In order to know the status of a certain feature on another platform, you'll have to do extra work every time. As time passes there is a chance that you’ll be trained on that extra work and it would not be a problem, but higher chances are you'll be less curious and annoyed by doing the same thing again and again.&lt;/p&gt;

&lt;p&gt;So, by design, we have introduced "Viscosity Of Environment” as stated by Robert C. Martin in his book,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Viscosity comes in two forms: viscosity of the software and viscosity of the environment. When faced with a change, developers usually find more than one way to make that change. Some of the ways preserve the design; others do not (i.e., they are hacks). When the design-preserving methods are more difficult to use than the hacks, the viscosity of the design is high. It is easy to do the wrong thing but difficult to do the right thing. We want to design our software such that the changes that preserve the design are easy to make. The viscosity of the environment comes about when the development environment is slow and inefficient. For example, if compile times are very long, developers will be tempted to make changes that don't force a large recompile, even though those changes don't preserve the design. If the source code control system requires hours to check in just a few files, developers will be tempted to make changes that require as few check-ins as possible, regardless of whether the design is preserved. In both cases, a viscous project is one in which the design of the software is difficult to preserve. We want to create systems and project environments that make it easy to preserve and improve the design. - Agile Principles, Patterns, and Practices in C# by Robert C. Martin and Micah Martin&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Another problem to consider is keeping the board updated, which is faced by many developers, including me. So, why doesn't someone fix this problem once for all? why can't we integrate Bitbucket with Jira and let them talk to each other on certain occasions like creating a branch, committing your code, creating a pull request, merging a pull request, and in result they keep the board updated? The answer to all these questions is YES we can and we did. I'll talk about this in detail in a future blog.&lt;/p&gt;

&lt;p&gt;When Polar Bears Squad was formed, our first meeting was to define our value system, "Keep evolving ( nothing remains constant, change is good until it's positive)" was our first value. All these months we had evolution in our core, but, we were not in a position to change repositories, branches, build, environments and workflow for First Project because we were very near to v1.0 release, we knew that if we changed anything we may miss the deadline.&lt;/p&gt;

&lt;h2&gt;
  
  
  A new direction
&lt;/h2&gt;

&lt;p&gt;Three weeks ago we came to know that Second Project is ready to be taken by Polar Bears, and we were very excited to face the new challenge, wait wait wait!!! a new challenge? developing an app with the same technology, same workflow? same branching model? same database? same build plans? and the same deployments? it won’t be a challenge, It's just a “same coffee in new wrapping”. So what will be a challenge then? the challenge would be to fix all the above problems in the new project or at least try it. Here are our problems&lt;/p&gt;

&lt;h4&gt;
  
  
  Mono-Repo
&lt;/h4&gt;

&lt;p&gt;Most top companies like Google, Microsoft, and Facebook are using a mono repository for their project. Mono-Repo means a single repository for everything, divided by folders and sub-folders for multiple projects and modules, they handle millions of commits daily by users and bots, with billions of file changes. Now the question is how they do it? Can tools (like git and mercurial we use daily) handle this amount of commits and data? Obviously not, these three companies have extended existing tools or created their own systems to handle this amount of data. But it doesn't mean we have to create ours too, our code base compared to these giant companies is nothing and these simple tools are able to handle our commits and file changes. So if we just use these tools with mono-repo we'd have support by default. You can read more on these &lt;a href="https://trunkbaseddevelopment.com/"&gt;here&lt;/a&gt; and &lt;a href="https://github.com/cgbystrom/awesome-trunk-based-dev"&gt;here&lt;/a&gt;.&lt;br&gt;
So, It means we can have a single repository having three folders for three platforms, and we will get support out of the box by daily use tools. That's great, isn't it?&lt;/p&gt;

&lt;h4&gt;
  
  
  One Branch
&lt;/h4&gt;

&lt;p&gt;Now the question is aren't we combining all the 48 things to a single repository which was previously divided into three different repositories, we'll have twelve branches in a single repository to maintain and it would be worst then the previous model. Yes, it would be worse if we don't update our workflow with mono-repo. A popular approach which is used widely with mono-repo is trunk based development, which is&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A source-control branching model, where developers collaborate on code in a single branch called ‘trunk’, resist any pressure to create other long-lived development branches by employing documented techniques. They, therefore, avoid merge hell, do not break the build, and live happily ever after. &lt;a href="https://trunkbaseddevelopment.com/"&gt;- Trunk Based Development&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So if we adopt mono-repo with trunk based development we can reduce the number of branches to just 1.&lt;/p&gt;

&lt;h4&gt;
  
  
  One Build
&lt;/h4&gt;

&lt;p&gt;To understand builds, deployments, and environments we need to see what responsibilities and functions they do or serve. Builds clone code, run the transformations over it, install dependencies, build code, create and publish artifacts. Deployments get published artifacts from the build and deploy them to an IP. Environments run on an IP, provides OS and Hosting Server for binaries.&lt;/p&gt;

&lt;p&gt;Every time we commit new code or merge a branch we trigger build and success build triggers deployment. Below are actions executed by build and deployment. Steps may differ based on the project but you'll get an idea what I am talking about.&lt;/p&gt;

&lt;p&gt;(&lt;strong&gt;shared&lt;/strong&gt;: same for D, Q, S, and P | &lt;strong&gt;separate&lt;/strong&gt;: unique for D, Q, S, and P)&lt;/p&gt;

&lt;h5&gt;
  
  
  Build
&lt;/h5&gt;

&lt;ol&gt;
&lt;li&gt;Clone Code (shared)&lt;/li&gt;
&lt;li&gt;Run Transformations (separate)&lt;/li&gt;
&lt;li&gt;Select Configurations (separate)&lt;/li&gt;
&lt;li&gt;Install Dependencies (shared)&lt;/li&gt;
&lt;li&gt;Clean Build (shared)&lt;/li&gt;
&lt;li&gt;Build (shared)&lt;/li&gt;
&lt;li&gt;Create Artifacts (shared)&lt;/li&gt;
&lt;li&gt;Publish Artifacts (shared)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If we look closely only actions which are unique for every environment are the reason to have multiple builds. If we are able to remove or fix those unique actions we can achieve one build. Transformations are smaller code changes which we need for a given environment like changing a variable value based on the environment. We can get rid of them easily if we optimize our code to use configuration settings for these smaller code changes. Now what is left is Configurations which will be different for every environment. If we just remove this step from the build and assign it to deployment to first select configuration before deploying artifacts, we will no longer have any need for multiple builds, and our builds can be reduced to 1.&lt;/p&gt;

&lt;p&gt;4 Deployments and Environments&lt;br&gt;
After changing build actions we will have the following actions for build and deployments.&lt;/p&gt;

&lt;h5&gt;
  
  
  Build
&lt;/h5&gt;

&lt;ol&gt;
&lt;li&gt;Clone Code (shared)&lt;/li&gt;
&lt;li&gt;Install Dependencies (shared)&lt;/li&gt;
&lt;li&gt;Clean Build (shared)&lt;/li&gt;
&lt;li&gt;Build (shared)&lt;/li&gt;
&lt;li&gt;Create Artifacts (shared)&lt;/li&gt;
&lt;li&gt;Publish Artifacts (shared)&lt;/li&gt;
&lt;/ol&gt;

&lt;h5&gt;
  
  
  Deployment
&lt;/h5&gt;

&lt;ol&gt;
&lt;li&gt;Get Published Artifacts (shared)&lt;/li&gt;
&lt;li&gt;Select Configurations (separate)&lt;/li&gt;
&lt;li&gt;Deploy Artifacts to IP (separate)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Generally, deployments are tightly coupled with environments and if we need to reduce the number of deployments we’ll have to reduce the number of environments or have one deployment and change the way our configuration works. To change configurations we can use remote configurations which are supported by AWS, Firebase and other popular platforms. We'll have to implement a way to switch between different environments, And if your squad is using each environment daily, it would be a problem to do that. Let's keep deployments as is for web and server implementation, and focus on the mobile app. A mobile app consumes the API provided by the server or sometimes works on its own. So if our app is consuming the API and providing views and data based on API responses. We are just replacing the API base URL in our deployments and creating a separate deployment for D, Q, S, and P.For mobile, we can configure the deployments to build for P by default, and embed a hidden mechanism to enable D, Q, and S. To do that we can use any custom mechanism like tapping on app logo 10 times, etc. Once we have enabled developer settings or menu, we can provide a drop-down or radio buttons to select environments. To take more control we can provide them with feature-flags and remote configurations. There are already built systems (&lt;a href="//featureflags.io"&gt;featureflags&lt;/a&gt;, &lt;a href="https://launchdarkly.com/use-cases/"&gt;launch-darkly&lt;/a&gt;, and &lt;a href="https://bullet-train.io"&gt;bullet-train&lt;/a&gt;) which serve this very purpose. To read more about feature flags you can read &lt;a href="https://en.wikipedia.org/wiki/Feature_toggle"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So we have reduced our mobile deployment and environment to one, and the rest is the same for now. If there is an update on server or web deployments and environments, I’ll update this section.&lt;/p&gt;

&lt;h2&gt;
  
  
  Time for action
&lt;/h2&gt;

&lt;p&gt;So, for Second Project we are experimenting with this new workflow, with mono-repo, one build to rule all environments, reduced deployments and environments, It will help us to reduce development to production time. We'll be using bullet-train for feature flags and remote configurations, its free for 20,000 requests per month and will serve the purpose like a charm.&lt;/p&gt;

&lt;p&gt;I’ll try to write another part of this with a proof of concept and technical details, so you can see everything in action. In summary, we have reduced repositories from 3 to 1, builds from 12 to 3, deployments from 12 to 9 and environments from 12 to 9. It’s not a big leap but it's your takeaway from this blog.&lt;/p&gt;

&lt;p&gt;Those who didn't get the Wolf joke please read &lt;a href="https://en.wikipedia.org/wiki/Silver_bullet"&gt;this&lt;/a&gt; first, and if you still didn’t get it. &lt;a href="https://www.instructables.com/id/how-to-kill-a-werewolf-1/"&gt;Here&lt;/a&gt; is a three-step procedure to kill.&lt;/p&gt;

&lt;p&gt;Please shout out your thoughts in the comments. Suggestions, criticism, improvements are highly appreciated.&lt;/p&gt;

&lt;p&gt;Thanks&lt;br&gt;
BA&lt;/p&gt;

</description>
      <category>tips</category>
      <category>discuss</category>
      <category>devops</category>
      <category>development</category>
    </item>
  </channel>
</rss>
