Skip to content

Instantly share code, notes, and snippets.

@chenharryhua
Created November 4, 2016 03:48
Show Gist options
  • Save chenharryhua/de72c777f85766d6e9ee105697f33c94 to your computer and use it in GitHub Desktop.
Save chenharryhua/de72c777f85766d6e9ee105697f33c94 to your computer and use it in GitHub Desktop.
code inspection

Yesterday, I reviewed my colleague's code which implemented a few tie-break rules to our search api. the code roughly looks like follow(to save space, I removed a few rules). for each tie-break method, it calls direct to the next rule if the condition is not satisfied.

  private def tieBreakerSortWithinESRelevanceGroups(decoratedSearchRequest:DecoratedSearchRequest, leftListing:ListingInfo, rightListing:ListingInfo):Boolean = {
    def tieBreakOnRoiScore(decoratedSearchRequest:DecoratedSearchRequest, leftListing:ListingInfo, rightListing:ListingInfo):Boolean = {
      (decoratedSearchRequest.intent, leftListing.roiScore, rightListing.roiScore) match {
        case (Some(Intent.TYPE), leftRoi, rightRoi) if (leftRoi == rightRoi) => tieBreakOnSource(decoratedSearchRequest, leftListing, rightListing)
        case (Some(Intent.TYPE), leftRoi, rightRoi) => leftRoi < rightRoi
        case _ => tieBreakOnSource(decoratedSearchRequest, leftListing, rightListing)
      }
    }
    ... //more rules defined.
    ...
    def tieBreakOnListingId(decoratedSearchRequest:DecoratedSearchRequest, leftListing:ListingInfo, rightListing:ListingInfo):Boolean = {
      leftListing.id < rightListing.id
    }
    if (leftListing.score == rightListing.score) 
      tieBreakOnRoiScore(decoratedSearchRequest, leftListing, rightListing)
    else 
      rightListing.score < leftListing.score   // relevance score in descending order
  }

The code is implemented correctly since it meets the business requirement. However from programmer's perspective, I think it could be improved further. But, first of all, what's the problem of the code?

  • unit-testabilites: because each rule is encoded inside a big method, unit testing individual rules become unfeasible
  • requirement change: if customer want to change the sequence of application of the rules, a lot of code changes occurs therefore
  • sharability: those rules are too local to be shared.(maybe there is no requirement for sharing those rules.)

The remediation:

  • instead of encapsulating all rules in a big block, we can implement it individually and change the return type to Option[Boolean]: for instance: def tieBreakOnListingId(req:DecoratedSearchRequest, l:ListingInfo, r:ListingInfo):Option[Boolean] inside the method, it will return Some[Boolean] when the rule is applied and None if not.
  • compose the rules via scalaz <+> operator to build up a bigger rule: tieBreakOnListingId(req, l, r) <+> tieBreakOnROI(req, l, r) <+> tieBreakOnSomethingelse(req, l, r)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment