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?

7e01d0a8ef8d90e1c5195f27b34ae999?s=128

Matt Green

March 28, 2013
Tweet

Other Decks in Programming

Transcript

  1. Elevate Your Intent Matt Green

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

    mattgreenrocks@gmail.com
  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?