The Hollywood Principle

The Hollywood Principle


Hollywood.jpg



Hollywood Principle says:  "Don't call us, we'll call you"

This little sentence opens up a new viewpoint in Software industries. This is one of the important principles every developer should know.

In this article, we will try to discuss this principle.

"Don't call us, we'll call you" what does it mean?

In layman terms,  you don’t have to bother about when your turns come, when your turns come they will call you.

But What you and they denote here?

To explain "you" and "they" in technical terms first we need to understand How a Software design works.

When we design a software we try to implements two things.

  1. API
  2. Framework.


  1. API:  API used to publish some methods/functions so the caller/user of the API call this method to get some useful information. So caller does not have any action points to take only call methods and get output.
  2. Framework: The Framework is a little bit critical than API. The framework is maintaining an algorithm but it expects the value to be produced by the caller of the Framework. To put it simple way, Framework takes Strategy or Business implementation from the caller and call it when it requires.



By Hollywood principle, we can make Framework works, where you means the Strategy or business implementation, which needs to be fed, and they denote framework engine/implementation which calls fed strategy when required.

Real time Example:

Spring DI: Think about Spring where we declare beans in XML, and Spring container call these beans create Spring beans, inject other beans into it and returns fully configured bean.  So by the help of XML, we feed the strategy and Spring container calls them when required. We often called it Dependency Injection so Hollywood Principle’s another name is IOC(Inversion of Control).

Struts 1.x: Pay attention to Struts 1.x implementation where caller of Struts extends ActionClass and provide  Business implementations in the Action class and Struts framework call those Action class based on the URL mentioned in Struts config file. So here Action class is Strategy and Struts framework invokes it.

Observer pattern/Listener in Swing:  Think about Swing’s actionListener we subscribe to an event like button click, on Blur etc and when this event occurs Swing call our code written in the actionPerformed method.


Apart from this Servlet / EJB all maintains lifecycles so underlying server calls appropriate life cycle method when the servlet or EJB state changed like init, service, destroy or ejbActivate ejbPassivate etc.

We call those methods as Callback methods because Framework call this method we don’t have to call them but we may provide the implementations of those methods if we want to push some strategies in Framework.



Let see a use case where we can use Hollywood principle

Say Cognizant has a Resume upload portal where job seeker uploads their resumes. When there is an On campusing happens in Cognizant they will call them by sending a mail to their inbox.

We can implement the same by Hollywood principle,
Jobseeker uploads their resumes in Job portal and Cognizant send mail to them when an on campusing occurs.
cognizant says : Don’t call me I will call you. :)Hollywood (2).jpg

Let see the implementation.

Assumption : Here I have not introduced any interface for sake of simplicity and not add any complex scenario like a priority, reset, GroupWise mail sending etc. as I just wanted to show How Hollywood principle works.


Resume.java

/**
*
*/
package com.example.hollywood;

/**
* @author Shamik Mitra
*
*/
public class Resume {
    private String email;
    private String name;
    private String content;
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getContent() {
        return content;
    }
    public void setContent(String content) {
        this.content = content;
    }
    @Override
    public String toString() {
        return "Resume [email=" + email + ", name=" + name + ", content=" + content + "]";
    }
   
   

}


CognizantJobPortal.java

/**
*
*/
package com.example.hollywood;

import java.util.ArrayList;
import java.util.List;

/**
* @author Shamik Mitra
*
*/
public class CognizantJobPortal {
   
    private static CognizantJobPortal portal = new CognizantJobPortal();
   
    public static CognizantJobPortal get(){
        return portal;
    }
   
    private CognizantJobPortal(){
       
    }
   
   
    private List<Resume> resumeList = new ArrayList<Resume>();
   
    public void uploadContent(String mail ,String name,String content)
    {
        Resume resume = new Resume();
        resume.setName(name);
        resume.setEmail(mail);
        resume.setContent(content);
        resumeList.add(resume);
    }

   
    public void triggercampusing(){
        for(Resume resume : resumeList){
            System.out.println("Sending mail to " + resume.getName() + " at " + resume.getEmail());
        }
    }
}


Test

