Tips:: Don't Play with Developers emotion.

Clean code Tips
 

Tips:: "To Me, CLean code is the Developer's Emotion, a code maintaining a classical design or badly written, both are two extremities and must be avoided, as per statistics we have a large number of developers who wants to see code as simple methods and classes combination with   readable variable names neither a grand design nor an unreadble code."



javaOnFly started a new segment called Tips corner, every Saturday we will post Tips only for you to make you a better programmer.

If you Like the Tips want more about the topic , you can read a whole bunch of detailed Java Articles on javaOnFly, if you like the content, you can subscribe to javaonfly.

Still not Satisfied!!! I love to discuss with enthusiastic people like you, on Java, Patterns, Microservice, clean code latest Trends, I am just one click away from you to connect

Follow me on

javaonfly :: https://javaonfly.blogspot.com

Twitter :: https://twitter.com/Shami83

Linked In :: https://www.linkedin.com/in/shamik-mitra-05b66227/

Instagram :: https://www.instagram.com/shamik.mitra/

Dzone :: https://dzone.com/users/1211805/mitrashamik.html

Facebook Group :: https://www.facebook.com/groups/javachamp

FaceBook Page :: https://www.facebook.com/artofjavaprog


#java #javaOnFly #code #programming #cleancode #covid javaonfly

#ask2shamik #tips

Getter method - cheating the spirit of "Law of Demeter"

 

Every time I look at the Getter methods, I wonder, a simple getter method but its impact is very high on the code. 

Is it a friend for developers or enemies who are acting as friends? 

We can discuss various topics on Getter but here I would focus on one topic, which impacts codebase severely and forcibly implementing coupling and breaching the encapsulation. 

The most interesting part is that in some cases Getters can cheat the “Law of Demeter” rules, welcome coupling, and breach encapsulation. 

So it creates confusion for developers and as an outcome, we ended up with bad quality code. Today I am going to discuss how getter method cheats the “Law of Demeter's” rules

 

Note:: I will not discuss “ Law of Demeter “ principles, I assume you have a fair bit of idea of that, I will just give a pointer on Law of Demeter so I can show you the cheating. 

What is Law of Demeter say:: 

In layman's terms, it is saying never talk to strangers as strangers are a danger, only talk to your friends. 

So, in technical terms, a method can only interact with its arguments, it’s holding class instance variables, Objects which are created inside the method context, and static variables in java.  

More precisely, For any class C, a method M belonging to C may only invoke the following:

  1. The object class C itself
  2. Members of class C
  3. An argument of the method M
  4. An object created within the method M
  5. Global objects 

Rules are very clear and specific, it tries to minimize the communication /

If you restrict your communication with passed arguments and the class instance variable then you are reducing the coupling, more communication means more coupling, if your degree of coupling is higher the obvious you are breaching encapsulation.

Although, Law of Demeter tries to secure encapsulation by enforcing the law “Talk to immediate friends not to any strangers” -- but our good(really?) The getter method can trick it, getter will maintain all the laws but humiliate the Law of Demeter by cheating. 

Let’s take a regular example which we can see often in the codebase.


Department.java

public class Department { private Long deptId; private Employee deptHead; private String deptName; public Long getDeptId() { return deptId; } public void setDeptId(Long deptId) { this.deptId = deptId; } public Employee getDeptHead() { return deptHead; } public void setDeptHead(Employee deptHead) { this.deptHead = deptHead; } public String getDeptName() { return deptName; } public void setDeptName(String deptName) { this.deptName = deptName; } } DepartmentReport.java package blog.javaonfly.article.getter; public class DepertmentReport { public void buildReport(Department dept) { /* * As per LOD Ok , but what is the use of doing that--??????? * Why are you cheating LOD spririt. */ Employee deptHead = dept.getDeptHead(); String deptHeadName = deptHead.getName();//LOD Breaks here !!!!! System.out.println("In Report" + dept); } }

Now , inspect these two lines


Employee deptHead = dept.getDeptHead();

String deptHeadName = deptHead.getName();//LOD Breaks here !!!!!


We have passed the Department object in build report method, so as per Law of Demeter we can talk to Department object, so we can call it’s getter method, getDepartmentHead() , which return an Employee Object which is stranger to buildReport method, so at this point, although we have not broken the Law of Demeter rule but Employee Object sneak in Report class and create a coupling!!!

Think logically, is it the Report object’s responsibility to deal with the Employee Object? 

The answer is obviously no, but then what do we do with only Employee Object in Report class? Employee Object is not useful if we do not dig into it as in report we may need the name of the Department head, the moment we call getName method it breaks the Law of Demeter as it says method needs to only interact with arguments, Rule 3.

So, dept.getDeptHead().getName(); is not permissible according to the law, and it is good as you do not know Employee is null or not in buildreport method if it is null, it will break Reports code!!!

So, By getter actually, we did the cheating to get a third level Object Employee(Report -> Department->Employee), but we can not do any useful thing with it without breaking Law of Demeter, But no one gives attention to Law of Demeter and we break the Law of Demeter, by happily calling a chain of getter methods.

This is one reason I do not like Getter's, it breaks encapsulation silently.

Now, let's make it more interesting.

Adding below code snippet in Department.java


public String getDeptHeadName() {

return deptHead != null? deptHead.getName():null;

}


Then , call this method in Department Report class buildReport method


String deptHeadName = dept.getDeptHeadName();


Now, Again according to the Law of Demeter it is perfect. The Department only talks to an instance variable department Head(Rule 2), and Report class told to method arguments(Rule3).

But again, we are breaking the spirit of Law of Demeter, Departments should not do any operation on Employe objects field, it is Employee Object responsibility to do the formatting and all other operation on it’s filed and get presentable data to the caller so, the caller should not do any operation on it.

Basically, Caller will not ask for data it will command the associate class for readymade data.

Tell don’t ask principle.

In this example you are asking, getter methods are asking for data that means asking for more responsibility to properly handle them, which is not your duty at all.

Now, what about this case,


public void buildReport(Department dept) {

Employee deptHead = dept.getDeptHead();

String deptHeadName = getDepartmentHeadName(deptHead);

System.out.println("In Report" + dept);

}

private String getDepartmentHeadName(Employee emp) {

return emp.getName();

}


Again, we did some trickery, we maintained the Law of Demeter but cheating its essence!!!

Now, we create a private method and pass the Employee object as an argument and call geName in that method, now as per Rule 3 we are good, but think on class perspective, as per Law of Demeter we should talk to immediate friends which is Department Object but here again We are talking to Employee Object.

What do we learn from this?


