• About Blog

    What's Blog?

    A blog is a discussion or informational website published on the World Wide Web consisting of discrete, often informal diary-style text entries or posts.

  • About Cauvery Calling

    Cauvery Calling. Action Now!

    Cauvery Calling is a first of its kind campaign, setting the standard for how India’s rivers – the country’s lifelines – can be revitalized.

  • About Quinbay Publications

    Quinbay Publication

    We follow our passion for digital innovation. Our high performing team comprising of talented and committed engineers are building the future of business tech.

Showing posts with label Best Practices. Show all posts
Showing posts with label Best Practices. Show all posts

Wednesday, April 26, 2023

Benefits & Best Practices of Code Review

Photo by Bochelly

Code reviews are methodical assessments of code designed to identify bugs, increase code quality, and help developers learn the source code. Developing a strong code review process, or utilizing version control, sets a foundation for continuous improvement and prevents unstable code from shipping to customers.

Software developers should be encouraged to have their code reviewed as soon as they’ve completed coding to get a second opinion on the solution and implementation. The reviewer can also act as a second step in identifying bugs, logic problems, or uncovered edge cases. Reviewers can be from any team or group as long as they’re a domain expert. If the lines of code cover more than one domain, we should have experts from both domains.


Benefits of Code Review

Knowledge Sharing: 

When software developers review code as soon as a team member makes changes, they can learn new techniques and solutions. Code reviews help junior developers learn from more senior team members, similar to how peer programming effectively helps developers share skills and ideas. By spreading knowledge across the organization, code reviews ensure that no person is a single point of failure. Everyone has the ability to review and offer feedback. Shared knowledge also helps team members take vacation, because everyone on the team has background knowledge on a topic.

Discover Bugs: 

Rather than discovering bugs after a feature has been shipped and scrambling to release a patch, developers can immediately find and fix problems before customers ever see them. Moving the review process earlier in the software development lifecycle through unit tests helps developers work on fixes with fresh knowledge. When waiting until the end of the lifecycle to do a review, developers often struggle to remember code, solutions, and reasoning. Static analysis is a cheap, efficient way to meet business and customer value.

Maintain Compliance: 

Developers have various backgrounds and training that influence their coding styles. If teams want to have a standard coding style, code reviews help everyone adhere to the same standards. This is especially important for open source projects that have multiple individuals contributing code. Peer reviews bring in maintainers to assess the code before pushing changes.

Enhance Security: 

Application security is an integral part in software development, and code reviews help ensure compliance. Security team members can review code for vulnerabilities and alert developers to the threat or even setup the quality gates in static code analysis to make sure they are identified well ahead. If your application is dealing with sensitive information then team should be trained on secure coding practices.

Increase Collaboration: 

When team members work together to create a solution, they feel more ownership of their work and a stronger sense of belonging. Authors and reviewers can work together to find the most effective solutions to meet customer needs. It’s important to strengthen collaboration across the software development lifecycle to prevent information silos and maintain a seamless workflow between teams. To successfully conduct code reviews, it’s important that developers build a code review mindset that has a strong foundation in collaborative development.


Best Practices

What to look for during the code review

It’s important to go into reviews knowing what to look for in a code review. Look for key things like code structure, style, logic. performance, test coverage, code readability and maintainability.

You can do automated checks (e.g., static analysis of the code) for some of the things like structure, style, standards and logic. But others areas like design and functionality, requires a human reviewer to evaluate as we don't have any tools for the same.

Reviewing code with certain questions in mind can help you focus on the right things. For instance, you might evaluate code to answer:

  • Do I understand what the code does? 
  • Does the code function as per the requirements? 
  • Does this code has been written as per the company standards requirements?

Build and Test — Before Code Review

In today’s time, we have Continuous Integration setup as part of the process. It’s key to build and test before doing a manual review. Ideally, the code review should be done after tests have passed. This ensures stability and doing automated checks first will cut down on errors and save time in the review process.

Limit Review Time for 45-60 Minutes

