User Tools

Site Tools


principles:single_level_of_abstraction

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
principles:single_level_of_abstraction [2014-06-30 23:17]
christian origin, Further Reading
principles:single_level_of_abstraction [2019-08-07 00:20] (current)
52.88.14.253 [Description]
Line 1: Line 1:
 ====== Single Level of Abstraction (SLA) ====== ====== Single Level of Abstraction (SLA) ======
- 
 ===== Variants and Alternative Names ===== ===== Variants and Alternative Names =====
 +
  
   * One Level of Abstraction   * One Level of Abstraction
Line 12: Line 12:
 ===== Principle Statement ===== ===== Principle Statement =====
  
-Each [[glossary:​module]] ​should be written in terms of a single level of abstraction.+Each method ​should be written in terms of a single level of abstraction.
  
  
Line 19: Line 19:
 All statements of a method should belong to the same level of abstraction. If there is a statement which belongs to a lower level of abstraction,​ it should go to a private method which comprises statements on this level. Doing so will result in smaller methods. All statements of a method should belong to the same level of abstraction. If there is a statement which belongs to a lower level of abstraction,​ it should go to a private method which comprises statements on this level. Doing so will result in smaller methods.
  
-Often the body of a loop can be extracted resulting in a separate private method. Loops should ideally contain a single statement (usually a method call). Sometimes this is not achievable without other drawbacks but certainly large loop bodies can be considered a small+Often the body of a loop can be extracted resulting in a separate private method. Loops should ideally contain a single statement (usually a method call). Sometimes this is not achievable without other drawbacks but certainly large loop bodies can be considered a smell
  
 A further indicator for a missing method is the combination of a blank line, a comment and a block of code. In most of the cases the code block should go to a new private method. This also makes the comment obsolete as the new method carries a name which typically resembles the comment. ​ A further indicator for a missing method is the combination of a blank line, a comment and a block of code. In most of the cases the code block should go to a new private method. This also makes the comment obsolete as the new method carries a name which typically resembles the comment. ​
  
-Sometimes extracting the method would result in the new method having a large number of parameters. Alternatively the parameters could be converted to fields of the class. But this would often result in bad [[glossary:​cohesion]]. Because of that in such a case extracting a new class is the next step in adhering to the principle.+Sometimes extracting the method would result in the new method having a large number of parameters. Alternatively the parameters could be converted to fields of the class. But this would often result in bad [[glossary:​cohesion]]. Because of that in such a case extracting a new class is the next step in adhering to the principle. ​ 
  
 ===== Rationale ===== ===== Rationale =====
Line 36: Line 36:
  
 ===== Caveats ===== ===== Caveats =====
- 
 See section [[#contrary principles]]. See section [[#contrary principles]].
  
Line 42: Line 41:
 ===== Origin ===== ===== Origin =====
  
-Stated in  +Stated in [[resources:​Clean Code]] (p. 36). The principle ​is maybe older, though.
-{{page>resources:​Clean Code#​reference}} ​(on page 36). The principles ​is maybe older.+
  
 ===== Evidence ===== ===== Evidence =====
Line 60: Line 58:
  
 ==== Specializations ==== ==== Specializations ====
 +  * [[One Line Blocks]]
  
 ==== Contrary Principles ==== ==== Contrary Principles ====
- 
   * [[More Is More Complex|MIMC]]:​ Adhering to SLA results in more methods and classes.   * [[More Is More Complex|MIMC]]:​ Adhering to SLA results in more methods and classes.
   * [[Principle of Separate Understandability|PSU]]:​ The purpose of SLA is to avoid [[glossary:​mental grouping]]. On the other hand just adhering to SLA and neglecting PSU may result in the opposite: The reader of the code has to do [[glossary:​mental inlining]]. Sometimes it can be more readable to allow a small amount of statements on the "​wrong"​ level of abstraction (like having a guarding if statement in a higher level method).   * [[Principle of Separate Understandability|PSU]]:​ The purpose of SLA is to avoid [[glossary:​mental grouping]]. On the other hand just adhering to SLA and neglecting PSU may result in the opposite: The reader of the code has to do [[glossary:​mental inlining]]. Sometimes it can be more readable to allow a small amount of statements on the "​wrong"​ level of abstraction (like having a guarding if statement in a higher level method).
Line 77: Line 75:
 ===== Examples ===== ===== Examples =====
  
-==== Example1: ​ ====+==== Example1: ​Loops ==== 
 + 
 +A typical example for the application of SLA is a loop iterating over a certain data structure:​ 
 + 
 +<code java> 
 +public List<​ResultDto>​ buildResult(Set<​ResultEntity>​ resultSet) { 
 +    List<​ResultDto>​ result = new ArrayList<>​();​ 
 +    for (ResultEntity entity : resultSet) { 
 +        ResultDto dto = new ResultDto();​ 
 +        dto.setShoeSize(entity.getShoeSize()); ​        
 +        dto.setNumberOfEarthWorms(entity.getNumberOfEarthWorms());​ 
 +        dto.setAge(computeAge(entity.getBirthday()));​ 
 +        result.add(dto);​ 
 +    } 
 +    return result; 
 +
 +</​code>​ 
 + 
 +There are two levels of abstractions in this method. First there is the loop which acts upon the whole result set and second there is the loop body which converts a single entity to a [[patterns:​Data Transfer Object|DTO]]. For the latter there is no syntactical grouping. The reader of the code has to find out that the first four lines of the loop body belong together. The code also doesn'​t explicitly state that these four lines convert an entity to a DTO. So the following code is better: 
 + 
 +<code java> 
 +public List<​ResultDto>​ buildResult(Set<​ResultEntity>​ resultSet) { 
 +    List<​ResultDto>​ result = new ArrayList<>​();​ 
 +    for (ResultEntity entity : resultSet) { 
 +        result.add(toDto(entity));​ 
 +    } 
 +    return result; 
 +
 + 
 +private ResultDto toDto(ResultEntity entity) { 
 +    ResultDto dto = new ResultDto();​ 
 +    dto.setShoeSize(entity.getShoeSize()); ​        
 +    dto.setNumberOfEarthWorms(entity.getNumberOfEarthWorms());​ 
 +    dto.setAge(computeAge(entity.getBirthday()));​ 
 +    return dto; 
 +
 +</​code>​ 
 + 
 +Now there are two smaller methods each of which is written in terms of a single level of abstraction. This is better readable as no mental grouping is necessary. Furthermore the two methods are still separately understandable ([[Principle of Separate Understandability|PSU]]) so no mental inlining is necessary and if you don't care about the details of the ''​toDto''​ method, you can just read and understand ''​buildResult''​ without being distracted by unnecessary detail. 
 + 
 +==== Example2: Comment Plus Code Block ==== 
 + 
 +==== Example3: Parameter Checking ==== 
 + 
 +==== Example4: Extracting Classes ​====
  
 ===== Description Status ===== ===== Description Status =====
principles/single_level_of_abstraction.1404163020.txt.gz · Last modified: 2014-06-30 23:17 by christian