<?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>DEV Community: Angry Nerds</title>
    <description>The latest articles on DEV Community by Angry Nerds (@angrynerds_soft).</description>
    <link>https://dev.to/angrynerds_soft</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%2F354737%2F50c58378-efa9-4aac-bd12-8b3c12b62866.jpg</url>
      <title>DEV Community: Angry Nerds</title>
      <link>https://dev.to/angrynerds_soft</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/angrynerds_soft"/>
    <language>en</language>
    <item>
      <title>Chain of Responsibility design pattern — with examples</title>
      <dc:creator>Angry Nerds</dc:creator>
      <pubDate>Mon, 31 Aug 2020 09:22:29 +0000</pubDate>
      <link>https://dev.to/angry_nerds/chain-of-responsibility-design-pattern-with-examples-2408</link>
      <guid>https://dev.to/angry_nerds/chain-of-responsibility-design-pattern-with-examples-2408</guid>
      <description>&lt;p&gt;Design patterns are not difficult to learn, but mastering them takes time. Still, it’s absolutely worth it! Knowledge on design patterns is necessary when you want to grow as a professional developer and build better software.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KWmBhR_c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AkCWv2eAivV-ndavn3nhc3w.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KWmBhR_c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AkCWv2eAivV-ndavn3nhc3w.jpeg" alt="" width="800" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Design patterns can be divided into three groups: &lt;strong&gt;creational, structural, and behavioral.&lt;/strong&gt; Chain of Responsibility belongs to the behavioral one — which is a group of design patterns that help with better interaction between objects in your code.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TIP:&lt;/strong&gt; There is a classic book discussing this topic and describing 23 design patterns — “Design Patterns: Elements of Reusable Object-Oriented Software”. You should definitely read it if you are not familiar with the matter.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OBbvGDA9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/568/0%2AATCmdG7psYeOGRbx.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OBbvGDA9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/568/0%2AATCmdG7psYeOGRbx.jpg" alt="" width="568" height="335"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Let’s learn more about the Chain of Responsibility with some practical examples
&lt;/h3&gt;

&lt;p&gt;The Chain of Responsibility pattern is used to replace statements like &lt;em&gt;if … else if … else&lt;/em&gt; with a more object-oriented form. Let’s consider calculating a tax amount that is different for each country. The first version of the method handling this calculation could look like this:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;It does not look that complicated, but the code can easily become longer and more laborious with time. In the next version, the tax may be calculated differently for various types of products, we may also have more countries that we want to calculate tax for. Moreover, at some point in the future, the law may be changed and that will result in different formulas based on date. This is a perfect example to use the Chain of Responsibility pattern. Take a look at the tax calculation problem implemented with this pattern:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;In this version, we don’t have five &lt;em&gt;if&lt;/em&gt; statements in one method and each type of tax is calculated by its own class. That way our code follows the Single Responsibility Principle, which is &lt;strong&gt;one of the most important rules in clean coding&lt;/strong&gt;. To use these new classes, we have to create an instance of each class and set value for Next property. See an example here:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;If you had trouble with understanding how it works, I recommend you set a breakpoint and use a debugger to check which instructions are executed. ​&lt;/p&gt;

&lt;p&gt;Here is another example — an algorithm that recommends you the next video to watch based on your age. This is a really simple example because it always returns the same video, but it fits nicely into the Chain of Responsibility pattern.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;And the third example — it’s the code for an ATM that checks if it can dispense cash using a finite number of notes inside the machine. In this case, we will have just one implementation of an abstract class, but we will define a chain consisting of three links using that one class.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Here is how we can use it:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;By now, I think you have already grasped the concept of the Chain of Responsibility pattern. Here is a class diagram and a sequence diagram that presents it:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---qsui2XM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/700/0%2AQozH-jjN9lhSxlTA.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---qsui2XM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/700/0%2AQozH-jjN9lhSxlTA.jpg" alt="" width="700" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Chain of Responsibility vs other patterns
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Chain of Responsibility vs Decorator
&lt;/h4&gt;

&lt;p&gt;The Chain of Responsibility design pattern may appear similar to the Decorator design pattern but the key difference is that the former can be stopped at any part of the processing, and the latter executes all steps (assuming that passed data was valid and it didn’t throw an exception). Decorator adds something with each step. ​&lt;/p&gt;

&lt;h4&gt;
  
  
  Chain of Responsibility vs Strategy
&lt;/h4&gt;

&lt;p&gt;With the Chain of Responsibility pattern, each object is responsible for executing an action on the next object, whereas, with the Strategy pattern, the client of that code has to decide which implementation should be used. ​&lt;/p&gt;

&lt;h3&gt;
  
  
  What next?
&lt;/h3&gt;