Never review for longer than 45 - 60 minutes at a time. Performance and attention-to-detail tend to drop off after that point. It’s best to conduct code reviews often (and in short sessions). Taking a break will give your brain a chance to reset. So, you can review it again with fresh eyes.

Review 300 Lines at a Time

If you try to review too many lines of code at once, you’re less likely to find defects. Try to keep each code review session to 300 lines or less. Setting a line-of-code (LOC) limit is important for the same reasons as setting a time limit. It ensures you are at your best when reviewing the code.

Give Feedback that Helps

Try to be constructive in your feedback, rather than critical. Be kind, explain your reasoning, balance giving explicit directions with just pointing out problems and letting the developer decide and encourage developers to simplify code or add code comments instead of just explaining the complexity to you.

Giving feedback in-person for the new members will help you communicate with the right tone as they will be new to the process.

Communicate Goals and Expectations

You should be clear on what are the goals of the review, as well as the expectations from reviewers. Giving your reviewers a checklist will ensure that the reviews are consistent. Engineers will evaluate each other’s code with the same criteria in mind.

By communicating goals and expectations, everyone saves time. Reviewers will know what to look for — and they’ll be able to use their time wisely in the review process.

Include Everyone in the Code Review Process

No matter how senior the engineer is, everyone needs to review and be reviewed. After all, everyone performs better when they know someone else will be looking at their work. When you’re running reviews, it’s best to include engineer and leads/architect. They’ll spot different issues in the code, in relation to both the broader codebase and the overall design of the product.

Including everyone in the review process improves collaboration and relationships between programmers.

Automate to Save Time

There are some things that reviewers will need to check in manual reviews. But there are some things that can be checked automatically using the right tools. Static code analyzers, for instance, find potential issues in code by checking it against coding rules. Running static analyzers over the code minimizes the number of issues that reach the peer review phase. Using tools for lightweight reviews can help, too.

By using automated tools, you can save time in peer review process. This frees up reviewers to focus on the issues that tools can’t find — like usability.

Conclusion

Code review is a critical process in software development that helps ensure the quality, reliability, and maintainability of the codebase. By following these best practices, your code review process can be an effective tool for ensuring that your codebase is high-quality and maintainable, while also promoting a positive and productive development culture.

I would like to thank my wonderful team members who bought the idea of why code review is important and helped me to build automation to save time for everyone. We automated to identify number of lines of code updated in a pull request. If the lines is above X number then it will reject the pull request by adding an appropriate message for the author. 

Thanks to the latest version of sonar which allows us to have a pull request based analysis that considers only the code that are added/updated. Automated the first round of the code review is done by a bot which pulls the data from the static analysis tool and highlights blockers, critical and major technical debts within the new code added.


Monday, September 13, 2021

Redis Overview and Benchmark

What is Redis?
Image Courtesy Morioh

ReDiS which stands for Remote Directory Server, is an open source in-memory data store, used as a database and as a cache. Redis provides data structures such as strings, hashes, lists, sets and sorted sets. Redis has built-in replication, Lua scripting, LRU eviction, transactions, and different levels of on-disk persistence and provides high availability via Redis Sentinel and automatic partitioning with Redis Cluster.

Redis is an open source, advanced key-value store and an apt solution for building highperformance, scalable web applications.

Redis has three main features that sets it apart from others:

  • Redis holds its database entirely in the memory, using the disk only for persistence.
  • Redis has a relatively rich set of data types when compared to many key-value data stores.
  • Redis can replicate data to any number of slaves.


Following are certain advantages of Redis:

  • Exceptionally fast − Redis is very fast and can perform about 110000 SETs per second, about 81000 GETs per second.
  • Supports rich data types − Redis natively supports most of the datatypes that developers already know such as list, set, sorted set, and hashes. This makes it easy to solve a variety of problems as we know which problem can be handled better by which data type.
  • Operations are atomic − All Redis operations are atomic, which ensures that if two clients concurrently access, Redis server will receive the updated value.
  • Multi-utility tool − Redis is a multi-utility tool and can be used in a number of use cases such as caching, messaging-queues (Redis natively supports Publish/Subscribe), any short-lived data in your application, such as web application sessions, web page hit counts, etc.