  • We learn that the Law of Demeter is giving us suggestions on how to reduce coupling and be safe by not talking to strangers but there are many loose ends from where we can break the naive clause of Law of Demeter, Getter is one of those.
  • Use Getter carefully, it may look simple but often breaks encapsulation by exposing a Has-A relationship to the Outerworld.
  • Do not write getter for HAS-A relationship, it means you are delegating the responsibility to the caller or Higher level methods.
  • Calling getter Chain is bad if each getter returns different Objects, because if any of the values is null then you are in deep trouble, adding multiple nulls check will not help you, it increases your complexity of codes.


Conclusion:: Law of Demeter is good when you take it as a suggestion, but if you technically try to prove you are maintaining the laws and tricks it, then there will be debate and may you win the debate but losing the code quality, on other hand, if you think logically put programming reasoning then only you can thank “Law of Demeter”.

God Class- The developers booby trap!!!


 We all know what is a dystopian world -- A world of Chaos or Injustice, for developer Antipattern, is the dystopian world but surprisingly willingly or unwillingly developers love to live in a dystopian world.


Jokes apart, but this is the ground reality for most of the Legacy or old projects, common experience for developers are they change in one place, it breaks in another place. This has happened due to three major factors.


  1. Tight coupling and complex codebase.

  2. Multiple God Objects are driving Business Logic.

  3. Inexperienced coder and tight timeline.



I have discussed enough on Tight coupling, SRP, KISS, Law of Demeter all these, these are the basic stuff must-have in the developer toolbox irrespective of experience.


Ironically we assume junior developers(Not all Juniors some are very good) may not have this knowledge, only Core Java knowledge is sufficient for them, and in the selection process we omit those questions or in their syllabus, we will not include them. Anyway, I am not going to discuss that this is a different topic and different countries have different selection processes or syllabus.


My take on coding is if from the beginning you do not know basic design principles, you can’t build a good code, which impacted other project members in long run, implementing a business logic according to acceptance criteria is just the tip of Iceberg, handling negative scenario and modularizing and packaging would be your main focus. 


In Agile for a 5 pointers development story(not counting QA), i like (2 + 1+1+1) split,  

2 for designing and packaging higher component(Top-down approach)

1 for Building logic,

1 for handling error handling

1 for Unit Testing.


If you are not maintaining design and packaging you will end up with multiple God objects, let discuss what do we mean by God Objects?


God Object/Monster Object :: 


In a simple term, God objects are something that is doing everything or knows about everything. That Uncle who pokes his nose in everywhere. 


Want to trace your project’s God objects footprint? Check your last two months' commit history and plot a graph and find out which are classes modified most.


You will observe a few classes will change often, those are your projects God Objects- who controlling your projects. In a classical word a Feature Envy class. 


I always wonder what makes God Objects?


so, I try to see the commit history of the God object and found one use case that in the first place a developer creates objects which hold few important business responsibilities, the intention was to create a Mediator type of object which has reference to multiple other important objects to reduce the coupling and accomplish more business logic with a small line of codes. To know how Mediator reduces coupling you can check the Mediator pattern.


Then over time developers are adding logic on top as this class acts as one shop for all. Blindly developers put logic there as it has already all-important objects references !!!!!.

it grows over time until you get a big escalation and your project managers mandate no one touch this class!!!! 


So, If we restrict ourselves in the first place we can reduce the probability of God Object, Once Mediator object grows it will turn into God objects-- A obvious booby trap, Once God Objects are created I think at that point in the Agile era refactoring a God object is very tough and should be avoided. 

On the contrary, during each sprint, at the end of the development phase you need to pay attention to Modularizing and refactoring your code a must-do activity in Sprint, to accomplish it, take a blanket story for all development work, Sprint goal is not to only focus on MVP also it needs to focus on Technical quality, but the second one is missing most of the cases, As, Business or Scrum Master doesn't want to give importance on code quality, peer review. I am open to hearing various perspectives on the strategy, 

How to maintain good code quality in Sprint?