&lt;p&gt;I strongly recommend you to read the book mentioned in the intro: &lt;em&gt;Design Patterns: Elements of Reusable Object-Oriented Software&lt;/em&gt;. You can also watch a &lt;a href="https://www.pluralsight.com/paths/design-patterns-in-c"&gt;series of courses on Pluralsight&lt;/a&gt; in the design patterns path. There is also a fun experiment that you can check out on GitHub: &lt;a href="https://github.com/EnterpriseQualityCoding/FizzBuzzEnterpriseEdition"&gt;FizzBuzz Enterprise Edition&lt;/a&gt; is a no-nonsense implementation of FizzBuzz made by serious businessmen for serious business purposes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Feel free to share your thoughts or questions in the comments!
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Article by Marcin Zarębski. Originally published at&lt;/em&gt; &lt;a href="https://angrynerds.co/blog/chain-of-responsibility-design-pattern-with-examples/"&gt;&lt;em&gt;https://angrynerds.co&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>chainofresponsibility</category>
      <category>softwaredesignpattern</category>
      <category>designpatterns</category>
    </item>
    <item>
      <title>Avoiding Anemic Domain Model</title>
      <dc:creator>Angry Nerds</dc:creator>
      <pubDate>Thu, 18 Jun 2020 16:01:16 +0000</pubDate>
      <link>https://dev.to/angry_nerds/avoiding-anemic-domain-model-1nh2</link>
      <guid>https://dev.to/angry_nerds/avoiding-anemic-domain-model-1nh2</guid>
      <description>&lt;p&gt;In this post, we are going to discuss the concept of Anemic Domain Model and its influence on designing software systems. It probably goes without saying but everything that is discussed here is in the context of object-oriented programming. Let’s start with defining the notion of Anemic Domain Model.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Anemic Domain Model&lt;/strong&gt; is a software pattern where classes representing domain objects contain only data and little or no logic in methods. Does it sound familiar? Maybe it is a consequence of using one of the most popular ways of organizing application logic into layers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ooJYKJJr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/241/0%2AjJPA7HqLwo4kwbOT.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ooJYKJJr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/241/0%2AjJPA7HqLwo4kwbOT.png" alt="" width="241" height="471"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You see the data layer and it may be quite natural to think of this as a table in a relational database. It is true that the objects from the data layer will be often used to preserve some data in a relational database but additional work is required to send data from those objects. The bottom line is that objects are not tables.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--imMTJr9k--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/680/0%2AdDTS5eblesZk7Qju.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--imMTJr9k--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/680/0%2AdDTS5eblesZk7Qju.png" alt="" width="680" height="463"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Using Anemic Domain Models is a direct violation of one of the core concepts in object-oriented programming. Having Anemic Domain Models leads to code duplication and a lack of encapsulation. Check out &lt;a href="https://martinfowler.com/bliki/AnemicDomainModel.html"&gt;this excellent blog post&lt;/a&gt; by Martin Fowler. Let’s see some examples.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;All examples in this post are in C#.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class Company 
{ 
    public int Id { get; set; } 
    public DateTime CreatedAt { get; set; } 
    public string Name { get; set; } 
    public string Description { get; set; } 
    public decimal ShareCapital { get; set; } 
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Company class is used by a service layer to create/update new companies, and that service is injected in some API controller. CompanyService class contains the necessary logic - here is a draft of that service. Let's omit the controller class as it is straightforward.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class CompanyService 
{ 
    public void Create(CreateCompanyModel model) 
    { 
        if (!string.IsNullOrWhiteSpace(model.Name)) 
        { 
            throw new Exception("name is required"); 
        } 

        Company company = new Company
        { 
            Id = ... //generate Id 
            CreatedAt = DateTime.UtcNow, 
            Name = model.Name 
        }; 

        // save company in database 
    } 

    public void Update(UpdateCompanyModel model) 
    { 
        // validate model if necessary 

        Company company = ... // get company from database      
        company.Description = model.Description; 
        company.ShareCapital = model.ShareCapital; 

        // update company in database 
    } 
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Potentially, there could be a couple of scenarios where new companies will be created or updated. Maybe we want to create a Business Corporation by following a different path than the path for General Partnership or a Limited Liability Company. This is something that will be defined by business needs.&lt;/p&gt;

&lt;p&gt;Right now, there is nothing in the Company class that helps you understand what are the required properties and what are the optional properties. There are no validation rules included. Probably the Name and CreatedAt should be required - and it may be obvious to someone but when you have a model with 20 properties it may be harder to choose a subset of required properties.&lt;/p&gt;

&lt;p&gt;Moreover, sometimes properties’ values could be automatically deduced when a new instance is created, e.g. CreatedAt seems like something that could be set behind the scenes. If only we defined a constructor, we would make creating a company easier. We could replace the above code with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class Company 
{ 
    public int Id { get; set; }
    public DateTime CreatedAt { get; set; } 
    public string Name { get; set; } 
    public string Description { get; set; } 
    public decimal ShareCapital { get; set; } 

    public Company(string name) 
    { 
        if (!string.IsNullOrWhiteSpace(name)) 
        { 
            throw new Exception("name is required"); 
        } 

        Id = ... //generate Id 
        Name = name; 
        CreatedAt = DateTime.UtcNow; 
    } 
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now our client can’t create a new company using default constructor without Name or CreatedAt values. This is good because it is a business rule that we want to enforce in our domain. However, he can still update Name or CreatedAt date. Does it make sense? As always, it depends. Let's assume that business rule is that we should change neither CreatedAt nor Name values. To do that, we will replace public setters with private setters in Company class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class Company 
{ 
    public int Id { get; private set; } 
    public DateTime CreatedAt { get; private set; } 
    public string Name { get; private set; } 
    public string Description { get; private set; } 
    public decimal ShareCapital { get; private set; } 

    public Company(string name) 
    { 
        if (!string.IsNullOrWhiteSpace(name)) 
        { 
            throw new Exception("name is required"); 
        } 

        Id = ... //generate Id 
        Name = name; 
        CreatedAt = DateTime.UtcNow; 
    } 
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A new problem arose that has to be addressed. In this version, we cannot set value for optional properties Description and ShareCapital. To fix that, we will add new methods: UpdateDescription, UpdateShareCapital. The idea is that for specific scenarios we want to have separate methods that will act accordingly. In more complex scenarios such a method would do more than setting value for one property, e.g. set more values, like the last update date.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class Company 
{ 
    public int Id { get; private set; } 
    public DateTime CreatedAt { get; private set; } 
    public string Name { get; private set; } 
    public string Description { get; private set; } 
    public decimal ShareCapital { get; private set; } 

    public Company(string name) 
    { 
        if (!string.IsNullOrWhiteSpace(name)) 
        { 
            throw new Exception("name is required"); 
        } 

        Id = ... //generate Id 
        Name = name; 
        CreatedAt = DateTime.UtcNow; 
    } 

    public void UpdateDescription(string description) 
    { 
        Description = description; 
    } 

    public void UpdateShareCapital(decimal shareCapital) 
    { 
        ShareCapital = shareCapital; 
    } 
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another advantage of this approach is discoverability — i.e. when you look at the object, you discover what you can do with that object. With an Anemic Domain Model, this is harder and potentially more confusing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Value objects
&lt;/h3&gt;

&lt;p&gt;We will define the concept of value objects that are useful building blocks in creating rich domain models. Eric Evans defines value objects this way:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;An object that represents a descriptive aspect of the domain with no conceptual identity is called a VALUE OBJECT. VALUE OBJECTS are instantiated to represent elements of the design that we care about only for what they are, not who or which they are.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;[Excerpt from “Domain-Driven Design: Tackling Complexity in the Heart of Software”, p. 59]&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Examples of value objects are numbers, strings, money, addresses, colors, etc. When you think about it, there is quite a natural distinction between entities and value objects. For example, if you have a product that costs $100, it doesn’t matter which $100 it is. When you design a value object, you have to make them immutable. Fulfilling the immutability requirement can be a little tedious. We will use value object implementation proposed by msdn (check &lt;a href="https://docs.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/implement-value-objects"&gt;here&lt;/a&gt;).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public abstract class ValueObject
{ 
    protected static bool EqualOperator(ValueObject left, ValueObject right)
    { 
        if (ReferenceEquals(left, null) ^ ReferenceEquals(right, null)) 
        { 
            return false; 
        } 
        return ReferenceEquals(left, null) || left.Equals(right); 
    } 

    protected static bool NotEqualOperator(ValueObject left, ValueObject right) 
    { 
        return !(EqualOperator(left, right)); 
    } 

    protected abstract IEnumerable&amp;lt;object&amp;gt; GetAtomicValues(); 

    public override bool Equals(object obj) 
    { 
        if (obj == null || obj.GetType() != GetType()) 
        { 
            return false; 
        }

        ValueObject other = (ValueObject)obj; 
        IEnumerator&amp;lt;object&amp;gt; thisValues = GetAtomicValues().GetEnumerator();
        IEnumerator&amp;lt;object&amp;gt; otherValues = other.GetAtomicValues().GetEnumerator(); 
        while (thisValues.MoveNext() &amp;amp;&amp;amp; otherValues.MoveNext()) 
        { 
            if (ReferenceEquals(thisValues.Current, null) ^    
                ReferenceEquals(otherValues.Current, null)) 
            { 
                return false; 
            } 

            if (thisValues.Current != null &amp;amp;&amp;amp;             
                !thisValues.Current.Equals(otherValues.Current)) 
            { 
                return false; 
            } 
        } 
        return !thisValues.MoveNext() &amp;amp;&amp;amp; !otherValues.MoveNext(); 
    } 

    public override int GetHashCode() 
    { 
        return GetAtomicValues() 
         .Select(x =&amp;gt; x != null ? x.GetHashCode() : 0) 
         .Aggregate((x, y) =&amp;gt; x ^ y); 
    } 
    // Other utility methods 
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can inherit from ValueObject class to define Money value object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class Money : ValueObject 
{ 
    public string Currency { get; private set; } 
    public decimal Value { get; private set; } 

    private Money() { } 

    public Money(string currency, string value) 
    { 
        Currency = currency; 
        Value = value; 
    } 

    protected override IEnumerable&amp;lt;object&amp;gt; GetAtomicValues() 
    { 
        yield return Currency; 
        yield return Value; 
    } 
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A word of caution must be mentioned here. Initially, you may be tempted to use struct as a value object. Even though it may seem like a good idea, it has major disadvantages. Read &lt;a href="https://enterprisecraftsmanship.com/posts/net-value-type-ddd-value-object/"&gt;this blog post&lt;/a&gt; to learn why. We can use Money class in ShareCapital property of Company class. With that change, we completed transforming an anemic model into a rich model. This is a new version of Company class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class Company 
{ 
    public int Id { get; private set; } 
    public DateTime CreatedAt { get; private set; } 
    public string Name { get; private set; } 
    public string Description { get; private set; } 
    public Money ShareCapital { get; private set; } 

    public Company(string name) 
    { 
        if (!string.IsNullOrWhiteSpace(name)) 
        { 
            throw new Exception("name is required"); 
        } 

        Id = ... //generate Id 
        Name = name; 
        CreatedAt = DateTime.UtcNow; 
    } 

    public void UpdateDescription(string description) 
    { 
        Description = description; 
    } 

    public void UpdateShareCapital(Money shareCapital) 
    { 
        ShareCapital = shareCapital; 
    } 
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We could benefit from using value objects instead of primitive types. The code will be well-organized and understandable, and it will help us avoid code duplication. There is even a term for the situation when your domain code relies heavily on primitive types — we call it a primitive obsession.&lt;/p&gt;

&lt;h3&gt;
  
  
  Refactor CompanyService
&lt;/h3&gt;

&lt;p&gt;We can simplify CompanyService by using a new version of Company class and by removing company logic that is encapsulated inside Company class. Here is the result of that change:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class CompanyService
{ 
    public void Create(CreateCompanyModel model) 
    { 
        Company company = new Company(model.Name); 

        // save company in database 
    } 

    public void UpdateDescription(string description, int companyId)
    { 
        Company company = ...// get company from database 
        company.UpdateDescription(description); 

        // update company in database 
    } 

    public void UpdateShareCapital(Money money, int companyId) 
    { 
        Company company = ...// get company from database 
        company.UpdateShareCapital(money); 

        // update company in database 
    } 
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code is much cleaner than the original version, and more object-oriented. It is also more expressive.&lt;/p&gt;

&lt;h3&gt;
  
  
  Potential problems
&lt;/h3&gt;

&lt;p&gt;▶ When you develop a small application, transforming it into rich models may not be worth it.&lt;/p&gt;

&lt;p&gt;▶ Additional work has to be done to make it work with popular ORM frameworks, e.g. NHibernate or Entity Framework. It is possible but it is not out of the box support.&lt;/p&gt;

&lt;p&gt;▶ The setup of your tests may become more complex. It can also be a good thing because your tests are closer to real-world scenarios. When you create your domain models in test, then you are forced to comply with all business rules that are implemented in your application.&lt;/p&gt;

&lt;p&gt;In general, I believe it is worth going the extra mile if you know that a project will be developed in a longer perspective.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where to go next?
&lt;/h3&gt;

&lt;p&gt;I highly recommend you a Pluralsight course &lt;a href="https://www.pluralsight.com/courses/refactoring-anemic-domain-model"&gt;&lt;em&gt;Refactoring from Anemic Domain Model Towards a Rich One&lt;/em&gt;&lt;/a&gt; by Vladimir Khorikov. You should also read &lt;a href="http://www.kamilgrzybek.com/"&gt;Kamil Grzybek’s blog&lt;/a&gt;, especially posts related to Domain-Driven Design. If you want to learn more about Domain-Driven Design, you can start by reading the book &lt;em&gt;Implementing Domain-driven Design&lt;/em&gt; by Vaughn Vernon.&lt;/p&gt;

&lt;h4&gt;
  
  
  If you have any questions, feel free to leave us a comment!
&lt;/h4&gt;

&lt;p&gt;&lt;em&gt;Article by Marcin Zarębski. Originally published at&lt;/em&gt; &lt;a href="https://angrynerds.co/blog/avoiding-anemic-domain-model/"&gt;&lt;em&gt;https://angrynerds.co&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;




</description>
      <category>domaindrivendesign</category>
      <category>softwaredesign</category>
      <category>softwaredevelopment</category>
      <category>patterns</category>
    </item>
    <item>
      <title>Master your git log with Conventional Commits in 6 steps</title>
      <dc:creator>Angry Nerds</dc:creator>
      <pubDate>Thu, 30 Apr 2020 14:49:54 +0000</pubDate>
      <link>https://dev.to/angry_nerds/master-your-git-log-with-conventional-commits-in-6-steps-32kp</link>
      <guid>https://dev.to/angry_nerds/master-your-git-log-with-conventional-commits-in-6-steps-32kp</guid>
      <description>&lt;p&gt;Have you ever read a guide on how to write commit messages, tried to stick to it and… failed? We’ve all been there. Using random phrases, like “fixes”, “final changes”, “added [something]”, or even forgetting what you really wanted to include in the message leads straight to a commit history from your worst nightmares. Such messages tell us absolutely nothing about the project, and soon turn following changes into hell. Sad reality of being a software developer?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gKIfGUtk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AYZXY_S2G9Vub-0Tj20j5ww.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gKIfGUtk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AYZXY_S2G9Vub-0Tj20j5ww.jpeg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Not anymore! We hope that after reading this article you will no longer have problems with self-discipline, and you will learn how to better document your work. We will also show you how to automate it all, avoid inappropriate commit message format and properly version the modules.&lt;/p&gt;

&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;Semantic Versioning, Conventional Commits and related tools are powerful — and very easy to use! They’ll not only take your skills to the next level, but also speed up the development process. Their advantages are significant:&lt;/p&gt;

&lt;p&gt;→ generating changelogs and determining the next module version can be automated (based on commit messages),&lt;br&gt;&lt;br&gt;
 → the whole process of building and publishing the module can be automated,&lt;br&gt;&lt;br&gt;
 → contributing to your project is easier thanks to a more structured commit history.&lt;/p&gt;

&lt;p&gt;Before we start with Conventional Commits, we need to know what the Semantic Versioning is.&lt;/p&gt;
&lt;h3&gt;
  
  
  1. Semantic Versioning
&lt;/h3&gt;

&lt;p&gt;You probably already use something similar to Semantic Versioning in your projects, but that’s not enough, especially when the project is a complex one. At some point you might get stuck in a dependency hell — and you really wouldn’t like that:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;“In the world of software management there exists a dreaded place called&lt;/em&gt; dependency hell_. The bigger your system grows and the more packages you integrate into your software, the more likely you are to find yourself, one day, in this pit of despair. In systems with many dependencies, releasing new package versions can quickly become a nightmare. If the dependency specifications are too tight, you are in danger of version lock (the inability to upgrade a package without having to release new versions of every dependent package). If dependencies are specified too loosely, you will inevitably be bitten by version promiscuity (assuming compatibility with more future versions than is reasonable)._ &lt;strong&gt;&lt;em&gt;Dependency hell is where you are when version lock and/or version promiscuity prevent you from easily and safely moving your project forward.&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;”&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Source:&lt;/em&gt; &lt;a href="https://semver.org/"&gt;&lt;em&gt;semver.org&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, what is Semantic Versioning?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Y4vHBO3r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/378/0%2AS6Di1DBVMkjEUrB4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Y4vHBO3r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/378/0%2AS6Di1DBVMkjEUrB4.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It’s the way we version the project, and the main guidelines are the following:  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Increment major version when you make incompatible API changes
&lt;/li&gt;
&lt;li&gt;Increment minor version when you add functionality in a backwards compatible manner
&lt;/li&gt;
&lt;li&gt;Increment patch version when you make backwards compatible bug fixes
&lt;/li&gt;
&lt;li&gt;Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And that’s it! Isn’t it simple? You can learn more about Semantic Versioning at &lt;a href="https://semver.org/"&gt;semver.org&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  2. Conventional Commits
&lt;/h3&gt;

&lt;p&gt;The big questions is: which version should we increment? Conventional Commits come to the rescue! This lightweight specification provides an easy set of rules for creating an explicit commit history. Features, fixes and breaking changes made in commit messages allow to determine which version should be released next.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1T0qw3Bc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/557/0%2AfuLQ7A8cpZnglVr0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1T0qw3Bc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/557/0%2AfuLQ7A8cpZnglVr0.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The commit message should be structured as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type(optional scope): description 
[blank line] 
[optional body] 
[blank line] 
[optional footer(s)]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Types of commits:&lt;br&gt;&lt;br&gt;
 * fix: it patches a bug in your codebase (this correlates with PATCH in semantic versioning).&lt;br&gt;&lt;br&gt;
 * feat: it introduces a new feature to the codebase (this correlates with MINOR in semantic versioning).&lt;br&gt;&lt;br&gt;
 * BREAKING CHANGE: a commit that has a footer BREAKING CHANGE:, or appends a ! after the type/scope, introduces a breaking API change (correlating with MAJOR in semantic versioning). A BREAKING CHANGE can be part of commits of any type.&lt;/p&gt;

&lt;p&gt;Types other than fix and feat are of course allowed — the Angular convention recommends: build, chore, ci, docs, style, refactor, perf, test, and others. Learn more here: &lt;a href="https://www.conventionalcommits.org/en/v1.0.0/"&gt;conventionalcommits.org&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  3. Lint commit messages
&lt;/h3&gt;

&lt;p&gt;Once you know what Conventional Commits are, it’s a good idea to be consistent and follow these rules, and preferably use a lint to keep a wrong commit message from passing on to the git history. With this tool, you will find out where you made a mistake when writing your message, and get tips on how to fix it.&lt;/p&gt;

&lt;p&gt;How to use it?&lt;/p&gt;

&lt;p&gt;Install commitlint dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install --save-dev @commitlint/config-conventional @commitlint/cli
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Create commitlint.config.js file with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module.exports = {extends: ['@commitlint/config-conventional']};
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Install husky:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install --save-dev husky
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Extend your package.json:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// package.json 
{ 
  "husky": 
    { 
      "hooks": 
        { 
          "commit-msg": "commitlint -E HUSKY\_GIT\_PARAMS" 
        } 
    } 
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Test your latest commit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx commitlint --from HEAD~1 --to HEAD -verbose
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This configuration is enough for a start, and if you want to learn more about the potential of this tool, have a look here: &lt;a href="https://commitlint.js.org/#/guides-local-setup"&gt;commitlint.js.org&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Conventional Changelog
&lt;/h3&gt;

&lt;p&gt;How to generate a changelog with Conventional Commits? There are several ways to do this, but the best one is conventional-changelog-cli, which is a standardized cli tool. How to use this tool? Just install it globally using npm install -g conventional-changelog-cli If this is your first time using this tool, and you want to generate all previous changelogs, you could do it as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;conventional-changelog -p angular -i CHANGELOG.md -s -r 0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You could use conventional-changelog -p angular -i CHANGELOG.md -s to extend the changelog with the changes since the last version. All available command line parameters can be listed using CLI: conventional-changelog -help. Get packages at &lt;a href="https://github.com/conventional-changelog/conventional-changelog"&gt;conventional-changelog&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. npm version
&lt;/h3&gt;

&lt;p&gt;Okay, we know how to generate a changelog, but how to automate it? To do this, we will use the npm version script and it's pretty easy to do, just take a look at this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm version [| major | minor | patch | premajor | preminor | prepatch | prerelease [--preid=] | from-git]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;For example, you can use such combinations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm version major
npm version minor 
npm version patch 
npm version prerelease --preid=alpha 
npm version prerelease --preid=beta 
npm version prerelease --preid=rc
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Once you know what the npm version command looks like, you can upgrade it with an additional changelog feature. Just type into package.json scripts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"version": "conventional-changelog -p angular -i CHANGELOG.md -s &amp;amp;&amp;amp; git add CHANGELOG.md"
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This will extend CHANGELOG.md file with a log of recent changes in the code, based on the commit messages. You could also use preversion and postversion scripts to run tests before the version script, and push changes or publish package after that. Learn more here: &lt;a href="https://docs.npmjs.com/cli/version"&gt;docs.npmjs.com/cli/version&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. .npmrc
&lt;/h3&gt;

&lt;p&gt;Can the process of versioning be even more automated? Sure! By adding a .npmrc file you could also automate your commit message and set your tag prefix. To do this, simply create.npmrc file or run the npm config command with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tag-version-prefix="" 
message="chore(release): %s :tada:"
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This way, every time a new version is called up, a new commit will be created with a Conventional Commit message. Learn more about the configuration here: &lt;a href="https://docs.npmjs.com/configuring-npm/npmrc.html"&gt;docs.npmjs.com/configuring-npm/npmrc&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;As you can see, a few easy steps can take your project management to a higher level, and help you stop treating commit messages like a burden.&lt;/p&gt;

&lt;p&gt;This article is also a good introduction to process automation in software development. What we have shown is only one of the possibilities! You have many conventions to choose from, you can expand your scripts with additional features and adapt them to each of your projects.&lt;/p&gt;

&lt;h3&gt;
  
  
  Don’t be afraid to commit — and enjoy the coding!
&lt;/h3&gt;

</description>
      <category>versioncontrol</category>
      <category>conventionalcommits</category>
      <category>git</category>
    </item>
    <item>
      <title>How to optimize an Angular app. 13 tips for front-end developers</title>
      <dc:creator>Angry Nerds</dc:creator>
      <pubDate>Wed, 18 Mar 2020 13:26:20 +0000</pubDate>
      <link>https://dev.to/angry_nerds/how-to-optimize-an-angular-app-13-tips-for-front-end-developers-4jck</link>
      <guid>https://dev.to/angry_nerds/how-to-optimize-an-angular-app-13-tips-for-front-end-developers-4jck</guid>
      <description>&lt;p&gt;How to optimize an Angular app? First, we need to consider how we understand optimization as such. Optimization helps achieve better app performance and easier code maintenance. Optimization is not a checklist or a to-do-list and there is no universal way to optimize your app.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_wwhFNQP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2ADywCSyPtXiSefNB8wzkxLA.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_wwhFNQP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2ADywCSyPtXiSefNB8wzkxLA.jpeg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Optimization is a process, and it should start at the same time as the &lt;a href="https://angrynerds.pl/services/web-development/"&gt;app development&lt;/a&gt;. It’s really hard to optimize the application that already exists (though it’s still possible of course), so we should take care of it during the whole project.&lt;/p&gt;

&lt;p&gt;Here’s a list of the best tips to help keep your code in line with good practices and make your Angular application faster. Enjoy and optimize!&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Code minification
&lt;/h3&gt;

&lt;p&gt;Trivial, but really important — each part of the application should be minified before deploying to the production stage. If you have ever used Webpack, you probably know plugins such as UglifyJS, MinifyCSS, etc. They remove every whitespace and every function that is never executed. Moreover, they change functions’ and variables’ names to shorter ones that make the code almost unreadable, but the size of the compiled bundle is smaller. Fortunately, with Angular, we don’t have to remember to add Webpack scripts to minify the code. All we have to do is make a bundle using ng build --prod command. It's just good to know when and how it happens.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. OnPush Change Detection
&lt;/h3&gt;

&lt;p&gt;Each Angular component has its own Change Detector that is responsible for detecting when the component data has been changed, and automatically re-render the view to reflect the changes. Change Detector is called whenever DOM emits an event (button click, form submit, mouseover etc.), an HTTP request is executed, or there’s an asynchronous interaction such as setTimeout or setInterval. On every single event, the Change Detector will be triggered in the whole application tree (from the top to the bottom, starting with the root component).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HoN1Pyzc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/939/0%2ArK2IK3wyTklv_f8h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HoN1Pyzc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/939/0%2ArK2IK3wyTklv_f8h.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The numbers show the order of checking the changes by the Change Detectors after the event in the Component in the left bottom corner. To change Detection Strategy for the component, the changeDetection in Component declaration should be set to ChangeDetectionStrategy.OnPush as below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Component({ 
   ... 
   changeDetection: ChangeDetectionStrategy.OnPush 
})
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;After that, the Change Detectors will work by comparing references to the inputs of the component. Inputs in this component are immutable and if values in these inputs have not changed, change detection skips the whole subtree of Change Detectors, as depicted below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pqaF-pd7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/939/0%2AhJDZh1MyGmByJWN1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pqaF-pd7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/939/0%2AhJDZh1MyGmByJWN1.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Change detector for a component with OnPush Strategy will be triggered only when a value in @Input() has been changed, an event has been emitted by a template, an event has been triggered by Observable in this component or this.changeDetector.markForCheck() has been called.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Pure pipes instead of functions/getters in templates
&lt;/h3&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class foo { 
   private \_bar: boolean = false; 
   get bar(): boolean { 
      return this.\_bar; 
   } 
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;get used in the view is nothing more than a function call. A better idea is to use pure pipes which will always return the same output, no matter how many times they will receive the same input. If the Change Detector reaches this view and pure in the pipe is set to true (default), the Change Detector will not check if that value has been changed because it knows that it will return exactly the same value.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Async pipe
&lt;/h3&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div&amp;gt;Time: {{ time | async }}&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The async pipe allows subscribing to Observable directly from the template. With async pipe, there’s no need to bother about unsubscribing. What’s more, Change Detector will check if the value was changed only when Observable had changed itself.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Unsubscribing
&lt;/h3&gt;

&lt;p&gt;When using RxJS, it’s really important not to forget about unsubscribing, otherwise there’s a risk to get memory leaks in our application. There are a few methods to unsubscribe a Subscription, but choosing the best one is probably a subject for another blog post — for now, just remember to do it. Here are the methods →&lt;/p&gt;

&lt;p&gt;1st method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let sub1: Subscription; 
let sub2: Subscription; 

ngOnInit() { 
   this.sub1 = this.service.Subject1.subscribe(() =&amp;gt; {}); 
   this.sub2 = this.service.Subject2.subscribe(() =&amp;gt; {}); 
} 

ngOnDestroy() { 
   if (this.sub1) { 
      this.sub1.unsubscribe(); 
   } 
   if (this.sub2) { 
      this.sub2.unsubscribe(); 
   } 
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;2n method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let subs: Subscription[] = []; 

ngOnInit() { 
   this.subs.push(this.service.Subject1.subscribe(() =&amp;gt; {})); 
   this.subs.push(this.service.Subject2.subscribe(() =&amp;gt; {})); 
} 

ngOnDestroy() { 
   subs.forEach(sub =&amp;gt; sub.unsubscribe()); 
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;3rd method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private subscriptions = new Subscription(); 

ngOnInit() { 
   this.subscriptions.add(this.service.Subject1.subscribe(() =&amp;gt; {})); 
   this.subscriptions.add(this.service.Subject2.subscribe(() =&amp;gt; {})); 
} 

ngOnDestroy() { 
   this.subscriptions.unsubscribe(); 
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;4th method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ngUnsubscribe = new Subject(); 

ngOnInit() { 
   this.service.Subject1.pipe(takeUntil(this.ngUnsubscribe)) 
      .subscribe(() =&amp;gt; {});     
   this.service.Subject2.pipe(takeUntil(this.ngUnsubscribe)) 
      .subscribe(() =&amp;gt; {}); 
} 

ngOnDestroy() { 
   this.ngUnsubscribe.next(); 
   this.ngUnsubscribe.complete(); 
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Track by function
&lt;/h3&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\*ngFor="let item of items; trackBy: trackByFn"
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;trackBy is a parameter that accepts a function that should return a unique value of each item of the list. Without using trackBy function, *ngFor will re-render each and every element of the list every time that list changes (each element will be removed from DOM and rendered once again). With trackBy function, only the values that have been changed will be re-rendered or deleted.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Webpack Bundle Analyzer
&lt;/h3&gt;

&lt;p&gt;If you find out that your bundle’s size is too big, you can check what exactly is in the bundle and decide whether you need all the external libraries or not. You can use e.g. Webpack Bundle Analyzer. All you need to do is just provide a simple configuration based on your application and your needs, and analyze the output graph.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_w1ZLcT---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/939/0%2Ar0E4kd6lzFclkBix.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_w1ZLcT---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/939/0%2Ar0E4kd6lzFclkBix.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  6. You probably don’t need external libraries
&lt;/h3&gt;

&lt;p&gt;After generating a graph via Webpack Bundle Analyzer you probably know that you shouldn’t add the whole library to your project if you use only a small feature from it. Try to code the same function that you import from the library on your own. For example, a concat method from Lodash&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { concat } from 'lodash' 
concat([1], 2, [3], [[4]])
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;is nothing more than&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[1].concat(2, [3], [[4]])
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The more code you write on your own, the bigger control and understanding of how it works you have. Moreover, it’s easier to debug and maintain the code without unnecessary external libraries. However, if you need to import something, choose modular library and&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { chunk } from "lodash"
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;instead of&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import \* from "lodash"
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  7. Styles per component
&lt;/h3&gt;

&lt;p&gt;No matter if you use SASS, LESS or pure CSS (is there anybody who still uses pure CSS? 😉) try to write as many styles per component as you can, instead of global ones. In the files with global styles declare variables with colors, fonts, reusable components, like buttons, dropdowns, form inputs, but keep everything else divided into components. Properties will be loaded only if the component is used in the rendered page, so it means better performance for the application. For you, as a front-end developer, it means that the SCSS is scoped and simplified, so you will be probably more productive during development.&lt;/p&gt;

&lt;h3&gt;
  
  
  8. Tree shaking
&lt;/h3&gt;

&lt;p&gt;You can imagine that the application is a tree with green and brown leaves that refer respectively to used and unused parts of the code. When you try to shake that tree, the brown leaves (dead code) will fall down. When using ng build --prod to build, the Angular CLI will compile and bundle all components into the application. When using ng build --prod --build-optimizer to build, all of the unused components will be omitted.--build-optimizer activates tree shaking (a term commonly used for dead-code elimination in JavaScript context) on Webpack. Unfortunately, this can cause some bugs, so be really careful while doing that and rather than excluding &lt;strong&gt;dead code,&lt;/strong&gt; try including &lt;strong&gt;living code&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  9. One-time string initialization
&lt;/h3&gt;

&lt;p&gt;While binding properties between components check if:&lt;br&gt;&lt;br&gt;
 * the target property accepts a string value,&lt;br&gt;&lt;br&gt;
 * the string is a fixed value that you can put directly into the template,&lt;br&gt;&lt;br&gt;
 * this initial value never changes.&lt;br&gt;&lt;br&gt;
&lt;em&gt;[Source:&lt;/em&gt; &lt;a href="https://angular.io/guide/template-syntax#one-time-string-initialization"&gt;&lt;em&gt;Angular.io&lt;/em&gt;&lt;/a&gt;&lt;em&gt;]&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If if the property covers all of these criteria omit the brackets and use&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[label]="Save"
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;instead of&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[label]="'Save'"
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This way the Change Detector will not check it while running in the component.&lt;/p&gt;

&lt;h3&gt;
  
  
  10. Dependencies between components
&lt;/h3&gt;

&lt;p&gt;The next thing to consider are dependencies between components in the application. Are all of them really necessary? Do you want and need them all? Try to check it by generating and analyzing dependencies graph (for example NGD: Angular Dependencies Graph).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wO5hj5bA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/939/0%2AGDpOwYfQ7aIogdrP.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wO5hj5bA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/939/0%2AGDpOwYfQ7aIogdrP.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It can be also helpful when you start working on an already existing project and want to have an overview of the architecture of the application.&lt;/p&gt;

&lt;h3&gt;
  
  
  11. CSS vs. JS animations
&lt;/h3&gt;

&lt;p&gt;Remember to use the appropriate animations, depending on what you want to achieve. CSS animations are perfect for smaller, self-contained states for UI elements, e.g. a sidebar with menu appearing from the side, a tooltip showing on hover, while JavaScript gives more control over animations, e.g. possibility to stop, slow down, reverse or pause the animation. CSS animations are smaller so use them every time you can, and only when they are not enough for you, choose JS ones. A good practice is to use a CSS animation to make a global loader for the application — then, even if the JavaScript of the application doesn’t load properly, the user can see a nice, animated loader.&lt;/p&gt;

&lt;h3&gt;
  
  
  12. Lazy loading
&lt;/h3&gt;

&lt;p&gt;Lazy loading loads only those modules and components that are necessary. If the user is not an admin, there is no need to load the entire AdminModule, and if the user is not signed into the application and uses it anonymously, there is no need to load the AccountModule, which allows to view and edit the profile.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const routes: Routes = [ 
      { path: 'account', 
      loadChildren: () =&amp;gt; import('./account/account.module') 
      .then(m =&amp;gt; m.AccountModule) }, 
      { path: admin, 
      loadChildren: () =&amp;gt; import('./admin/admin.module') 
      .then(m =&amp;gt; m.AdminModule) } 
];
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;What’s more, you can try lazy load for a bigger amount of images or longer content — load it on scroll.&lt;/p&gt;

&lt;h3&gt;
  
  
  13. Throw it away to the backend
&lt;/h3&gt;

&lt;p&gt;Move as much application logic as possible to the backend. When the logic of the application relies little on the choices of the user, there is no need to perform huge calculations on the frontend side.&lt;/p&gt;

&lt;h3&gt;
  
  
  We hope these tips will help you with your next Angular project. If you have anything to add, feel free to share your thoughts in the comments!
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Originally published at&lt;/em&gt; &lt;a href="https://angrynerds.co/blog/how-to-optimize-angular-app/"&gt;&lt;em&gt;https://angrynerds.co&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;




</description>
      <category>angular</category>
      <category>webdev</category>
    </item>
    <item>
      <title>MotionLayout + Android Studio 4.0 = ❤</title>
      <dc:creator>Angry Nerds</dc:creator>
      <pubDate>Fri, 15 Nov 2019 00:00:00 +0000</pubDate>
      <link>https://dev.to/angry_nerds/motionlayout-android-studio-4-0-1cbm</link>
      <guid>https://dev.to/angry_nerds/motionlayout-android-studio-4-0-1cbm</guid>
      <description>&lt;p&gt;Android Studio 4.0 will include a lot of really great features, like layout Multi Preview, support for Jetpack Compose or Live Layout Debug tool. This seems to be a lot for a single release, but there is also one more thing — MotionEditor. This tool finally makes working with MotionLayout really easy and fun!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gyRL89_t--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AWjh7LoE6VWYiwL68T6A6_w.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gyRL89_t--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AWjh7LoE6VWYiwL68T6A6_w.jpeg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;MotionLayout is out there since the release of constraint-layout:2.0.0-alpha1 (June 2018), and it has already caused quite a stir. When we first saw the example animations that can be done pretty easily using it, we were pretty impressed. However, as it turned out, using MotionLayout was time- and work-consuming, because there was a lot of code to write, and in order to test it we had to run our app on the device each time.&lt;/p&gt;

&lt;p&gt;These times are over!&lt;/p&gt;

&lt;p&gt;As for constraint-layout:2.0.0-beta3 and &lt;strong&gt;&lt;em&gt;Android Studio 4.0 Canary1&lt;/em&gt;&lt;/strong&gt; we can edit MotionLayout in the graphic design tool, and what's even better, we can preview the effects of our work right in the Android Studio, with no need to run the app on the device ❤&lt;/p&gt;

&lt;p&gt;That sounds really awesome. Now, let’s see how it works.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nXYrRbSC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/300/1%2AU4W7FMILmFocouIYvgfo_w.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nXYrRbSC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/300/1%2AU4W7FMILmFocouIYvgfo_w.gif" alt=""&gt;&lt;/a&gt;&lt;em&gt;A simple MotionLayout with changing position, color, rotation, and size of the view.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  MotionLayout
&lt;/h3&gt;

&lt;p&gt;At the beginning, just a few words about the MotionLayout itself.&lt;/p&gt;

&lt;p&gt;MotionLayout class extends ConstraintLayout. That means you can seamlessly convert the latter to the first, and without any changes it should work pretty much the same. That is really nice, because it enables us to experiment with MotionLayout, starting with any existing ConstraintLayout.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"    
    android:layout\_width="match\_parent"  
    android:layout\_height="match\_parent"&amp;gt; 

    &amp;lt;View
        android:id="@+id/sky" android:layout\_width="0dp"     
        android:layout\_height="0dp"  
        android:background="@color/sky\_morning" 
        app:layout\_constraintBottom\_toTopOf="@id/guideline" 
        app:layout\_constraintEnd\_toEndOf="parent" 
        app:layout\_constraintStart\_toStartOf="parent" 
        app:layout\_constraintTop\_toTopOf="parent" /&amp;gt; 

    &amp;lt;View 
        android:id="@+id/ground" 
        android:layout\_width="0dp" 
        android:layout\_height="0dp"      
        android:background="@color/ground"   
        app:layout\_constraintBottom\_toBottomOf="parent"  
        app:layout\_constraintEnd\_toEndOf="parent" 
        app:layout\_constraintStart\_toStartOf="parent" 
        app:layout\_constraintTop\_toBottomOf="@id/guideline" /&amp;gt; 

    &amp;lt;androidx.constraintlayout.widget.Guideline 
        android:id="@+id/guideline"
        android:layout\_width="wrap\_content"   
        android:layout\_height="wrap\_content" 
        android:orientation="horizontal" 
        app:layout\_constraintGuide\_percent="0.5" /&amp;gt; 

    &amp;lt;ImageView 
        android:id="@+id/biker" 
        android:layout\_width="wrap\_content"  
        android:layout\_height="wrap\_content" 
        android:contentDescription="@string/biker"    
        android:src="@drawable/ic\_bike" 
        app:layout\_constraintBottom\_toBottomOf="@id/guideline" 
        app:layout\_constraintTop\_toTopOf="@id/guideline" /&amp;gt; 

&amp;lt;/androidx.constraintlayout.widget.ConstraintLayout&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Above: just a simple constraint layout that will be our starting point.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The real magic of MotionLayout lays in the MotionScene resource file, which contains all the constraints and attributes transitions that result in our layout animation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;
&amp;lt;MotionScene    
    xmlns:android="http://schemas.android.com/apk/res/android"  
    xmlns:motion="http://schemas.android.com/apk/res-auto"&amp;gt; 

    &amp;lt;Transition 
        motion:constraintSetEnd="@+id/end" 
        motion:constraintSetStart="@id/start" 
        motion:duration="1000"&amp;gt; 
       &amp;lt;KeyFrameSet&amp;gt; 
       &amp;lt;/KeyFrameSet&amp;gt; 
    &amp;lt;/Transition&amp;gt; 

    &amp;lt;ConstraintSet android:id="@+id/start"&amp;gt; 
    &amp;lt;/ConstraintSet&amp;gt; 

    &amp;lt;ConstraintSet android:id="@+id/end"&amp;gt; 
    &amp;lt;/ConstraintSet&amp;gt; 
&amp;lt;/MotionScene&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Above: an empty MotionScene file.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Each Transition has to have a start and end ConstraintSet, and a number of KeyFrames that enables us to achieve various interesting effects. You should remember, that constraints set in the MotionScene always take precedence over these declared in the MotionLayout file.&lt;/p&gt;

&lt;p&gt;If you want to know more about the MotionLayout itself, there is a great series of articles on the &lt;a href="https://medium.com/google-developers/introduction-to-motionlayout-part-i-29208674b10d"&gt;Google Developers Medium&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To use all the discussed below features you need to add a dependency to your build.gradle file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dependencies { 
    implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta3'
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  MotionEditor
&lt;/h3&gt;

&lt;p&gt;Ok, so now that we know what MotionLayout is, let’s see what Android Studio 4.0 can do to make our work with it more enjoyable.&lt;/p&gt;

&lt;p&gt;First of all, in the layout design panel there is a tool to automatically convert our selected ConstraintLayout to the MotionLayout.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--byUtAuVn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/656/0%2AtDf3EZMBiAI52Jw5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--byUtAuVn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/656/0%2AtDf3EZMBiAI52Jw5.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What it really does is changing the root layout to MotionLayout, creating a new MotionScene xml file in the resources/xml package and setting the app:layoutDescription attribute of the new layout to the motion scene file. That's it. But is also redirects us to the brand new MotionEditor view.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--erZO6HOY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/937/0%2AC7kSrPqh-CbogluB.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--erZO6HOY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/937/0%2AC7kSrPqh-CbogluB.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There you can see a preview of our MotionLayout on the left, a panel with all the transitions and constraint sets in the middle, and attributes panel on the right.&lt;/p&gt;

&lt;p&gt;One thing to remember is that you can navigate between code, design, and split screen using the three buttons on the top right corner of the view (not on the bottom left as it was before).&lt;/p&gt;

&lt;p&gt;Now, by navigating between the start and end states in the middle panel, we are able to add/change views constraints and attributes. E.g. we want the color of the sky to change from light to dark. All we need to do is to choose start state, click on sky entry and add a new Custom Attribute (there is an autocomplete in the attributes popups ☺). Then repeat it for the end state.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--B02NPNGy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/939/0%2AW2eD6tyBueABVbxK.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--B02NPNGy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/939/0%2AW2eD6tyBueABVbxK.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;MotionLayout will do the rest for us, and we get a nice simple sky animation.&lt;/p&gt;

&lt;p&gt;In a similar way, but by changing the start and end constraints of the biker image, we are able to create a changing position animation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pfLPeBXp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/935/0%2A63AkdauT9Ilq2cuH.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pfLPeBXp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/935/0%2A63AkdauT9Ilq2cuH.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By clicking on the grey arrow between the states, you open the Transition panel where you can play the current motion animation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kfT7TEPJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/938/0%2AsGHDZJIyKGTebU_D.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kfT7TEPJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/938/0%2AsGHDZJIyKGTebU_D.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To make it work on the device we need to start the motion somehow. We can either start/set the progress in code, or add an OnSwipe/OnClick MotionObject. In this example, we choose the second option, and by clicking the third button on top of the motion panel we add a SwipeHandler with an anchor at the biker.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--r0b41AnF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/274/0%2AHkUSjpuaFjymVWZO.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--r0b41AnF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/274/0%2AHkUSjpuaFjymVWZO.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DMNo8aaY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/300/1%2AlHwFJzbJg0Lwy2C0i1ZRtA.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DMNo8aaY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/300/1%2AlHwFJzbJg0Lwy2C0i1ZRtA.gif" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now let’s add some sunshine to our animation ☺&lt;/p&gt;

&lt;p&gt;We add the sun image, and want it to move above the biker, but on the arc, so simply changing the constrains won’t be sufficient. We need to add also a KeyFrame. We can do it by choosing KeyPosition from the Transition panel, and setting the percentY position in a 50th frame (frames go from 0 to 100) to a negative value, and type do pathRelative.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--O3WTCcZ_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/464/0%2Av8jpKAEWQi08ylzs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--O3WTCcZ_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/464/0%2Av8jpKAEWQi08ylzs.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--za53qJ-Q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/414/0%2A62Dfj8aGkcDfKPrl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--za53qJ-Q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/414/0%2A62Dfj8aGkcDfKPrl.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--77inE7iC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/936/0%2A2dib4H-3sYIT8pit.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--77inE7iC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/936/0%2A2dib4H-3sYIT8pit.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now our animation starts to gain some life.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RNW_iSr4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/300/1%2A8m53ygZ_cC779ywzs_-tTQ.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RNW_iSr4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/300/1%2A8m53ygZ_cC779ywzs_-tTQ.gif" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In a similar way, but using KeyAttribute we can modify things like scale, rotation or alpha of our view.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sRhYMfDv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/444/0%2AMeR7TOHom7rAxAvJ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sRhYMfDv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/444/0%2AMeR7TOHom7rAxAvJ.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s get nuts and add all of the above attributes! Making the sun do a 360 degrees rotation during the animation, scaling to 1.5 in the middle, and vanishing after the 60th frame.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AOmZeQ7e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/573/0%2AmOxp0BeoaGnkH1S7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AOmZeQ7e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/573/0%2AmOxp0BeoaGnkH1S7.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When we add a moon image with the same path as the sun image, and with alpha increasing after 60th, we’ll get a really nice transition.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EbIcc7xn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/300/1%2AJ6XSZwNzZdy58oGtTGIlvw.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EbIcc7xn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/300/1%2AJ6XSZwNzZdy58oGtTGIlvw.gif" alt=""&gt;&lt;/a&gt;&lt;em&gt;Here I added also a backgroundColor frame for sky at the 60th frame.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now you can use your imagination and add other views to the animation. Will you be able to recreate the one from below? ☺&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--78DVPpC2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/300/1%2AlFIssNRxu6sCgqzwTm8YKg.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--78DVPpC2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/300/1%2AlFIssNRxu6sCgqzwTm8YKg.gif" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This kind of animation is a great example of how MotionLayout can be mixed with a ViewPager for creating a really nice custom experience.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;_You can find the complete code of the example _&lt;/strong&gt; &lt;a href="https://github.com/aleksandra-majchrzak/motion-layout-examples"&gt;&lt;strong&gt;&lt;em&gt;HERE&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;&lt;em&gt;.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cU1AuBGY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/300/1%2Ahm2Nxpl_5ZBVfCNWoiVp1g.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cU1AuBGY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/300/1%2Ahm2Nxpl_5ZBVfCNWoiVp1g.gif" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It is also worth to mention that if you have a MotionLayout written with an older constraint-layout version and older Android Studio, you can still use it with the Android Studio 4.0, and MotionEditor will work just fine, no changes need to be done ✔&lt;/p&gt;

&lt;h3&gt;
  
  
  Problems
&lt;/h3&gt;

&lt;p&gt;The tools that Android Studio 4.0 gives us to work with the MotionLayout are great, however we must remember that neither of them is stable yet, and definitely not production ready. There still can occur some random crashes and other errors.&lt;/p&gt;

&lt;p&gt;Here are some problems I encountered while playing with the above example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;modifying constraints can sometimes cause big lags&lt;/li&gt;
&lt;li&gt;there must be no errors or warnings (!) in your xml code for MotionEditor to work&lt;/li&gt;
&lt;li&gt;‘showPaths’ option does not work when there are many views in the layout&lt;/li&gt;
&lt;li&gt;MotionEditor does not work for your custom classes extending MotionLayout&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Now it’s time for your own experiments. MotionLayout gives us great abilities to create beautiful and meaningful animations. There are many other features that I haven’t discussed here, like multiple transitions in a single MotionScene, creating custom attributes, using MotionLayout progress, KeyCycles, or motion easing.&lt;/p&gt;

&lt;p&gt;The best place to start your adventure is definitely the &lt;a href="https://developer.android.com/training/constraint-layout/motionlayout/examples"&gt;documentation page&lt;/a&gt;, where you can find many examples.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Article by Aleksandra Krzemień. Originally published at&lt;/em&gt; &lt;a href="https://angrynerds.co/blog/motionlayout-plus-android-studio-40/"&gt;&lt;em&gt;https://angrynerds.co&lt;/em&gt;&lt;/a&gt; &lt;em&gt;on November 15, 2019.&lt;/em&gt;&lt;/p&gt;




</description>
      <category>android</category>
      <category>androidstudio</category>
      <category>animation</category>
      <category>motionlayout</category>
    </item>
    <item>
      <title>Automating repetitive actions with Selenium WebDriver and Node.js</title>
      <dc:creator>Angry Nerds</dc:creator>
      <pubDate>Tue, 15 Oct 2019 00:00:00 +0000</pubDate>
      <link>https://dev.to/angrynerds_soft/automating-repetitive-actions-with-selenium-webdriver-and-node-js-352e</link>
      <guid>https://dev.to/angrynerds_soft/automating-repetitive-actions-with-selenium-webdriver-and-node-js-352e</guid>
      <description>&lt;h3&gt;
  
  
  Automating repetitive actions with Selenium WebDriver and Node.js
&lt;/h3&gt;

&lt;p&gt;Programmers — strange beings who want to automate every activity. Even if you are not a programmer, you probably know the feeling of frustration associated with repetitive tasks — and with the fact you’re responsible for them, not someone else. You can accept it and get into the routine of repeating the same actions over and over again, or analyze the problem and find a solution. And the solution I want to recommend you is a &lt;strong&gt;bot&lt;/strong&gt;. Citing the concise Wikipedia definition:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Bot — is a program that performs certain tasks instead of a human. Sometimes its function is to pretend human behavior.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PJpGR9aN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/0%2AuF-ClmuKb6Ltgfyt.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PJpGR9aN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/0%2AuF-ClmuKb6Ltgfyt.jpg" alt="" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;“…performs certain tasks instead of a human”&lt;/em&gt; — sounds great, doesn’t it? The definition however begins with “a program” — and you might ask yourself where you can get this kind of software. Well, you can simply build it! If you don’t know where to start, think of the steps you would follow to execute a chosen task — after all, a program is nothing more than a set of instructions. In this tutorial, I will show you how to do it using Selenium WebDriver for Node.js and a simple click game — Cookie Clicker.&lt;/p&gt;

&lt;p&gt;In brief: Cookie Clicker is a free web time-eater. The player’s goal is to click at the big cookie on the left side of the screen. With each click, we get points that can be exchanged for ‘boosters’ that will speed up the process of gaining new points. So basically it means lots of repetitive clicking… Sounds like a perfect bot environment, right? The entire game is available &lt;a href="https://orteil.dashnet.org/cookieclicker/"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The tools we need
&lt;/h3&gt;

&lt;p&gt;First of all, we need a powerful tool, which is Node.js and the npm package manager. We’ll download them from &lt;a href="https://nodejs.org/en/"&gt;here&lt;/a&gt;. Of course, we can’t do it without an IDE — the built-in terminal will be a big plus.&lt;/p&gt;

&lt;p&gt;With a good editor, Node and npm, we are ready to initiate our project. How to do it? Very simply — we create a directory for our bot and use the terminal to enter the command npm init. It should look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VLHuoZrn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/0%2ALS_6M4UO8votpsts.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VLHuoZrn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/0%2ALS_6M4UO8votpsts.jpg" alt="" width="800" height="788"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, we must equip our newly initiated project with tools to control the web application. Selenium WebDriver will come to the rescue! It’s commonly used in automated testing of web applications, but today we will use it for other purposes. We will also make use of a driver for the Chrome browser. The correct order should be as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i selenium-webdriver 
npm i chromedriver
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, our package.json file should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{ 
"name": "cookie-bot",
"version": "1.0.0",
"description": "", 

"main": "index.js", 
   "scripts": { 
   "test": "echo \"Error: no test specified\" &amp;amp;&amp;amp; exit 1" 
}, 
"author": "",
"license": "ISC",
"dependencies": {
   "chromedriver": "^76.0.1", 
   "selenium-webdriver": "^4.0.0-alpha.5" 
  } 
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  We code the bot
&lt;/h3&gt;

&lt;p&gt;We’ll start with creating a .js file in which we will keep the instructions for our bot — I named my file cookie-bot.js. Now we need to deal with the dependencies we downloaded earlier — that’s why you will need to import them at the beginning:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const webdriver = require('selenium-webdriver'); 
const chrome = require('selenium-webdriver/chrome'); 
const chromedriver = require('chromedriver');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we will initialize the driver for our browser — in our case, for Chrome:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;chrome.setDefaultService(new chrome.ServiceBuilder(chromedriver.path).build()); 
const driver = new webdriver.Builder().forBrowser('chrome').build();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now it will start to get more interesting… First, I recommend something simple. If you haven’t seen the game yet, then I encourage you to do it now (by clicking &lt;a href="https://orteil.dashnet.org/cookieclicker/"&gt;here&lt;/a&gt;). Our point of interest is the big cookie on the left:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--inFcX3Jt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/784/0%2ADhLX9O8alUM2-yvd.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--inFcX3Jt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/784/0%2ADhLX9O8alUM2-yvd.jpg" alt="" width="784" height="900"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I know, you feel tempted to click it — but we’ll refrain from that. In the end, we’re going to ignore the game’s rules and cheat. Or, in other words, we will have our bot do it for us. How will our virtual cheater know where to go? We’ll have to tell him:&lt;/p&gt;

&lt;p&gt;driver.get('&lt;a href="https://orteil.dashnet.org/cookieclicker/'"&gt;https://orteil.dashnet.org/cookieclicker/'&lt;/a&gt;);&lt;/p&gt;

&lt;p&gt;That’s how we tell our automated browser what address to go to. Combining it together, our script looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const webdriver = require('selenium-webdriver'); 
const chrome = require('selenium-webdriver/chrome'); 
const chromedriver = require('chromedriver'); 

chrome.setDefaultService(new chrome.ServiceBuilder(chromedriver.path).build()); 
const driver = new webdriver.Builder().forBrowser('chrome').build(); 

const init = () =&amp;gt; {     
    driver.get('https://orteil.dashnet.org/cookieclieker/');
}; 

init();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s try to run what we’ve just programmed. We run our script through the terminal with the node command , in my case: node cookie-bot.js (or by defining our startup script in package.json — we run it then with the command npm start — more on defining scripts can be found &lt;a href="https://www.freecodecamp.org/news/introduction-to-npm-scripts-1dbb2ae01633/"&gt;here&lt;/a&gt;). We should see the Chrome browser saying that it is controlled by the automated test software. If you got a similar result and nothing broke along the way — congratulations!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lRCNUFNS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/800/0%2AbdgZdYTgFBA86sov.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lRCNUFNS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/800/0%2AbdgZdYTgFBA86sov.jpg" alt="" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we can release our cheater and try to make it click the cookie. Let’s stop for a second here, because we will need some knowledge on CSS selectors. If you are familiar with them — great, you will certainly not find anything that surprising. If it’s a new thing for you or you want to refresh your knowledge, please look &lt;a href="https://www.testingexcellence.com/css-selectors-selenium-webdriver/"&gt;here&lt;/a&gt; and &lt;a href="https://www.w3schools.com/css/css_selectors.asp"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Moving on to the program: now it’s time to tell our bot where the cookie to click is located. To do it, we must go to our game and examine the clickable object. In Google Chrome it looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Zn5ESq-E--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/0%2AfE9og6o29HsxeoCw.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Zn5ESq-E--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/0%2AfE9og6o29HsxeoCw.jpg" alt="" width="800" height="477"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All simple and clear! Our cookie has a unique ID called ‘bigCookie’ — as if the game developers themselves encouraged cheating in their own game. Let’s “catch” this element with our selector and try to tell the bot to click on it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const cookieEl = driver.findElement({id: 'bigCookie'}); cookieEl.click();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As simple as that! It should work perfectly in most cases. But what if it doesn’t? There’s one thing you need to make sure of. When defining the ‘cookieEl’ element, we have to be absolutely sure that such an element is in the DOM tree (if you don’t know what the DOM is, look &lt;a href="https://css-tricks.com/dom/"&gt;here&lt;/a&gt;). If it’s not there at the moment we define it, our script will return an error. So let’s prepare a simple protection against this case:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;driver.wait(webdriver.until.elementLocated({id: 'bigCookie'})); const cookieEl = driver.findElement({id: 'bigCookie'}); cookieEl.click();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let’s tell our cheater to wait until the item with the ‘bigCookie’ ID is found. This way, we protect ourselves against a situation in which we would want to use an element that doesn’t exist on the site yet.&lt;/p&gt;

&lt;p&gt;Running the script now will turn on the browser and make our bot click the cookie once. Yeah, I know, it doesn’t sound like a big cheat. So let’s spice the things up! We will make our bot click the cookie for example twice every second. Just like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const startInterval = () =&amp;gt; { 
    const cookieEl = driver.findElement({id: 'bigCookie'});          
    setInterval(() =&amp;gt; { 
       cookieEl.click(); 
    }, 500); 
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can find more about setInterval &lt;a href="https://developer.mozilla.org/pl/docs/Web/API/Window/setInterval"&gt;here&lt;/a&gt;. Finally, our script should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const webdriver = require('selenium-webdriver'); 
const chrome = require('selenium-webdriver/chrome'); 
const chromedriver = require('chromedriver'); 

chrome.setDefaultService(new chrome.ServiceBuilder(chromedriver.path).build()); 
const driver = new webdriver.Builder().forBrowser('chrome').build();

const startInterval = () =&amp;gt; {
    const cookieEl = driver.findElement({id: 'bigCookie'});   
    setInterval(() =&amp;gt; { 
       cookieEl.click(); 
    }, 500); 
}; 

const init = () =&amp;gt; {    
    driver.get('https://orteil.dashnet.org/cookieclicker/');    
    driver.wait(webdriver.until.elementLocated({id: 'bigCookie'}));   
    startInterval(); 
}; 

init();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can sit back and watch your bot do the clicking for you — your mouse will definitely appreciate it. Is that all? By no means. We are going for more! Now we will buy some in-game accessories that will speed up the collection of our cookies. Look at the right panel in the game — there is a list of things that we can buy:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---lh-livg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/0%2Ax-8DspQ--gKElot-.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---lh-livg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/0%2Ax-8DspQ--gKElot-.jpg" alt="" width="800" height="477"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Do we want to buy these improvements ourselves? Of course not. It’s a complete waste of time. We will have our bot do it! What connects all these improvements is the class — ‘product’. As you can see, the things we can’t buy have the ‘locked’ and ‘disabled’ classes. However, we are looking for those that we can buy — they have three classes: ‘product’, ‘unlocked’, ‘enabled’. Let’s get them!&lt;/p&gt;

&lt;p&gt;First of all, make sure that the list of elements with the class ‘product’ is in our DOM:&lt;/p&gt;

&lt;p&gt;driver.wait(webdriver.until.elementLocated({className: 'product'}));&lt;/p&gt;

&lt;p&gt;Now we can deal with the list itself. We will have to create a variable to which we will assign the list of items that we can click on:&lt;/p&gt;

&lt;p&gt;const products = await driver.findElements({className: 'product unlocked enabled'});&lt;/p&gt;

&lt;p&gt;Please note the method we use: findElements. It returns Promise as opposed to the findElement method, which returns ready-to-use WebElement. We are not interested in assigning to the ‘products’ Promise variable, but in what this Promise returns. That is why an await appeared in the variable definition. It forces us to be asynchronous in our function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const checkProducts = async () =&amp;gt; {
    const products = await driver.findElements({className: 'product unlocked enabled'}); 
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now just check if the ‘products’ array is not empty and click on its last element. Why the last one? The upgrades in the game are listed from the worst to the best one. With a choice between two improvements we can buy, we’ll always choose the better one. Finally, our function should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const checkProducts = async () =&amp;gt; { 
    const products = await driver.findElements({className: 'product unlocked enabled'}); 
    if (products.length &amp;gt; 0) { products.pop().click(); 
    } 
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We check if the length of the array is greater than zero — if it is, then we are clicking on its last element. All we have to do is call our function at the right time. Luckily, we have an interval that is responsible for clicking our cookie — so let’s use it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;setInterval(async () =&amp;gt; { 
  cookieEl.click(); 
  await checkProducts(); 
  }, 500);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Eventually, our script looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const webdriver = require('selenium-webdriver'); 
const chrome = require('selenium-webdriver/chrome'); 
const chromedriver = require('chromedriver'); 

chrome.setDefaultService(new chrome.ServiceBuilder(chromedriver.path).build()); 
const driver = new webdriver.Builder().forBrowser('chrome').build(); 

const checkProducts = async () =&amp;gt; { 
    const products = await driver.findElements({className: 'product unlocked enabled'}); 
    if (products.length &amp;gt; 0) { 
        products.pop().click(); 
    } 
}; 

const startInterval = () =&amp;gt; { 
    const cookieEl = driver.findElement({id: 'bigCookie'}); 
    setInterval(async () =&amp;gt; { 
       cookieEl.click(); 
       await checkProducts(); 
    }, 500); 
}; 

const init = () =&amp;gt; {     
    driver.get('https://orteil.dashnet.org/cookieclicker/');   
    driver.wait(webdriver.until.elementLocated({id: 'bigCookie'})); 
    driver.wait(webdriver.until.elementLocated({className: 'product'})); 
    startInterval(); 
}; 

init();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;30 lines of pure cheat. With the bot doing all the clicking, we can spend our time on something different… Maybe programming another bot?&lt;/p&gt;

&lt;h3&gt;
  
  
  Summing up
&lt;/h3&gt;

&lt;p&gt;Despite the relatively small amount of code that I have prepared here, I showed you a very interesting tool which is Selenium WebDriver. Of course, it wasn’t created to cheat at games. It is used in the automation of testing web applications. Once prepared, it saves a lot of time in application regression testing. If you ever considered becoming a tester of such applications, it’s an absolute must-have in your toolbox.&lt;/p&gt;

&lt;p&gt;This tutorial is just a brief coverage of a vast topic of automating actions happening in the browser. We hope it will encourage you to dig deeper and come up with great solutions to make your everyday work more efficient. We don’t want to waste time on routine, do we?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Article by Krzysztof Drozdowski. Originally published at&lt;/em&gt; &lt;a href="https://angrynerds.co/blog/automating-repetitive-actions-with-selenium-webdriver-and-nodejs/"&gt;&lt;em&gt;https://angrynerds.co&lt;/em&gt;&lt;/a&gt; &lt;em&gt;on October 15, 2019.&lt;/em&gt;&lt;/p&gt;




</description>
      <category>bots</category>
      <category>node</category>
      <category>selenium</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