/**
*
*/
package com.example.hollywood;

/**
* @author Shamik Mitra
*
*/
public class HollywoodTest {
   
    public static void main(String[] args) {
       
        CognizantJobPortal.get().uploadContent("shamik@xyz.com", "Shamik Mitra", "A java developer");
        CognizantJobPortal.get().uploadContent("Ajanta@vvv.com", "Ajanta Mitra", "A PHP developer");
        CognizantJobPortal.get().uploadContent("Swastika@vvv.com", "Swastika Mitra", "A Microservice developer");
        CognizantJobPortal.get().uploadContent("Mayukh@vvv.com", "Mayukh Mitra", "A Network engineer");
        CognizantJobPortal.get().uploadContent("Samir@123.com", "Samir Mitra", "A java Architect");   
        // Now trigger campusing
        CognizantJobPortal.get().triggercampusing();
    }

}

Output:

Sending mail to Shamik Mitra at shamik@xyz.com
Sending mail to Ajanta Mitra at Ajanta@vvv.com
Sending mail to Swastika Mitra at Swastika@vvv.com
Sending mail to Mayukh Mitra at Mayukh@vvv.com
Sending mail to Samir Mitra at Samir@123.com


Please note that in CognizantJobPortal class I maintain a list where uploaded resumes are added. When cognizant triggers a campusing, job portal/framework send the mail to all jobseekers who uploaded the CV to Cognizant.


































A Story on Flyweight pattern

The Flyweight pattern
Flyweight Pattern

Swastika wants to introduce Theme in her blog but she is facing a problem.

The Problem:

Her blog is a combination of multiple widgets like Header widget, Footer Widget, Content Widget, Follower widget etc.

And those widgets are populated by backend call or any web service call in a simple term to load widget repetitively considered as a costly operation.

But as Swastika wants to introduce Theme, Theme can reorder the widget position as well as the color of the widgets, As Look and Feel are different for the different theme.

So the question pop up in Swastika’s mind is

Every time User changes the Theme should she reload the widget and populate the data?
Then it is a very bad design as it will load all costly widgets again and again so sluggish the response.

As Theme Change operation is in User's hand so Swastika can’t say users to “don’t change Theme frequently”. It will hurt her blog reputation.

So what she do now?

Swastika goes to her OOP Teacher for a Solution.

Sir Tell her to Reuse Widget but she believes her widget is stateful, so she explain the problem she has having now,

Swastika : Sir, I can use cache and put the Widget against a key in the cache and reuse it, but say my default theme is Classic Blue so every widget has color blue and say in classic Blue theme my Follower widget is in Left of the Screen.  Now if a user changes it to Slick green, then every widget must have to change their color to Green and say in Slick green theme, Follower widget will be on the Right side of the screen.

Now If I want to reuse my widget from cache it has Blue color and Follower widget position is in left so How I can reuse them without populating a new widget?


Sir: Wow, what a thought Swastika, very good but think about the scenario here your Widget populate data from backend and loaded once, But if you want to load it again for just to assign a color and position then you welcoming a potential danger to your blog.



So your new feature is not an addition it is a technical debt. Then it is better not to have it.

Think in an OOPs perspective when you change the Theme what happens, it just reorders your widget position and changes the color but widgets content are remain same. So if you load the Widget once and make your widget to capable of taking color and position value from outside then can you reuse your widget?

The answer is Yes as because apart from color and position your widget is state-independent in this context as it’s content does not change.

By Oops you can easily pass any attribute from outside and based on the theme your widget layout manager can decide what would be the position and color of your widget.



Flyweight pattern does the same.

What is a Flyweight pattern?

According to Wiki:
A flyweight is an object that minimizes memory usage by sharing as much data as possible with other similar objects; it is a way to use objects in large numbers when a simple repeated representation would use an unacceptable amount of memory. Often some parts of the object state can be shared, and it is common practice to hold them in external data structures and pass them to the flyweight objects temporarily when they are used.


So According to the definition widgets are Flyweight objects and reloading them unnecessary increase response time, So instead of that if we share color and position data to all Flyweight objects/Widgets then we can reuse the Widgets. And layoutManager computes the value of color and position by using Theme, An external data structure.