 God objects are bad for your code, it's a booby trap which brings unwanted side effects. Often your Mediator Objects turned in into God object, Pay attention to Mediator Objects after each sprint and refactor it when necessary, Restricting it in the first place will be the best protection not to refactor after it turned into God Objects.

Clean Code:: Method Arguments must be crisp and Encapsulated.


 While writing methods, please pay close attention to the method arguments, This is the one area where the method assimilates the foreign body into its core body. Foreign material is always dangerous, you do not have any control over it, but as an owner of a method, you can put a defensive mechanism aka Validation. Or the Anti-corruption layer of your method.


So, the first tip.

  1. Always put validation on the input argument, you can use java annotations to do the validation.


Now, let's think about what we do in a method after receiving the inputs.


Most methods will do three things.


  1. It will act on the inputs:: so the method will receive the inputs and apply some business logic on them and get a result.


Example::


public void buildReport(String firstName, String lastName, String address, int age, char sex, String dept) {

//build the report

}


If you pay attention to this method we can derive one important thing, the input parameter passed here has associativity, what I meant to say, all input parameters are passed into the method for which reason? Simple, to create the report we need those data. Think logically, when you build a report it will focus on a segment or a context. The Business rule always works to accomplish a feature inside a domain. So if you build a report which needs the above arguments that means you are dealing with the data which are used together frequently because they are in the same domain and same context.


In some cases, I saw some methods which take data from multiple domains and aggregate it and give a view of overall functionality but those cases are less. Mostly a method works on a narrowed feature under a domain. 

Tip 2 :  if your arguments list is long that means you are breaching encapsulations, easily you can tie them under an object as those arguments are often changed or used together, then pass that wrapped object.


I can modify the above method cleaner way



public void buildReport(EmployeeReportContext employeeReportContext) {

//build the report

}



I tied related arguments in the EmployeeReportContext object and make it a Monadic function(A method which takes one argument)




2.  Methods will take decisions based on the arguments:: it will take the arguments and based on the arguments perform some algorithm or business rule to accomplish a feature.




public void serachEmployee(String firstName,String lastName, String latLong, ,Long deptId) {

//build the search query based on the inputs.

}



Again, we can see we are dealing with related input which can be encapsulated in an object.

Now on top of this, another observation is if we pass multiple arguments that means this method is responsible for multiple decision making but we know in SRP Pyramid on a particular level one method is responsible for one responsibility. So the method is breaking SRP, how we can solve this, just segregate out the decision/responsibility by extract method strategy.


I will break the methods into small chunks, in this way by extracting responsibility. Also, reduce the argument list and make each method a monadic Method.



public void searchEmployee(EmployeeSearchInput input) {

Address address = findAdressFromLatLong(input.getLatLong());

Department dept = finDeptbyID(input.getDeptId());

//TODO :: populateEmployeeSearchInput using address and dept

query = buildSearchquery(input);

result = executeSearch(query)



}



3. Holder methods:: These kinds of methods are edge methods that will take the arguments and pass those arguments to next-level methods.


Now first understand why we need this type of method? I like to call them Edge methods like edge service, while we are building an N-tier architecture often we need to pass a good amount of data to the next tier, now if you pass multiple arguments to the next level it will create coupling.


On the other hand, we also do not want to call next tier methods multiple times, then in a distributed system, it will create a Chatty communication where we need to pass multiple data over the network multiple times.


So it boils down to one principal question: how we can pass all data in one shot,on top of that we need to think about the future if I want to pass new data between tiers how to accommodate them because the holder method is a contract between two layers you can’t change method signature often !!!!



So passing multiple arguments in the holder methods is not a solution, as in the future you can change the signature.


So the best way to design this type of method is to create a coarse-grained object (DTO), and pass all data in one shot, or a Map like structure key is the property and value is the object, in both cases, you can easily extend them without breaching the contract.


Example:: The best example is the HTTPRequest object it carries data from UI to controller and servlet doPost and doGet is the holder method which takes the request, extracts parameters from it, and then passes to the next level.


Also, DTO (Data Transfer Object) is doing the same job.



Conclusion:: what we learned from the article?


We learned whatever the method type is, always encapsulate the inputs parameter, never pass multiple parameters in a method, it brings smell in different ways. 


Try to restrict method argument to null-- no foreign body, or one, maximum 3 but over than three is risky, needs to wrap them or need to extract the responsibility from the calling method.