Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Refactoring & Restructuring - Improving the Code and Structure of Software

220 views

Published on

According to the US Department of Defense, “Well structured software is delivered in half the time, at half the cost, and with 8x less bugs”. In this tech talk on structural quality, we briefly discuss why software structure matters and how good structural quality results in better developer productivity, provides developer guidance, helps improved estimates, reduces risk & meeting delivery dates, focused testing, enhanced reuse & extensibility and helps divide the labour in large teams.

As Martin Fowler observed, “High internal quality reduces the cost of future features, meaning that putting the time into writing good code actually reduces cost.” This talk is entirely focused on improving the internal software and structural quality. In specific, we discuss code refactoring with specific examples and discuss restructuring with demonstrations. By attending this talk, you will have a good understanding on why structure matters and specific & effective ways to improve internal software quality.

Published in: Software
  • Be the first to comment

Refactoring & Restructuring - Improving the Code and Structure of Software

  1. 1. HOW TO IMPROVE SOFTWARE CODE & STRUCTURE? GANESH SAMARTHYAM (KONFHUB) ganesh@konfhub.com
  2. 2. “HIGH INTERNAL QUALITY REDUCES THE COST OF FUTURE FEATURES, MEANING THAT PUTTING THE TIME INTO WRITING GOOD CODE ACTUALLY REDUCES COST” Martin Fowler WHY CARE? https://martinfowler.com/articles/is-quality-worth-cost.html
  3. 3. THREE STEP APPROACH AWARENESS -> ACCEPTANCE -> ACTION Smells Tech Debt Quantification Refactoring / Restructuring
  4. 4. IMPROVING CODE CODE SMELLS -> REFACTORING class PollutantEntry { String country; String state; String city; String place; LocalDateTime localDateTime; Float average; Float max; Float min; String pollutant; public PollutantEntry(String country, String state, String city, String place, LocalDateTime localDateTime, Float average, Float max, Float min, String pollutant) { this.country = country; this.state = state; this.city = city; this.place = place; this.localDateTime = localDateTime; this.average = average; this.max = max; this.min = min; this.pollutant = pollutant; } } OH! THIS IS SMELLY: DATA CLUMPS & LONG PARAMETER LIST
  5. 5. IMPROVING CODE CODE SMELLS -> REFACTORING public class PollutantEntry { private Location location; private LocalDateTime lastUpdate; private PollutionData pollutionData; /* The Builder class corresponds to the PollutantEntry - it helps create a Pollutant entry object given the location object, time of reading, and the actual pollution reading */ public static class Builder { PollutantEntry pollutantEntry = new PollutantEntry(); public Builder() { } public Builder location(Location location) { pollutantEntry.location = location; return this; } public Builder lastUpdate(LocalDateTime lastUpdate) { pollutantEntry.lastUpdate = lastUpdate; return this; } public Builder pollutionData(PollutionData pollutionData) { pollutantEntry.pollutionData = pollutionData; return this; } public PollutantEntry build() { return pollutantEntry; } } } INTRODUCE ABSTRACTIONS & USE BUILDER PATTERN!
  6. 6. IMPROVING CODE CODE SMELLS -> REFACTORING OH! THIS IS SMELLY :-( THIS IS SHORT & SWEET! :-)
  7. 7. THREE STEP APPROACH CODE SMELLS -> REFACTORING OH! THIS IS SMELLY :-( THIS IS SHORT & SWEET! :-)
  8. 8. EFFECTIVE APPROACH CODE SMELLS -> REFACTORING class Interpret { private static Stack<Integer> executionStack = new Stack<>(); public static int interpret(byte[] byteCodes) { int pc = 0; while(pc < byteCodes.length) { switch(byteCodes[pc++]) { case ByteCode.ILOAD: executionStack.push((int)byteCodes[pc++]); break; case ByteCode.IMUL: executionStack.push(executionStack.pop() * executionStack.pop()); break; case ByteCode.IDIV: { int rval = executionStack.pop(); int lval = executionStack.pop(); executionStack.push(lval / rval); break; } case ByteCode.IADD: executionStack.push(executionStack.pop() + executionStack.pop()); break; case ByteCode.ISUB: { int rval = executionStack.pop(); int lval = executionStack.pop(); executionStack.push(lval - rval); break; } } } return executionStack.pop(); } THIS IS A JVM LIKE INTERPRETER CODE - IT IS SMELLY, AND WHEN IT EVOLVES, IT WILL STINK!
  9. 9. EFFECTIVE APPROACH CODE SMELLS -> REFACTORING THIS IMPROVED SOLUTION USES COMMAND PATTERN class Interpreter { public int interpret(ByteCode[] byteCodes) { Stack<Integer> evalStack = new Stack<Integer>(); for(ByteCode byteCode : byteCodes) { byteCode.exec(evalStack); } Arrays.stream(byteCodes).forEach(byteCode -> byteCode.exec(evalStack)); return evalStack.pop(); } } abstract class ByteCode { abstract void exec(Stack<Integer> execStack); } class ILOAD extends ByteCode { byte val; public ILOAD(byte arg) { val = arg; } public void exec(Stack<Integer> execStack) { execStack.push((int) val); } } class IADD extends ByteCode { public void exec(Stack<Integer> execStack) { execStack.push(execStack.pop() + execStack.pop()); } } class IMUL extends ByteCode { public void exec(Stack<Integer> execStack) { execStack.push(execStack.pop() * execStack.pop()); } } class ISUB extends ByteCode { public void exec(Stack<Integer> execStack) { int rval = execStack.pop(); int lval = execStack.pop(); execStack.push(lval - rval); } } class IDIV extends ByteCode { public void exec(Stack<Integer> execStack) { int rval = execStack.pop(); int lval = execStack.pop(); execStack.push(lval / rval); } }
  10. 10. EFFECTIVE APPROACH DESIGN & ARCH SMELLS -> RESTRUCTURING Step 1: Separate the interface & implementation Step 2: Depend on the interfaces (and not on the implementations) (Reflection: Needs code-level changes)
  11. 11. EFFECTIVE APPROACH DESIGN & ARCH SMELLS -> RESTRUCTURING Step 1: Create a separate package for the interface(s) Step 2: Separate the interface & implementation (Reflection: Needs package-moves - no code level changes)
  12. 12. EFFECTIVE APPROACH DESIGN & ARCH SMELLS -> RESTRUCTURING Step: Separate the interfaces in “maven-classrealm” from the implementation (concrete classes) into to a separate module (“maven-classrealm-api”) (Reflection: NO CODE CHANGE(S) NEEDED!!)
  13. 13. RECOMMENDED APPROACH IF YOU ARE IN THIS SITUATION => DO THIS!
  14. 14. KEY BENEFITS Quickening mental models when working with code The time to understand the structure of a large codebase (especially for teams who have been transferred responsibility of an existing product) is drastically reduced The cost of transfer of maintenance is lesser as KT time reduced as much as 75% Modularization results in reduced change impact The time to make a change (new enhancement/bug fix) is drastically reduced as the time to do impact analysis is drastically reduced The bug density is lower as developers can better modularize and make changes confidently Improved build & subsequent testing time Modularization results in reduced time for compilation & more modular components as part of a modular build system Faster build times (even upto 90%) resulting in quicker turnaround time for developers for changes + quicker unit testing

×