Showing posts with label DesignPatterns. Show all posts
Showing posts with label DesignPatterns. Show all posts

Code smell

2022-04-17

Note that a CodeSmell is a hint that something might be wrong, not a certainty. A perfectly good idiom may be considered a CodeSmell because it's often misused, or because there's a simpler alternative that works in most cases. Calling something a CodeSmell is not an attack; it's simply a sign that a closer look is warranted.

One of the nice things about smells is that it's easy for inexperienced people to spot them, even if they don't know enough to evaluate if there's a real problem or to correct them. I've heard of lead developers who will pick a "smell of the week" and ask people to look for the smell and bring it up with the senior members of the team. Doing it one smell at a time is a good way of gradually teaching people on the team to be better programmers.

Some examples of code smells

Conditional Complexity

Watch out for large conditional logic blocks, particularly blocks that tend to grow larger or change significantly over time. Consider alternative object-oriented approaches such as decorator, strategy, or state.

Combinatorial Explosion

You have lots of code that does almost the same thing.. but with tiny variations in data or behavior. This can be difficult to refactor-- perhaps using generics or an interpreter?

Oddball Solution

There should only be one way of solving the same problem in your code. If you find an oddball solution, it could be a case of poorly duplicated code-- or it could be an argument for the adapter model, if you really need multiple solutions to the same problem.

Data Clumps

If you always see the same data hanging around together, maybe it belongs together. Consider rolling the related data up into a larger class. 

Indecent Exposure

Beware of classes that unnecessarily expose their internals. Aggressively refactor classes to minimize their public surface. You should have a compelling reason for every item you make public. If you don't, hide it.

Feature Envy

Methods that make extensive use of another class may belong in another class. Consider moving this method to the class it is so envious of.

Long method names

Seriously: If you follow good naming standards, long method names are often an indication that the method is in the wrong class. For example,

createWhateverFromWhateverOtherClass(OtherClass creator) vs

creator.createWhatever(). See UsingGoodNamingToDetectBadCode.



Duplicated Code

Balance the smell against the cost of reducing it in your environment. Each environment (language, linkers, etc) has its own threshold for how much duplication you can remove without it being too painful or too obfuscating.

Consequently if a company spent X dollars to develop a product with duplicated code it will have to spend X * K dollars on code refactoring without any single visible improvement of the product, where K is between 3 and 100 depending on skills, complexity, language, etc.

Some companies hire more and more developers to pay interest on that duplication debt or keep changing developers wondering why production emergencies don’t disappear even with best minds on it.

Switch Statements Smell

ObjectOrientedProgramming avoids them: "Most times you see a switch statement, you should consider polymorphism. This is not to say that SwitchStatementsAreEvil, just that they aren't ObjectOriented. Please note also that not all programs that use switches exhibit the CodeSmell.

When you get the SwitchStatementsSmell, it's an indication that your code isn't ObjectOriented. It could also be a case of following the rule DoTheSimplestThingThatCouldPossiblyWork.

Classes with too much code -

See: OneResponsibilityRule, GodClass
Violates the Single responsibility principle of SOLID

Principle of Least Knowledge or Law of Demeter(LOD)

An object should avoid invoking methods of an object returned by another method. For many modern object oriented languages that use a dot as field identifier, the law can be stated simply as "use only one dot". That is, the code a.m().n() breaks the law where a.m() does not.

Ref: https://wiki.c2.com/?SwitchStatementsSmell 

https://wiki.c2.com/?CodeSmell

http://mywwwexperience.blogspot.com/2022/03/principle-of-least-knowledge-or-law-of.html

Dependency Injection Design Pattern and IoC Principle

2022-04-04

 Consider a typical scenario where we have a client class which calls another class (can be referred here as service class as it provides service to the calling client class). So the client class has dependency with a specific service class. Now later if there is a new service to be invoked by the client then we need to rewrite the client class in the area where the existing service class to be replaced with new service class. This is called dependency of the client with its service class and its clear example of tight coupling. Dependency injection is a design pattern which eliminates this type of dependency of a class independent of its dependencies. 

This DI is an example of one way of achieving the Dependency Inversion principle found in the SOLID philosophy. The practice of dependency injection is made possible by following the dependency inversion principle.

Typical code without DI pattern will look like as given below:


using System;
namespace DISample
{
    class Program
        {
            static void Main(string[] args)
                {
                    Customer objClient=new Customer();
                    string orderResponse = objClient.OrderFood();
                    Console.WriteLine(orderResponse);
                }
         }

Public class Customer
{
    public string OrderFood()
        {
            Zomato objShopAService=new Zomato();
            return objShopAService.Order();    
        }
}

Public class Zomato
{
    public string Order()
    {
        return "Thanks for ordering in Zomato. Please wait we are going to deliver asap.";
    }
}

public class Swiggy
{
    public string Order()
    {
      return "Thanks for ordering in Swiggy. Your food will be delivered soon by our courier guy.";
    }
}

Public class UberEats
{
   public string Order()
   {
     return "Thanks for ordering in UberEats. We are sending your food now!";
   }
}

}

