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

Re-architecture

 Re-architecture

Ragunath Jawahar

February 14, 2020
Tweet

More Decks by Ragunath Jawahar

Other Decks in Programming

Transcript

  1. ? • Started out as a Minimum Viable Product •

    Workarounds and fighting the framework • Overcome limitations • Accidental complexity (RxJava) • Open-Source (funded by a non-profit) • Painful tests (1:8)
  2. System Boundaries • Network • File System / Database /

    Persistence • Hardware • UI • 3rd Party Integrations
  3. + -

  4. + -

  5. Setup Tear down Test 1 Test 2 Test 3 Test

    4 LoginControllerTest.kt Setup Tear down Test 1 Test 2 Test 3 Test 4 LoginControllerTest.kt
  6. Different package Setup Tear down Test 1 Test 2 Test

    3 Test 4 LoginControllerTest.kt Setup Tear down Test 1 Test 2 Test 3 Test 4 LoginControllerTest.kt
  7. Setup Tear down Test 1 Test 2 Test 3 Test

    4 LoginControllerTest.kt Setup Tear down Test 1 Test 2 Test 3 Test 4 LoginControllerTest.kt
  8. Setup Tear down Test 1 Test 2 Test 3 Test

    4 LoginControllerTest.kt Setup Tear down Test 1 Test 2 Test 3 Test 4 LoginControllerTest.kt
  9. Setup Tear down Test 1 Test 2 Test 3 Test

    4 LoginControllerTest.kt Setup Tear down Test 1 Test 2 Test 3 Test 4 LoginControllerTest.kt
  10. Setup Tear down Test 1 Test 2 Test 3 Test

    4 LoginControllerTest.kt Setup Tear down Test 1 Test 2 Test 3 Test 4 LoginControllerTest.kt
  11. Setup Tear down Test 1 Test 2 Test 3 Test

    4 LoginControllerTest.kt Setup Tear down Test 1 Test 2 Test 3 Test 4 LoginControllerTest.kt
  12. Setup Tear down Test 1 Test 2 Test 3 Test

    4 LoginControllerTest.kt Setup Tear down Test 1 Test 2 Test 3 Test 4 LoginControllerTest.kt
  13. Setup Tear down Test 1 Test 2 Test 3 Test

    4 LoginControllerTest.kt Setup Tear down Test 1 Test 2 Test 3 Test 4 LoginControllerTest.kt
  14. Setup Tear down Test 1 Test 2 Test 3 Test

    4 LoginControllerTest.kt Setup Tear down Test 1 Test 2 Test 3 Test 4 LoginControllerTest.kt
  15. Setup Tear down Test 1 Test 2 Test 3 Test

    4 LoginControllerTest.kt Setup Tear down Test 1 Test 2 Test 3 Test 4 LoginControllerTest.kt
  16. Pros • Provides a fallback if things go wrong •

    Little refactoring experience • Allows complementing asymmetric/low-confidence tests with manual testing • “Works” even if you don’t have enough tests
  17. Cons • All or nothing • Hard to accommodate incoming

    feature requests • Duplicate tests and features • Reviewing pull requests can be difficult • Easy to miss functionality that is not covered by tests • Cleaning up old code after feature stabilisation
  18. + -

  19. + -

  20. + -

  21. + -

  22. + -

  23. + -

  24. + -

  25. + -

  26. Tear down Test 1 Test 2 Test 3 Test 4

    LoginControllerTest.kt Setup
  27. Tear down Test 1 Test 2 Test 3 Test 4

    LoginControllerTest.kt Setup
  28. Tear down Test 1 Test 2 Test 3 Test 4

    LoginControllerTest.kt Setup
  29. Tear down Test 1 Test 2 Test 3 Test 4

    LoginControllerTest.kt Setup
  30. @Test !// TODO: Migrate to Mobius fun `when save is

    clicked then user input should be validated`() { whenever(patientRepository.ongoingEntry()).thenReturn(Single.just(OngoingNewPatientEntry())) with(uiEvents) { onNext(FullNameChanged("")) onNext(PhoneNumberChanged("")) onNext(DateOfBirthChanged("")) onNext(AgeChanged("")) onNext(GenderChanged(None)) onNext(ColonyOrVillageChanged("")) onNext(DistrictChanged("")) onNext(StateChanged("")) onNext(SaveClicked) } with(uiEvents) { onNext(DateOfBirthChanged("33/33/3333")) onNext(SaveClicked) } with(uiEvents) { onNext(AgeChanged(" ")) onNext(DateOfBirthChanged("")) onNext(SaveClicked) } with(uiEvents) { onNext(DateOfBirthChanged("16/07/2018")) onNext(SaveClicked) } with(uiEvents) { onNext(PhoneNumberChanged("1234")) onNext(SaveClicked) } with(uiEvents) { onNext(PhoneNumberChanged("1234567890987654")) onNext(SaveClicked) } verify(ui, atLeastOnce()).showEmptyFullNameError(true) verify(ui, atLeastOnce()).showEmptyDateOfBirthAndAgeError(true) verify(ui, atLeastOnce()).showInvalidDateOfBirthError(true) verify(ui, atLeastOnce()).showMissingGenderError(true) verify(ui, atLeastOnce()).showEmptyColonyOrVillageError(true) verify(ui, atLeastOnce()).showEmptyDistrictError(true) verify(ui, atLeastOnce()).showEmptyStateError(true) verify(ui, atLeastOnce()).showLengthTooShortPhoneNumberError(true) verify(ui, atLeastOnce()).showLengthTooLongPhoneNumberError(true) }
  31. @Test !// TODO: Migrate to Mobius fun `when save is

    clicked then user input should be validated`() { whenever(patientRepository.ongoingEntry()).thenReturn(Single.just(OngoingNewPatientEntry())) with(uiEvents) { onNext(FullNameChanged("")) onNext(PhoneNumberChanged("")) onNext(DateOfBirthChanged("")) onNext(AgeChanged("")) onNext(GenderChanged(None)) onNext(ColonyOrVillageChanged("")) onNext(DistrictChanged("")) onNext(StateChanged("")) onNext(SaveClicked) } with(uiEvents) { onNext(DateOfBirthChanged("33/33/3333")) onNext(SaveClicked) } with(uiEvents) { onNext(AgeChanged(" ")) onNext(DateOfBirthChanged("")) onNext(SaveClicked) } with(uiEvents) { onNext(DateOfBirthChanged("16/07/2018")) onNext(SaveClicked) } with(uiEvents) { onNext(PhoneNumberChanged("1234")) onNext(SaveClicked) } with(uiEvents) { onNext(PhoneNumberChanged("1234567890987654")) onNext(SaveClicked) } verify(ui, atLeastOnce()).showEmptyFullNameError(true) verify(ui, atLeastOnce()).showEmptyDateOfBirthAndAgeError(true) verify(ui, atLeastOnce()).showInvalidDateOfBirthError(true) verify(ui, atLeastOnce()).showMissingGenderError(true) verify(ui, atLeastOnce()).showEmptyColonyOrVillageError(true) verify(ui, atLeastOnce()).showEmptyDistrictError(true) verify(ui, atLeastOnce()).showEmptyStateError(true) verify(ui, atLeastOnce()).showLengthTooShortPhoneNumberError(true) verify(ui, atLeastOnce()).showLengthTooLongPhoneNumberError(true) }
  32. @Test !// TODO: Migrate to Mobius fun `when save is

    clicked then user input should be validated`() { whenever(patientRepository.ongoingEntry()).thenReturn(Single.just(OngoingNewPatientEntry())) with(uiEvents) { onNext(FullNameChanged("")) onNext(PhoneNumberChanged("")) onNext(DateOfBirthChanged("")) onNext(AgeChanged("")) onNext(GenderChanged(None)) onNext(ColonyOrVillageChanged("")) onNext(DistrictChanged("")) onNext(StateChanged("")) onNext(SaveClicked) } with(uiEvents) { onNext(DateOfBirthChanged("33/33/3333")) onNext(SaveClicked) } with(uiEvents) { onNext(AgeChanged(" ")) onNext(DateOfBirthChanged("")) onNext(SaveClicked) } with(uiEvents) { onNext(DateOfBirthChanged("16/07/2018")) onNext(SaveClicked) } with(uiEvents) { onNext(PhoneNumberChanged("1234")) onNext(SaveClicked) } with(uiEvents) { onNext(PhoneNumberChanged("1234567890987654")) onNext(SaveClicked) } verify(ui, atLeastOnce()).showEmptyFullNameError(true) verify(ui, atLeastOnce()).showEmptyDateOfBirthAndAgeError(true) verify(ui, atLeastOnce()).showInvalidDateOfBirthError(true) verify(ui, atLeastOnce()).showMissingGenderError(true) verify(ui, atLeastOnce()).showEmptyColonyOrVillageError(true) verify(ui, atLeastOnce()).showEmptyDistrictError(true) verify(ui, atLeastOnce()).showEmptyStateError(true) verify(ui, atLeastOnce()).showLengthTooShortPhoneNumberError(true) verify(ui, atLeastOnce()).showLengthTooLongPhoneNumberError(true) }
  33. @Test !// TODO: Migrate to Mobius fun `when save is

    clicked then user input should be validated`() { whenever(patientRepository.ongoingEntry()).thenReturn(Single.just(OngoingNewPatientEntry())) with(uiEvents) { onNext(FullNameChanged("")) onNext(PhoneNumberChanged("")) onNext(DateOfBirthChanged("")) onNext(AgeChanged("")) onNext(GenderChanged(None)) onNext(ColonyOrVillageChanged("")) onNext(DistrictChanged("")) onNext(StateChanged("")) onNext(SaveClicked) } with(uiEvents) { onNext(DateOfBirthChanged("33/33/3333")) onNext(SaveClicked) } with(uiEvents) { onNext(AgeChanged(" ")) onNext(DateOfBirthChanged("")) onNext(SaveClicked) } with(uiEvents) { onNext(DateOfBirthChanged("16/07/2018")) onNext(SaveClicked) } with(uiEvents) { onNext(PhoneNumberChanged("1234")) onNext(SaveClicked) } with(uiEvents) { onNext(PhoneNumberChanged("1234567890987654")) onNext(SaveClicked) } }
  34. Move functionality to the new architecture and the test would

    fail indicating a successful port. Next, remove the functionality from the new architecture, now the current test & all other tests should pass.
  35. Pros • Pretty low risk, micro changes to the system

    • System is green and ready to ship all the time • Easy for the reviewer to understand system evolution • Fairly easy to accommodate incoming feature requests • Untested code attracts attention • No duplication
  36. Cons • Requires familiarity around testing and refactoring • Requires

    fast feedback cycles • Requires experimentation • Has the highest pay-off when similar patterns are replicated • May inherit some design decisions from the older architecture