Redis Monitoring

Availability, the redis server will respond to the PING command when it's running smoothly.

$ redis-cli -h 127.0.0.1 ping
PONG

Cache Hit Rate

This information can be calculated with the help of INFO command.

$ redis-cli -h 127.0.0.1 info stats | grep keyspace
keyspace_hits:1069963628
keyspace_misses:2243422165

Workload Statistics

The first two stats talks about connections and commands processed where last two stats talk about bytes received and sent from the redis server.

$ redis-cli -h 127.0.0.1 info stats | grep "^total"
total_connections_received:1687889
total_commands_processed:5602955422
total_net_input_bytes:198210899161
total_net_output_bytes:309040592973

Key Space

Anytime to know number of keys in the database, use this command. The size of the keyspace with a quick drop or spike in the number of keys is a good indicator of issues.

$ redis-cli -h 127.0.0.1 info keyspace
# Keyspace
db0:keys=3857884,expires=277,avg_ttl=259237

Clear Keys

We can clear all the keys from the Redis, using the below command.

$ redis-cli -h 127.0.0.1
127.0.0.1:6379> flushall


How to Perform Redis Benchmark?

Redis benchmark is the utility to check the performance of Redis by running n commands simultaneously.

redis-benchmark [option] [option value]

Option Description
-h Specifies server host name 127.0.0.1
-p Specifies server port 6379
-c Specifies number of parallel connections, default is 50
-n Specifies total number of requests, default is 100000
-d Specifies data size of SET/GET value in bytes, default is 3
-r Use random keys for SET/GET/INCR
-q Forces Quiet to Redis. Just shows query/sec values
-l Generates loop, Run the tests forever
-t Only runs the comma-separated list of tests
--csv
Output in CSV format

$ redis-benchmark -h 127.0.0.1 -n 100000 -q
PING_INLINE: 57306.59 requests per second
PING_BULK: 57273.77 requests per second
SET: 56657.22 requests per second
GET: 57012.54 requests per second
INCR: 57240.98 requests per second
LPUSH: 57045.07 requests per second
RPUSH: 56657.22 requests per second
LPOP: 57142.86 requests per second
RPOP: 57175.53 requests per second
SADD: 56369.79 requests per second
HSET: 55679.29 requests per second
SPOP: 54704.60 requests per second
LPUSH (needed to benchmark LRANGE): 52798.31 requests per second
LRANGE_100 (first 100 elements): 35448.42 requests per second
LRANGE_300 (first 300 elements): 17618.04 requests per second
LRANGE_500 (first 450 elements): 12812.30 requests per second
LRANGE_600 (first 600 elements): 10036.13 requests per second
MSET (10 keys): 47281.32 requests per second

References

Thursday, June 24, 2021

Template Method Pattern - Skeleton is Defined in Base Class

Template Method Design Pattern
Photo Courtesy Unsplash

What is the Template Method Design Pattern?

The Template Method Design Pattern defines a sequence of steps of an algorithm and allows the subclasses to override the steps but do not allow to change the sequence. The Key to the Template Design Pattern is that we put the general logic in the abstract parent class and let the child classes define the specifics.

Template Method pattern falls under the behavioural design pattern, is one of the easiest to understand and implement. This design pattern is used popularly in framework development and also helps to avoid code duplication.

An abstract class contains the templateMethod which should be made final so that it cannot be overridden. This template method makes use of other operations available in order to run the algorithm but is decoupled for the actual implementation of these methods. Concrete class implements all the methods required by the templateMethod that were defined as abstract in the parent class.

Pattern Implementation

As am a coffee person, I will take an example of preparing the coffee using a template method pattern which should allow to understand the pattern easily instead of taking some framework implementations such as AbstractController, RequestProcessor, HttpServlet, InputStream, OutputStream etc.

public abstract class CoffeeMaker {
   protected boolean sugarFree = false;

