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

Elevate Your Intent

Elevate Your Intent

How do we convey the purpose of our RubyMotion code?


Matt Green

March 28, 2013

Other Decks in Programming


  1. Elevate Your Intent Matt Green

  2. About Me • Github: https://github.com/mattgreen • Twitter: @mattgreenrocks • Email:

  3. “Programs must be written for people to read, and only

    incidentally for machines to execute.” - Harold Abelson, Structure and Interpretation of Computer Programs
  4. Why Intent? • Code is a sequence of instructions •

    But it can’t tell us what it’s doing, or why • How can we convey our intent?
  5. What Are We Doing? • We are problem solvers first

    and foremost • Can we change how we think about problem solving? • Code is only as good as our understanding • These are skills to build our careers on
  6. Requirements • Story: User Logs In • User enters username

    and password • Credentials sent to web service • If credentials are valid, store username + unique token in Keychain • Otherwise, display an error message
  7. None
  8. None
  9. Responsibilities • This code has four main responsibilities: • UI

    handling • HTTP request sending • HTTP response parsing • Keychain storage • One problem: this is a simple requirement!
  10. Muddled intent • Multiple responsibilities • Several levels of abstraction

    • Involved test setup • Two conditionals away from pain! • Employ design to increase intent
  11. Decoupling the API • Extract the web service to a

    new API class • API class will only be responsible for: • Sending requests • Parsing responses • Good class and method names further increase intent
  12. None
  13. None
  14. What Did We Gain? • Named a domain concept: the

    web service • Encapsulated the responsibility of: • Communicating with the API • Interpreting the response • Isolated the dependency (BubbleWrap)
  15. Testing the API • Use integration tests • Only test

    against API.login responsibilities • Need to mock web service response • Small, focused classes = simpler test suites
  16. Decoupling Keychain • Extract Keychain access out to a new

    class • Responsible for persisting username and token • Thus, we name it UserRegistration, rather than something involving Keychain
  17. None
  18. None
  19. Benefits • Introduced a domain concept • Abstracted: • ACSimpleKeychain

    details (service, id) • Error-checking style • Dependency itself (ACSimpleKeychain)
  20. Testing UserRegistration • Similar to API: • Call UserRegistration.store •

    Check against ACSimpleKeychain directly • Narrow interfaces ease testing
  21. Generalizing... • API and UserRegistration are boundaries: they allow us

    to interact with the world • Boundaries typically fall into a few categories, such as persistence, networking, and hardware sensors • However, they are dependencies...
  22. Dependencies • Dependencies may: • Have, or introduce bugs •

    Change their API across versions • Have a clunky, error-prone API • In short: they increase risk! • So, we isolate them
  23. Why isolate? • Dependency-induced complexity obscures actual domain complexity •

    To prevent this, we use layers: • Domain: “what does my app do?” • Technical: “how does it accomplish it?” • Layers are required for complex systems
  24. Dependencies And Evil “Evil things exist. You're going to have

    mutable state; you're going to use libraries that don't fail loudly; libraries are sometimes going to force global mutable state on you…I want that stuff on one side so that I can always keep my eye on it...because occasionally those evil forces inhabit a body and make it wear hockey masks and swing sharp objects at me and, damn it, I'm a programmer; I can't be fighting off global- mutable-state-possessed homicidal monsters.” - Gary Bernhardt
  25. Managing Boundaries • Name it after a domain concept •

    Write a simple API tailored to your app • Check for errors, and fail loudly • Rely on integration tests to verify/upgrade dependency
  26. None
  27. Pushing Onward • The controller still knows: • That we

    call the API • To store the credentials if the login succeeded • How do we test that logic? • What do we do this logic is complex?
  28. The edge of MVC • Extract interaction to a service

    object, such as LoginUser that is UI agnostic • Encapsulate interaction between API and UserRegistration, simplifying our view controller • However, the API is async. How to cope?
  29. Desired Code...

  30. Enter Elevate • Elevate is a global task queue designed

    for service objects • Robust: powered by NSOperationQueue • Start/stop operations from view controller • Simplifies async I/O in service objects
  31. Elevate Usage • Elevate calls execute on any object passed

    to the view controller’s async method • The async method returns an NSOperation to cancel the operation • Only one operation may run at a time
  32. None
  33. Elevate Simplifies IO • iOS web service requests are async

    • Elevate’s HTTP client: • Feels like a blocking HTTP client • Allows cancellation via NSOperation • Increased readability = increased intent
  34. None
  35. Conclusion • Maximizing intent requires practice • ‘Average’ code can

    be improved by simply extracting concerns out • Boundaries are necessary, but incur risk • Elevate helps you create a service layer
  36. Further Study • Clean Architecture: http://blog.8thlight.com/uncle-bob/ 2012/08/13/the-clean-architecture.html • Destroy All

    Software: https://www.destroyallsoftware.com/ • Growing Object Oriented Software Guided By Tests, by Steve Freeman & Nat Pryce
  37. Questions?