Question
Very often, when discussing programs, the term “logic” or “business logic” is used.
For example:
- (on unit tests) it is not necessary to achieve 100% coverage of the code with tests, it suffices to test only logic .
- (about web applications) the controller should not contain any business logic , but should only call methods of other classes
- There should be no business logic in the VIEW layer (that is, in the JSP files)
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 {
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.