   public void prepareCoffee() {
      boilWater();
      addMilk();
      if (!isSugarFree()) {
         addSugar();
      } else {
 System.out.println("- No Sugar")
      }
      addCoffeePowder();
      System.out.println("- Coffee is Ready!!!");
   }

   public final void boilWater() {
      System.out.println("- Boiling Water");
   }

   public boolean isSugarFree() {
      return sugarFree;
   }

   public void setSugarFree(boolean sugarFree) {
      this.sugarFree = sugarFree;
   }

   abstract void addMilk();
   abstract void addSugar();
   abstract void addCoffeePowder();
}

Now we will create 2 concrete classes which will provide different implementations.

public class CothasCoffeeMaker extends CoffeeMaker {
   @Override
   public void addMilk() {
      System.out.println("- Adding Milk");
   }

   @Override
   public void addSugar() {
      System.out.println("- Adding Sugar");
   }

   @Override
   public void addCoffeePowder() {
      System.out.println("- Adding Cothas Coffee Powder");
   }
}

public class BruCoffeeMaker extends CoffeeMaker {
   @Override
   public void addMilk() {
      System.out.println("- Adding Milk");
   }

   @Override
   public void addSugar() {
      System.out.println("- Adding Sugar");
   }

   @Override
   public void addCoffeePowder() {
      System.out.println("- Adding Bru Coffee Powder");
   }
}

Now it's time to write the main method to execute the above code and see the output of the two variations of the coffee.

public class CoffeeMakerExample {
   public static void main(String[] args) {
      System.out.println("Cothas Coffee Preparation")
      CoffeeMaker coffeeMaker = new CothasCoffeeMaker();
      coffeeMaker.prepareCoffee();

      System.out.println("Bru Coffee Preparation");
      coffeeMaker = new BruCoffeeMaker();
      coffeeMaker.setSugarFree(true);
      coffeeMaker.prepareCoffee();
   }

}

The CoffeeMaker class is an abstract class containing the algorithm skeleton. The prepareCoffee() is the method that contains the process steps. The boilWater() method is common step for the process of any coffee preparation and no customization is required, hence it has been made as final so the subclasses will not override and provide a different implementation. 

We have two subclasses CothasCoffeeMaker and BruCoffeeMaker which follows the same preparation process but implementation are given at each individual subclass.

If you execute the above program, you should see the following output.

Cothas Coffee Preparation
- Boiling Water
- Adding Milk
- Adding Sugar
- Adding Cothas Coffee Powder
- Coffee is Ready!!!

Bru Coffee Preparation
- Boiling Water
- Adding Milk
- No Sugar
- Adding Bru Coffee Powder
- Coffee is Ready!!!

Conclusion

  • The pattern promotes the code reusability and decoupling, but at the expense of using inheritance.
  • The pattern adhers to the Single Responsibility and Open/Closed principles of S.O.L.I.D - Design Principles.

Reference

Tuesday, May 25, 2021

Singleton Design Pattern - Build It, Break It and Fix It!

Singleton Design Pattern
Photo Courtesy Unsplash


Singleton pattern is one of the simplest design patterns and falls under creational pattern as this pattern provides one of the best ways to create an object. This pattern involves a single class which is responsible for creating an object while making sure that the instantiation of a class to only one object. This class provides a way to access its only object which can be accessed directly without instantiating the object of the class.

Let’s see various design options for implementing the pattern. If you have a good hold on static class variables and access modifiers this is not a difficult task.

Lazy Instantiation

public class Singleton implements Serializable {

  private static Singleton singletonObject;

  //Adding a private constructor so that no one creates object
  private Singleton() {
  }

  public static Singleton getInstance() {
    if (singletonObject == null) {
      singletonObject = new Singleton();
    }
    return singletonObject;
  }

}

Here we have declared getInstance() as static so that we can call it without instantiating the class. First time, when getInstance() method is called, it creates a new Singleton object and later it just returns the same object reference. Note that singletonObject is not created until we call the getInstance() method, as we are using the lazy instantiation of the object.

