Raft Project 2 Review/Discussion

Lecture Notes for CS 190
Winter 2018
John Ousterhout

Together or Apart?

  • Tendency is still towards shallow/small classes (too much "apart")
  • Example TA1 (separate class with methods just to log messages, each method only invoked once)
  • Separate class NetworkException generated only by NetworkManager: make exception a nested class
  • Example TA2: keep related code together within a method (do the whole job in one place)
  • Different classes for different return results from client requests (Example TA3)
  • Inheritance hierarchy for messages: factor out check for stale term?
  • Should be apart: shell-command state machine built into Raft server (make Raft server more general-purpose)
  • Persistent log module taking on other responsibilities:
    • Applying committed entries
    • Persistent log class makes decisions about truncation, entry equality (Example TA4)
    • Separate structures for committed, uncommitted entries
    • Best approach: keep it simple, general (just append and truncate)

Making Code Obvious

  • Examples that are not obvious:
    • Code looks unsafe, but it's actually safe (Example O1)
    • Doesn't conform to normal usage: getters with no "get" (commitIndex() instead of getCommitIndex())
    • this.wait(), this.notify(): no place to put documentation
    • ByteBuffer: internal state isn't obvious (especially when reused in different places)
    • Poor indentation (Examples O2, O3)
    • Program appears to end without doing anything (Example O4)
      • Must document!
    • Command loop hidden among lambdas (Example O5)
    • Declare as one type, allocate as another (Example O6)
    • Assign "ids" to clients (like server ids) for sending responses
    • Long lambdas (Example O7)
    • Callbacks: flow of control is no longer obvious
    • Depending on non-obvious state information, double-purpose a method (Example O8)
    • Send a request on one socket, get response on another
      • Clients must establish a listen port to receive responses
  • Try to conform to reader expectations and conventions, document when you don't.
  • Names: biggest problem is they don't reflect what's most important
    • Heartbeats: no longer just heartbeats (Example N1); heartbeat is now a special case
    • Examples N2-N10 (think about abstraction: what's the key idea?)
  • Documentation issues (see examples)

Other Issues

  • Performance:
    • Don't spend a lot of time at micro-optimizing
    • Get a feel for big issues, focus on them
      • Opening sockets
      • One thread per open socket (Google: 100K open sockets/server!)
      • Reading entire log into memory
      • Copying entire log to do insertion or removal
      • Cache misses