Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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

    View Slide

  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

    View Slide

  3. NAMING STUFF IN JAVA
    Classes, Interfaces, Records, Enums, Methods and Variables, oh my.
    @jeanneboyarsky @omniprof

    View Slide

  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

    View Slide

  5. THERE IS NOTHING IN THE REAL
    WORLD NAMED X, Y, OR Z
    It’s programming and not algebra.
    @jeanneboyarsky @omniprof

    View Slide

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

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  11. CYCLOMATIC COMPLEXITY VERSUS
    K.I.S.S.
    You can make too many decisions.
    @jeanneboyarsky @omniprof

    View Slide

  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

    View Slide

  13. public int weird(int number) {
    var result=0;
    if (number % 2 != 0)
    result = 1;
    else
    result = silly(result);
    return result;
    }
    @jeanneboyarsky @omniprof

    View Slide

  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

    View Slide

  15. DON’T ABUSE STATIC
    Do you have a good reason for making anything static? Probably not.
    @jeanneboyarsky @omniprof

    View Slide

  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.

    View Slide

  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

    View Slide

  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 cows =
    dao.selectCowsByUser(userId);
    387: prepCowsListPage(false, userId, cows);
    388: }
    @jeanneboyarsky @omniprof

    View Slide

  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

    View Slide

  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?

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  24. if (email.indexOf("@") != -1) {
    System.out.println(
    email.substring(
    email.indexOf("@") + 1));
    }
    @jeanneboyarsky @omniprof

    View Slide

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

    View Slide

  26. if (email.contains("@")) {
    var startOfString = "^";
    var anyChars = ".*";
    var at = "@";
    var regex = startOfString
    + anyChars + at;
    System.out.println(
    email.replaceFirst(regex, ""));
    }
    @jeanneboyarsky @omniprof

    View Slide

  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

    View Slide

  28. // Pre stream
    public OptionalInt max(List 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 list) {
    return list.stream().mapToInt(x -> x).max();
    }

    View Slide

  29. THE TIME HAS COME TO SAY GOODBYE
    TO CONCATENATION FOR LONG
    STRINGS. LONG LIVE TEXT BLOCKS!
    All rise JSON strings!.
    @jeanneboyarsky @omniprof

    View Slide

  30. public String getJson(String search) {
    String json = "{" +
    " \"query\": \"%s\"" +
    " \"start\": \"1\"," +
    " \"end\": \"10\"" +
    "}";
    return String.format(json, search);
    }
    @jeanneboyarsky @omniprof

    View Slide

  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

    View Slide

  32. public String getJson(String search) {
    String json = """
    {
    "query": "%s"
    "start": "1"
    "end": "10"
    }""";
    return String.format(json, search);
    }
    @jeanneboyarsky @omniprof

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  37. WE NEED MORE RECORDS!
    Only teenage turtles should be mutable.
    @jeanneboyarsky @omniprof

    View Slide

  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

    View Slide

  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

    View Slide

  40. Automatically get
    • final record
    • private final instance variables
    • public accessors
    • constructor taking both fields
    • equals
    • hashCode
    • toString
    @jeanneboyarsky @omniprof

    View Slide

  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

    View Slide

  42. BOOK GIVEAWAY!
    @jeanneboyarsky @omniprof

    View Slide