The main problem with the above method is that it is not thread safe. If we have two threads T1 and T2 which invokes the getInstance() method at the same time, the execution sequence creates two objects for Singleton.

The other option is to make getInstance() method as synchronized. Here, using synchronized keyword makes sure that only one thread is allowed at a time to execute getInstance() method. The main disadvantage of this is method is, that using synchronized every time while creating the Singleton object is expensive and may decrease the performance of your program. However if performance of getInstance() is not critical for the application this method provides a clean and simple solution.

Eager Instantiation

public class Singleton implements Serializable {

  private static Singleton singletonObject = new Singleton();

  //Adding a private constructor so that no one creates object
  private Singleton() {
  }

  public static Singleton getInstance() {
    return singletonObject;
  }
  
}


Here we have created instance of Singleton with the help of static initializer. JVM executes static initializer when the class is loaded and hence this is guaranteed to be thread safe. Use this method only when the Singleton class is light and is used throughout the execution of the program.

Double Check and Locking Instantiation

public class Singleton implements Serializable {

  private static volatile Singleton singletonObject;

  //Adding a private constructor so that no one creates object
  private Singleton() {
  }

  public static Singleton getInstance() {
    if (singletonObject == null) {
      // Making thread safe
      synchronized(Singleton.class) {
        // Check again as object is still null
        if (singletonObject == null) {
          singletonObject = new Singleton();
        }
      }
    }
    return singletonObject;
  }
    
}

In the above implementation, we have declared the singletonObject as volatile. Using volatile is yet another way (like synchronized, atomic wrapper) of making class thread safe. Thread safe means that a method or class instance can be used by multiple threads at the same time without any problem. This method drastically reduces the overhead of calling the synchronized method every time.

Now that we know how to implement a Singleton pattern in 3 different ways. Let’s see whether we can break the Singleton pattern ?

Reflection

Reflection is a feature in the Java programming language. It allows an executing Java program to examine or introspect upon itself, and manipulate internal properties of the program. For example, it’s possible for a Java class to obtain the names of all its members and display them.

We will use Reflection and see whether we can break the Singleton or not ?

class Singleton implements Serializable {

  private static Singleton singletonObject = new Singleton();

  //Adding a private constructor so that no one creates object
  private Singleton() {
  }

  public static Singleton getInstance() {
    return singletonObject;
  }
  
}

public class SingletonExample {
  
  public static void main(String[] args) {
    try {
        Singleton obj1 = Singleton.getInstance();
        System.out.println("Singleton.getInstance().hashCode: " + obj1.hashCode());

        Constructor constructor = Singleton.class.getDeclaredConstructor();
        constructor.setAccessible(true);
        Singleton obj2 = (Singleton) constructor.newInstance();
        System.out.println("Reflection.newInstance().hashCode: " + obj2.hashCode());
    }
    catch (Exception e) {
        e.printStackTrace();
    }
  }
  
}

If you execute the above program, you should see in the output that the hashCode of both objects are different and it clearly violates Singleton pattern.

Singleton.getInstance().hashCode: 1418481495
Reflection.newInstance().hashCode: 303563356

Let’s fix this loop hole by making some simple code change in the Singleton constructor.

private Singleton() {
    if (singletonObject != null) {
        throw new IllegalStateException("Already Initialised!");
    }
}

Now if you execute the program with the above changes, the line 24 will call the constructor and it will throw an IllegalStateException. Thus prevents the creation of the second instance.

Caused by: java.lang.IllegalStateException: Already initialised!

What if I change the access level of the singleton field from private to public using the Reflection? Oops… it will allow me to set the singleton object to null and it will create a new object. Let’s modify our main method to hack the Singleton class.

public static void main(String[] args) {
    try {
        Singleton obj1 = Singleton.getInstance();
        System.out.println("Singleton.getInstance().hashCode: " + obj1.hashCode());

        Field field = Singleton.class.getDeclaredField("singletonObject");
        field.setAccessible(true);
        field.set(field, null);
        
        Constructor constructor = Singleton.class.getDeclaredConstructor();
        constructor.setAccessible(true);
        Singleton obj2 = (Singleton) constructor.newInstance();
        System.out.println("Reflection.newInstance().hashCode: " + obj2.hashCode());
    }
    catch (Exception e) {
        e.printStackTrace();
    }
}

