📜 ⬆️ ⬇️

Where is the logic hidden?

Question


Very often, when discussing programs, the term “logic” or “business logic” is used.
For example:


So, who will tell me what “logic” is? Do I mean by this any IF in the code? But does code without IFs happen? Or (business-) “logic” means any information that comes from a client? But can we do something for the client’s money that he did not order? Can not. Therefore, all our code is entirely “business logic” from the client. That's why I could never understand what this damn logic is.


')

Answer


It may be easier to answer this question if the word “knowledge” is used instead of the word “logic”. Logic is any knowledge of code, or how code should behave. You can also formulate this: “logic” is all that you would like to comment at least once.

Example


Take for example the class Account, which I recently dug up in my project.

It was so. One day in our office, the Internet was cut off for a couple of hours. I actually could not work - well, there, svn, jira, the knowledge base, etc. were not available. And I decided as an exercise to write a unit test for some class. And stumbled upon Account:

public class Account { // Negative amount means that account is prepaid private BigDecimal amount; public BigDecimal getAmount() { return amount; } //        } 


It would seem, what is there to test? Where are the IF's? Where is the logic here? It would seem that there is none, and there is nothing to test. I already wanted to throw this class and find something more complicated, when I suddenly noticed a comment about the variable amount :
Negative amount means that account is prepaid


What is it?
It turns out that the “amount” is the total debt of this customer, and if the customer has made a prepayment, then this “debt” is with a minus sign. Well, this is some kind of knowledge about the code. Let's try turning this comment into a unit test :

 public class AccountTest { @Test public void negativeAmountMeansThatAccountIsPrepaid() { Account prepaidAccount = new Account(-123); assertTrue(prepaidAccount.isPrepaid()); } } 


Once we check the case of a negative amount, it is good to check the case of a positive one:
  @Test public void positiveAmountMeansThatAccountIsInDebt() { Account indebtAccount = new Account(456); assertFalse(indebtAccount.isPrepaid()); assertTrue(indebtAccount.isInDebt()); } 


This is how we accidentally had two new methods, isPrepaid and isInDebt, the implementation of which, of course, is obvious:
 public class Account { private BigDecimal amount; public boolean isInDebt() { return amount > 0; } public boolean isPrepaid() { return amount < 0; } } 


You see, already IFs appeared in the code!
The next thought that should come to mind is: probably these IFs were already somewhere before?

I had to search a little bit, but it was worth it. It turned out that these IFs were indeed in the code, and not just anywhere, but in the JSP file, that is, in the “view” layer, in which, by definition, there should be no logic:

 <%-- Positive amount means that account is in debt %--> <c:if test="${account.amount > 0}"> <font color="red"> !</font> </c:if> <c:if test="${account.amount < 0}"> <font color="green"></font> </c:if> 


Opanki, how interesting! So my second test case surfaced. How wonderful. Now, since we have the isInDebt and isPrepaid , we can remove the logic from the JSP:

 <c:if test="${account.inDebt}"> <font color="red"> !</font> </c:if> <c:if test="${account.prepaid}"> <font color="green"></font> </c:if> 


Got better? I think that has become. This is a bit more like encapsulation - hiding the implementation from prying eyes. Only the Amount class knows in which case the client owes or does not owe money. No one else in the whole world knows how this happens - the client gets a ready-made solution using the isInDebt and isPrepaid . Theoretically, the values ​​of "debt" and "prepayment" in general can be stored in different columns of the database, or even in general in different tables and in general in different databases. Now, due to the presence of two methods, this logic is hidden (encapsulated) in the class Account .

If you still don't believe, compare the amount of code.
It was
 <%-- Positive amount means that account is in debt %--> <c:if test="${account.amount > 0}"> <font color="red"> !</font> </c:if> 

It became
 <c:if test="${account.inDebt}"> <font color="red"> !</font> </c:if> 



You can go even further and instead of the getAmount() method getAmount() can do two different methods getPrepaidAmount() and getDoubt() . Moreover, inside them you can check whether the client really has a debt or a prepayment. That is, now it will be impossible, for example, to write such code:

 <%--      ,    . %--> <c:if test="${account.amount != 0}> <font color="red"> !</font> </c:if> 


Ideally, the getAmount () method can now be completely erased. This is the real encapsulation: hide data and code and give access only through methods. I think if the Internet had not been repaired, I would have gotten rid of the remaining 20 getter setters.

Morality


You can see how unit tests lead to readable, object-oriented code. And you say: “There is no logic in my code, there is nothing to test there ...” As it is!

The logic is there, it can not be.

Source: https://habr.com/ru/post/114889/


All Articles