$30 off During Our Annual Pro Sale. View Details »

12 Tips for Writing Readable Code

12 Tips for Writing Readable Code

Presented at 2022 JavaOne with Ken Fogel

Jeanne Boyarsky

October 20, 2022
Tweet

More Decks by Jeanne Boyarsky

Other Decks in Programming

Transcript

  1. TWELVE TIPS FOR WRITING MORE READABLE JAVA CODE With Jeanne

    Boyarsky & Ken Fogel Slides available after the presentation at https://speakerdeck.com/boyarsky @jeanneboyarsky @omniprof
  2. Who are we Jeanne Boyarsky • Java Champion • Java

    Author • Developer in NYC • @jeanneboyarsky Ken Fogel §Java Champion §JCP Executive Committee Member §Dawson College Research Scholar in Residence §@omniprof @jeanneboyarsky @omniprof
  3. NAMING STUFF IN JAVA Classes, Interfaces, Records, Enums, Methods and

    Variables, oh my. @jeanneboyarsky @omniprof
  4. It’s a bird, it’s a plane, its § A noun

    § Variables, Enum, Interface, Class, Record § A verb § Methods § All capitals § Constants § Not containing a dollar sign $ § Not an abbreviation, except for maybe WTF § In camel case when a phrase @jeanneboyarsky @omniprof
  5. THERE IS NOTHING IN THE REAL WORLD NAMED X, Y,

    OR Z It’s programming and not algebra. @jeanneboyarsky @omniprof
  6. var f = "jeanne"; var l = "boyarsky"; var s

    = f + l; System.out.println(s.length()); @jeanneboyarsky @omniprof
  7. var firstName = "jeanne"; var lastName = "boyarsky"; var fullName

    = firstName + lastName; System.out.println(fullName.length()); @jeanneboyarsky @omniprof
  8. DON’T BE TOO CLEVER, THE PERSON WHO WILL REPLACE YOU

    ONCE YOU LEAVE MUST UNDERSTAND YOUR CODE. There is no award for code that works but which no one can figure out how. @jeanneboyarsky @omniprof
  9. private BigDecimal loanCalculationTooClever(BigDecimal presentValue, BigDecimal annualPercentageRate, BigDecimal numberOfPayments) throws ArithmeticException

    { return presentValue.multiply(annualPercentageRate.divide( new BigDecimal("12"), MathContext.DECIMAL64). divide(BigDecimal.ONE.subtract(BigDecimal.ONE. add(annualPercentageRate.divide(new BigDecimal("12"), MathContext.DECIMAL64)).pow(-numberOfPayments.intValue(), MathContext.DECIMAL64 )), MathContext.DECIMAL64)).setScale(2, RoundingMode.HALF_EVEN); } @jeanneboyarsky @omniprof n rate rate PV PMT - + - ´ = ) 1 ( 1 Clever, compact, and unintelligible
  10. private BigDecimal loanCalculationStepByStep(BigDecimal presentValue, BigDecimal annualPercentageRate, BigDecimal numberOfPayments) throws ArithmeticException

    { var ratePerPayment = annualPercentageRate.divide( new BigDecimal("12"), MathContext.DECIMAL64); var divisor = BigDecimal.ONE.add(ratePerPayment); divisor = divisor.pow(-numberOfPayments.intValueExact(), MathContext.DECIMAL64); divisor = BigDecimal.ONE.subtract(divisor); var result = ratePerPayment.divide(divisor, MathContext.DECIMAL64); result = presentValue.multiply(result); result = result.setScale(2, RoundingMode.HALF_EVEN); return result; } @jeanneboyarsky @omniprof Expressive and intelligible n rate rate PV PMT - + - ´ = ) 1 ( 1
  11. CYCLOMATIC COMPLEXITY VERSUS K.I.S.S. You can make too many decisions.

    @jeanneboyarsky @omniprof
  12. public int weird(int number) { var result=0; var random =

    new Random(); if (number % 2 == 0) { try { while (random.nextInt(3) % 2 != 0) result++; } catch (ArithmeticException e) { result = 0; } } else { result = 1; } return result; } @jeanneboyarsky @omniprof
  13. public int weird(int number) { var result=0; if (number %

    2 != 0) result = 1; else result = silly(result); return result; } @jeanneboyarsky @omniprof
  14. private int silly(int result) { var random = new Random();

    try { while (random.nextInt(3) % 2 != 0) { result++; } } catch (ArithmeticException e) { result = 0; } return result; } @jeanneboyarsky @omniprof
  15. DON’T ABUSE STATIC Do you have a good reason for

    making anything static? Probably not. @jeanneboyarsky @omniprof
  16. @jeanneboyarsky @omniprof public class BadPassLine { private static int Bankroll;

    private static int defaultBank; private static int bet; private static int win = 0; private static int lost = 0; private static int point; public static void main(String[] args){ . . . } public static int gamebegin() { . . . } public static void gamestart(){ . . . } public static int rollingDice(){ . . . } } After 3 Java courses, this is what a student submitted for a PassLine dice game as a warm-up assignment in their 4th Java course with me. Impress me, I said. This student depressed me.
  17. IF IT DON’T FIT THE SCREEN, THEN MAYBE YOUR METHOD

    IS TOO LONG If it doesn’t fit on a screen, then it's too long. No turning the screen to portrait mode or use 6- point text. @jeanneboyarsky @omniprof
  18. 142: int userId = request.getIntParameter("user_id"); 143: int loggedInUserId = SessionFacade.getUserSession().getUserId();

    144: context.put("loggedInUserId", loggedInUserId); 145: context.put("isCurrentUser", userId == loggedInUserId); ... 12: 383: if (canListAllCows() || 384: (canGrantCows() && (userId == loggedInUserId))) { 385: CowsDao dao = DataAccessDriver.newCowsDao(); 386: List<Cow> cows = dao.selectCowsByUser(userId); 387: prepCowsListPage(false, userId, cows); 388: } @jeanneboyarsky @omniprof
  19. THE MAGIC NUMBER FOR A METHOD IS 1, THE NUMBER

    OF TASKS THE METHOD CARRIES OUT You may have many responsibilities in your day-to-day life, but your methods should only have a Single Responsibility. @jeanneboyarsky @omniprof
  20. private static void playGame() { System.out.println(); int bet = 0;

    while (true) { System.out.println("\nYou have $" + currentCash); System.out.println("Insert a bet amount:"); if (reader.hasNextInt()) { bet = reader.nextInt(); if (!(checkIfInvalidBet(bet))) { break; } } else { System.out.println("You can only put whole numbers!"); } } Let’s play How Many Tasks Can You Find In This One Method?
  21. if (bet != 0) { boolean victory; int point =

    0; int total; while (true) { total = roll2Dice(); if (point == 0) { if (total == 7 || total == 11) { victory = true; break; } if (total == 2 || total == 3 || total == 12) { victory = false; break; } point = total; System.out.println("\nThe point is now " +point + "\n"); @jeanneboyarsky @omniprof
  22. } else { if (total == 7) { victory =

    false; break; } if (total == point) { victory = true; break; } } } if (victory) { currentCash += bet; System.out.println(“You have won this round! \n"); } else { currentCash -= bet; System.out.println("Sorry, you lost this round! \n"); } } } @jeanneboyarsky @omniprof
  23. THE STRING CLASS IS FULL OF POORLY AND BADLY NAMED

    METHODS. Use methods from a string whose name your boss could even understand. @jeanneboyarsky @omniprof
  24. if (email.indexOf("@") != -1) { System.out.println( email.substring( email.indexOf("@") + 1));

    } @jeanneboyarsky @omniprof
  25. if (email.contains("@")) { System.out.println( email.replaceFirst("^.*@", "")); } @jeanneboyarsky @omniprof

  26. if (email.contains("@")) { var startOfString = "^"; var anyChars =

    ".*"; var at = "@"; var regex = startOfString + anyChars + at; System.out.println( email.replaceFirst(regex, "")); } @jeanneboyarsky @omniprof
  27. ROW, ROW, ROW YOUR CODE, GENTLY DOWN THE STREAM Collections

    and for loops should be like water and oil, don’t mix them. @jeanneboyarsky @omniprof
  28. // Pre stream public OptionalInt max(List<Integer> list) { if (list.isEmpty())

    { return OptionalInt.empty(); } Collections.sort(list); int max = list.get(list.size()-1); return(OptionalInt.of(max)); } @jeanneboyarsky @omniprof // Post stream public OptionalInt maxStream(List<Integer> list) { return list.stream().mapToInt(x -> x).max(); }
  29. THE TIME HAS COME TO SAY GOODBYE TO CONCATENATION FOR

    LONG STRINGS. LONG LIVE TEXT BLOCKS! All rise JSON strings!. @jeanneboyarsky @omniprof
  30. public String getJson(String search) { String json = "{" +

    " \"query\": \"%s\"" + " \"start\": \"1\"," + " \"end\": \"10\"" + "}"; return String.format(json, search); } @jeanneboyarsky @omniprof
  31. public String getJson(String search) { Path path = Path.of( ""src/main/resources/query.json");

    String json = null; try { json = Files.readString(path); } catch (IOException e) { throw new UncheckedIOException(e); } return String.format(json, search); } @jeanneboyarsky @omniprof
  32. public String getJson(String search) { String json = """ {

    "query": "%s" "start": "1" "end": "10" }"""; return String.format(json, search); } @jeanneboyarsky @omniprof
  33. THE TRADITIONAL SWITCH IS FROM THE 1950S. TIME TO CODE

    LIKE ITS 2022 Switch expression, Switch statement, Switch pattern matching. It is time to finally say goodbye to fall thru in the absence of a break. @jeanneboyarsky @omniprof
  34. double value = 0; switch (point) { case NORTH: value

    = 12.12; break; case SOUTH: value = 14.14; break; case EAST: value = 16.16; break; case WEST: value = 18.18; break; } The 1950s just called and they want their switch back. @jeanneboyarsky @omniprof
  35. // switch statement switch (point) { case NORTH -> doNorth();

    case SOUTH -> doSouth(); case EAST -> { doEast(); doEastern(); } case WEST -> doWest(); default -> doLost(); }; // switch expression double value = switch (point) { case NORTH -> 12.12; case SOUTH -> 14.14; case EAST -> 16.16; case WEST -> 18.18; default -> 0.0; }; Now’s the time to say goodbye to break. @jeanneboyarsky @omniprof
  36. Object value = 4; switch (value) { case null ->

    System.out.println("null"); case String s -> System.out.println("String"); case Integer i when i > 1 && i < 6 -> System.out.println("Integer"); default -> System.out.println("Something else"); } The future is the Pattern Matching Switch! @jeanneboyarsky @omniprof
  37. WE NEED MORE RECORDS! Only teenage turtles should be mutable.

    @jeanneboyarsky @omniprof
  38. public class Book { private String title; private String numPages;

    public Book(String title, String numPages) { super(); this.title = title; this.numPages = numPages; } public String getTitle() { return title; } public String getNumPages() { return numPages; } @jeanneboyarsky @omniprof
  39. public record Book(String title, String numPages) { } Book book

    = new Book( "Breaking and entering", 289); System.out.println(book.title()); System.out.println(book.toString()); @jeanneboyarsky @omniprof
  40. Automatically get • final record • private final instance variables

    • public accessors • constructor taking both fields • equals • hashCode • toString @jeanneboyarsky @omniprof
  41. FOR MORE This deck – on Speakerdeck shortly New Java

    features - https://speakerdeck.com/boyarsky/2022-java17-refactoring New Java features - https://speakerdeck.com/boyarsky/2022-devnexus-java12-17 @jeanneboyarsky @omniprof
  42. BOOK GIVEAWAY! @jeanneboyarsky @omniprof