Using Reflection, we are changing the value of the instance field to NULL after the object gets created. When we invoke the constructor, the condition fails as singleton instance is null hence it will allow you to create another instance.

We can prevent it by declaring the singletonObject instance as FINAL so that it’s value can’t be changed once assigned.

private final static Singleton singletonObject = new Singleton();

Now if you execute the program, it will throw an IllegalAccessException. Reflection can’t convert final field to non-final field. Please note, this approach only works with Eager Instantiation method.

Serialization

Java provides a mechanism, called object serialization where an object can be represented as a sequence of bytes that includes the object’s data as well as information about the object’s type and the types of data stored in the object.

After a serialized object has been written into a file, it can be read from the file and deserialized, i.e., the type information and bytes that represent the object and its data can be used to recreate the object in memory.

Most impressive is that the entire process is JVM independent, meaning an object can be serialized on one platform and deserialized on an entirely different platform.

We will use Serialization and see whether we can break the Singleton or not ?

class Singleton implements Serializable {

  private final static Singleton singletonObject = new Singleton();

  //Adding a private constructor so that no one creates object
  private Singleton() {
    if (singletonObject != null) {
      throw new IllegalStateException("Already Initialised!");
    }
  }

  public static Singleton getInstance() {
    return singletonObject;
  }
  
}

public class SingletonExample {
  
  public static void main(String[] args) {
    try {
        Singleton obj1 = Singleton.getInstance();
        System.out.println("Singleton.getInstance().hashCode: " + obj1.hashCode());
      
        // Serialize the object to file
        ObjectOutput objectOutput = new ObjectOutputStream(new FileOutputStream("file.txt"));
        objectOutput.writeObject(obj);
        objectOutput.close();

        // DeSerailize the object from file
        ObjectInput objectInput = new ObjectInputStream(new FileInputStream("file.txt"));
        Singleton obj2 = (Singleton) objectInput.readObject();
        in.close();

        System.out.println("Serialization.getInstance().hashCode: " + obj2.hashCode());
    }
    catch (Exception e) {
        e.printStackTrace();
    }
  }
  
}

If you execute the above program, you should see in the output that the hashCode of both objects are different and it clearly violates Singleton pattern.

Singleton.getInstance().hashCode: 1418481495
Serialization.getInstance().hashCode: 565760380

Let’s fix this loop hole by making some simple code change in the Singleton class. We have to implement readResolve() method and return the singletonObject reference.

protected Object readResolve() {
    return singletonObject;
}

Conclusion

  • We saw how to implement the Singleton Pattern in different ways like Lazy Instantiation, Eager Instantiation and Double Check and Locking Instantiation.
  • We saw how we can break the Singleton Pattern using the Reflection and Serialization methods.
  • Also, we saw how it can be prevented by making few code changes so the Singleton Pattern won’t allow you to create more than one instance.

References:




Wednesday, February 10, 2021

Vue JS — Best Practices

 Vue JS Logo

VueJS — The Progressive JavaScript Framework

Vue (pronounced /vjuː/, like view) is a progressive framework for building user interfaces. Unlike other monolithic frameworks, Vue is designed from the ground up to be incrementally adoptable. The core library is focused on the view layer only, and is easy to pick up and integrate with other libraries or existing projects. On the other hand, Vue is also perfectly capable of powering sophisticated Single-Page Applications when used in combination with modern tooling and supporting libraries.

If you are an experienced frontend developer and want to know how Vue compares to other libraries/frameworks, check out the Comparison with other Frameworks.

Lifecycle Hooks

Every Vue instance goes through a series of initialisation steps. When it is created from setting up data observation to compiling the template, to mounting the instance to the DOM, and finally to updating the DOM during data changes. This process is known as the lifecycle of a Vue instance and they have some functions run inside them by default as they go through this process of creating and updating the DOM. It is inside them that Vue components are created and manipulated, these functions are called lifecycle hooks.

