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
Tweet

Other Decks in Programming

Transcript

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

    incidentally for machines to execute.” - Harold Abelson, Structure and Interpretation of Computer Programs
  2. 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?
  3. 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
  4. 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
  5. Responsibilities • This code has four main responsibilities: • UI

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

    • Involved test setup • Two conditionals away from pain! • Employ design to increase intent
  7. 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
  8. 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)
  9. Testing the API • Use integration tests • Only test

    against API.login responsibilities • Need to mock web service response • Small, focused classes = simpler test suites
  10. 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
  11. Benefits • Introduced a domain concept • Abstracted: • ACSimpleKeychain

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

    Check against ACSimpleKeychain directly • Narrow interfaces ease testing
  13. 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...
  14. 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
  15. 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
  16. 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
  17. 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
  18. 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?
  19. 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?
  20. 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
  21. 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
  22. 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
  23. 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
  24. 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