So every Flyweight object has two kinds of data

  1. Intrinsic data:  Which is State independent data, that is which does not change with the context like Swastika’s Widgets content does not change with the theme.
  2. Extrinsic Data:  Which is context-dependent data and changed with the context like Swastika’s Widgets color and position change with Theme.
To make our Flyweight object reusable we need to pass extrinsic data from outside to       Flyweight Object.

Coding Time:

Sir start the coding to show Swastika How he can make her widget reusable without loading it --help of Flyweight pattern.


IWidget.java

/**
*
*/
package com.example.flyweight;

/**
* @author Shamik Mitra
*
*/
public interface IWidget {
   
    public void setWidgetName(String name);
    public String getWidgetName();
    public void setWidgetContent(String content);   
    public void display();
    public void applyTheme(String color,String postion,Layoutmanager manager);

}



Now Sir create a layout manager and use Flyweight pattern there.

/**
*
*/
package com.example.flyweight;

import java.util.HashMap;
import java.util.Map;

/**
* @author Shamik Mitra
*
*/
public class Layoutmanager {
   
    private static Layoutmanager mgr = new Layoutmanager();
   
    Map<String,IWidget> map = new HashMap<String,IWidget>();
   
    public static Layoutmanager get(){
        return mgr;
    }
   
    private Layoutmanager(){
        init();
    }
   
       
    public void addWidget(IWidget widget,String position){
        System.out.println("Adding Widget " + widget.getWidgetName()+  " in to position " + position);
       
    }
   
    private void init(){
       
        IWidget followerWidget = new IWidget(){
           
            private String name;
            private String content;
            private String color;
            private String position;

            @Override
            public void setWidgetName(String name) {
            this.name=name;
            }
           
            @Override
            public String getWidgetName() {
            return name;
            }

            @Override
            public void setWidgetContent(String content) {
            System.out.println("setting content first-time....loading from back end costly operation");
            this.content=content;
               
            }

            @Override
            public void display() {
                System.out.println(" Widget name : " + name);
                System.out.println(" Widget color : " + color);
                System.out.println(" Widget color : " + position);
                System.out.println(" Widget content : " + content);
            }

            @Override
            public void applyTheme(String color, String postion, Layoutmanager manager) {
                this.color=color;
                this.position=postion;
                manager.addWidget(this,postion);
               
            }
           
        };
       
        followerWidget.setWidgetName("Follower Widget");
        followerWidget.setWidgetContent("Showing blog Followers.");
        followerWidget.applyTheme("Blue", "LEFT", this);
        followerWidget.display();
        map.put(followerWidget.getWidgetName(), followerWidget);
       
       
       
    }
   
   
    public void ChangeTheme(){
        System.out.println("After Change Theme");
        for(String name : map.keySet()){
            if("Follower Widget".equalsIgnoreCase(name)){
                IWidget widget = map.get(name);
                widget.applyTheme("Green", "RIGHT", this);
                widget.display();
            }
        }
    }
   
    public static void main(String[] args) {
        Layoutmanager mgr = Layoutmanager.get();
        mgr.ChangeTheme();
    }
   
   

}







Explanation:
In Init() method sir creates Follower Widget for the first time and put it on a map so later on when the user does change the theme Sir can reuse the Widget.
Then apply the Classic Blue theme as the default theme.

When user call ChangeTheme() method, the application calls every Widget’s applyTheme() method and pass color and position from Layout manager so Widget/flyweights Object can change the color and set itself in the correct position.

Here Color and Position: the Extrinsic property of Flyweight Object.
Other properties of Widget is Intrinsic in nature.


Improvements:

Please note that this is a very basic example. To make it concrete more improvement needed like.

  1. The theme has to be a context Object implements an ITheme interface which dictates what will be color and other properties.
  2. LayOutManager should be the implementation of ILayoutManager interface as there can be various Layouts.
  3. The widget can be decorated by decorator pattern.
  4. We can segregate the logic of Widget creation and load it into the cache in a separate Class called WidgetFlyWeightFactory.