There are eight lifecycle methods:

  1. Before Create
  2. Created
  3. Before Mount
  4. Mounted
  5. Before Update
  6. Updated
  7. Before Destroy
  8. Destroyed

If interested, take a look at  the Lifecycle Diagram of Vue JS. Refer to the official page which has complete details about each lifecycle hooks.

Be Aware of Camel vs Kebab Case

JavaScript are case-sensitive aka Counter is not equal to counter. As HTML, in general is case-insensitive, especially the HTML attributes. As VueJS spans both of these worlds, it’s better to understand this clearly.

camelCase

Start with lower-case and combine subsequent words by capitalise them. Example: amInCamelCase.

kebab-case

Write everything in lower-case and separate words by hyphens. Example: this-is-a-kebab-case.

To help you out, VueJS translates camelCase prop names into kebab-cased equivalent. But whenever things happen automatically, you need to be aware of it.

Vue.component('my-component', {
  props: ['myPropertyMessage'], // camelCase in JavaScript
  template: '<h1>{{myPropertyMessage}}</h1>'
})

The above JS code will translate to something like below

<!-- kebab-case in HTML -->
<my-component my-property-message="Hello World!"></my-component>

Hence declare props with camelCase and use Kebab Case in Templates.

Always use kebab-case for event names

When emitting/listening to custom events, we should always use kebab-case. Why? Because the events will be transformed automatically into lowercase anyway. We wont be listening to an event in camelCase or PascalCase, therefore, makes more sense to declare the event the same way we are going to listen to it: in kebab-case.

// Emitting
this.$emit('my-event') // instead of myEvent

// Listening
v-on:my-event

Always use :key in v-for loops

Is a common best practice to always add a :key to your template loops. A v-for without a :key can lead to hard to find errors, especially with certain kind of components or objects.

Don’t use v-if With v-for Elements

It’s a clear advice from the style guide from vuejs.org

<div v-for='plan in subscriptionPlans' v-if='plan.type == 1'></div>

The reason is that VueJS assigns a higher priority of the v-for than the v-if. This leads to a performance issue as the loop would run and filter inside instead of filter first.

The best practice here is to reduce the size to iterate over before the iteration by using a computed property:

computed: {
  onSaleSubscriptions: function() {
    return this.subscriptionPlans.filter(function (plan) {
       return(plan.type == 1)
    })
  }
}

Use $_ for mixins properties

Mixins are a great way to get repeated code into one single block and import it as many times as you want, but this can lead to several issues. In this point we will address the issue of overlapping properties.

When we import a mixin into our Component we are merging the mixin code with our component code. Now what happens with property that have the same name? Component will always have the upper hand as their properties have higher priority.

What if I want my mixin to have more priority? You can’t assign a priority but you can avoid properties from overlapping or even from overwriting by choosing a correct naming convention.

In order to differentiate mixin properties from Component properties we use $_. Why these symbols? Well, several reasons:
  • Convention from VueJs style guide
  • _ is reserved for Vue’s private properties
  • $ is reserved for Vue’s ecosystem

var authMixin = {
   //...
   methods: {
      $_authMixinGetUserInfo(){
         //...
      }
   }
}

Clear event listeners on component destroy with $off

When listening to events with $on, we should always remember to remove that listener with $off on destroyed(). This prevents us from having memory leaks.

const EmployeeComponent = { 
  mounted() {
    console.log("Employee component mounted");
    this.notify.$on("manager", this.startedListening);
  },
  beforeDestroy() {
    console.log("Employee component before destroy");
    // Remove all listening events.
    this.notify.$off("manager", this.stoppedListening);
  },
  methods: {
    startedListening() {
      // callback
    },
    stoppedListening() {
      // callback
    },
  },
};

Sources:


Featured Post

Your AI Sidekick: How Claude took over Pritee’s Repetitive tasks

  It was a classic Wednesday morning in our Bengaluru office . Pritee, one of our sharpest Project Managers, had just stepped out of a stake...