So what if the client class here (i.e. Customer changes his mind to place the order from UberEats instead of Zomato. Since the customer class is currently tightly coupled as per the implementation we need code to be recompiled whenever the client wishes to change its services. And this implementation is difficult to unit test.

Now let us use the how DI design pattern helps to decouple the classes and how the class can be independent from the creation of the objects it depends on. 

There are 4 components in the DI design pattern which helps in achieving this pattern:

1. Client class; client class depends on the service class(in sample its Customer class)

2. Service class; which provides service to the client class(in sample its Swiggy,Zomato,UberEats class)

3. Interface: (the interface which defines the contract of the service class, interface is IOnlineFoodDelivery in below sample. As the Dependency Inversion Principle suggests modules should depend on abstractions. So to have the abstractions implemented we go for an abstraction with the help of interface)

4. Injector: (Injector class injects the service class object into the client class, injector is done in Main() of Program class in below sample)


using System;
namespace DISample
{
    class Program
    {
        static void Main(string[] args)
        {
            Customer objCust=new Customer(new Zomato());
        }
}

public class Customer
{
    IOnlineFoodDelivery _iOnlineFoodDelService;
    public Customer(IOnlineFoodDelivery pIOnlineFoodDelivery)
    {

        _iOnlineFoodDelService=pIOnlineFoodDelivery;
        Console.WriteLine(_iOnlineFoodDelService.Order());
    }
}

public interface IOnlineFoodDelivery
{
    public string Order();
}

public class Zomato:IOnlineFoodDelivery
{
    public string Order()
       {
            return "Thanks for ordering in Zomato. Please wait we are going to deliver asap.";
       }
}

public class Swiggy:IOnlineFoodDelivery
{
    public string Order()
    {
        return "Thanks for ordering in Swiggy. Your food will be delivered soon by our courier guy.";
    }
}

public class UberEats:IOnlineFoodDelivery
{
    public string Order()
    {
        return "Thanks for ordering in UberEats. We are sending your food now!";
    }
 }
}

Types of Dependency Injection:
There are 3 ways how the injector can inject the service class object to the client
1. Constructor injection: The dependencies are provided through a client's class constructor.(above sample code)
2. Setter injection: The client exposes a setter method that the injector uses to inject the dependency.
3. Interface injection: The dependency's interface provides an injector method that will inject the dependency into any client passed to it.

Dependency injection separates the creation of a client's dependencies from the client's behavior, which promotes loosely coupled programs and the dependency inversion and single responsibility principles.

Dependency injection is an example of design pattern which implements the Inversion of Control(IoC). IoC is a programming principle, IoC inverts the flow of control as compared to traditional control flow.

Inversion of control serves the following design purposes:
To decouple the execution of a task from implementation.
To focus a module on the task it is designed for.
To free modules from assumptions about how other systems do what they do and instead rely on contracts.
To prevent side effects when replacing a module.

Inversion of control is sometimes facetiously referred to as the "Hollywood Principle: Don't call us, we'll call you".

As a discipline, dependency injection separates how objects are constructed from how they are used. As a result, dependency injection frameworks often diminish the importance of the new keyword found in most object-oriented languages.

The need of understanding the patterns used in the frameworks behind the tools/technologies

2022-03-14

 For developers entering or working in the field right now, it's important to understand the architecture behind the tools and frameworks you are using to prepare yourself for the future, Hammond said. 

"What I found over the past almost 30 years is, the languages change, the frameworks change, the vendors change, but these implementation patterns tend to repeat themselves in each era," Hammond said. "If you understand that, you can begin to see the differences as new technologies come out and apply what you already know in these new contexts." 

Ref: https://www.techrepublic.com/article/how-programming-will-change-over-the-next-10-years-5-predictions/[September 17, 2018, 4:00 AM PST ]

IMO Rather than going through the new learning of technologies or online learning courses, go through the core subject & get a basic understanding of networking, complier, data structures & algorithms, socket programming, Operating systems as much as possible because the underlying technologies of any s/w are built on these & having insight about the basics will help to understand the issues facing, concepts such as performance bench marks, n/w communication issues etc.

Note: the underlying technologies of SSL or TLS not changed for the past 20 years so is TCP/IP so is HTTP so is OS so is networking so is data structures & algorithms.

If you check the version of HTTP its still 1.1