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

Defensive Programming x Fintech

Defensive Programming x Fintech

What is defensive programming? How to master this discipline. common mistakes and tips for better code

Merab Tato Kutalia

September 08, 2019
Tweet

More Decks by Merab Tato Kutalia

Other Decks in Programming

Transcript

  1. Safe zones - Protect code from invalid data coming from

    “outside” - Everything outside of the boundary is dangerous
  2. Safe zones - Protect code from invalid data coming from

    “outside” - Everything outside of the boundary is dangerous - Double check for limits and bounds
  3. Safe zones - Protect code from invalid data coming from

    “outside” - Everything outside of the boundary is dangerous - Double check for limits and bounds - Do whitelists, not blacklists
  4. Handling - Defensive Programming is NOT about swallowing errors or

    hiding bugs - Return an error and stop (fail fast)
  5. Handling - Defensive Programming is NOT about swallowing errors or

    hiding bugs - Return an error and stop (fail fast) - Return a neutral value
  6. Handling - Defensive Programming is NOT about swallowing errors or

    hiding bugs - Return an error and stop (fail fast) - Return a neutral value - Don’t be afraid to fail!!!
  7. Code doesn’t work as advertised - Don’t assume that a

    function call outside of code will work as advertised.
  8. Code doesn’t work as advertised - Don’t assume that a

    function call outside of code will work as advertised. - Always wrap 3rd party libraries with your own gateways.
  9. Code doesn’t work as advertised - Don’t assume that a

    function call outside of code will work as advertised. - Always wrap 3rd party libraries with your own gateways. - ALWAYS!
  10. fun register(facebookAccessToken : String) { val response = facebookSdkClient.getUserByToken(facebookAccessToken) if

    (response.email.isNullOrEmpty()) throw IllegalArgumentException("Invalid response from Facebook") // Register the user }
  11. Logging - Add logging and tracing to help explain what’s

    going on at run-time, especially if you run into a problem.
  12. Logging - Add logging and tracing to help explain what’s

    going on at run-time, especially if you run into a problem. - Use 3rd party systems to analyze logs and maintain the same level
  13. authorizeUserWithUsernameAndPassword(user, pass) .subscribe({ when { it.errorCode != 0 -> {

    // API error } else -> { getUserInfo(it.accessToken) } } }, { // Any other error. Throwable })
  14. authorizeUserWithUsernameAndPassword(user, pass) .subscribe({ result: ApiResponse<LoginResponse> -> when { result.errorCode !=

    0 -> { // API error } else -> { getUserInfo(result.accessToken) } } }, { it: Throwable // Any other error. Throwable })
  15. Misc - Never ever wait forever on an external call,

    especially a remote call. - Forever can be a long time when something goes wrong. Use time-out/retry logic
  16. Misc - Never ever wait forever on an external call,

    especially a remote call. - Forever can be a long time when something goes wrong. Use time-out/retry logic. - When just checking null for an immutable variable, don’t use LET.
  17. // NOT RECOMMENDED fun process(str: String?) { str?.let { /*Do

    something*/ } } // Decompiled JAVA public final void process(@Nullable String str) { if (str != null) { boolean var4 = false; /*Do something*/ } }
  18. // RECOMMENDED fun process(str: String?) { if (str != null)

    // Do Something } // Decompiled JAVA public final void process(@Nullable String str) { if (str != null) /*Do something*/ }
  19. “A public method is like a child: once you've written

    it, you are going to maintain it for the rest of its life!” Stefan Priebsch
  20. - Defensive code is code – all code has bugs

    - Understanding what conditions to check for and how much defensive coding is needed takes experience Misc
  21. - Well you like doing extra work for no reason,

    congratulations! ⭐ Frameworks
  22. - Well you like doing extra work for no reason,

    congratulations! ⭐ - Well tested, trusted by thousands of developers and stable Frameworks
  23. - Well you like doing extra work for no reason,

    congratulations! ⭐ - Well tested, trusted by thousands of developers and stable - That’s what is used to call intelligent code reuse Frameworks
  24. fun doSomething(count: Int){ if (count < 1 || count >

    100) throw IllegalArgumentException("Invalid count") /* Do something */ } fun doSomethingElse(count: Int) { if (count < 1 || count > 100) throw IllegalArgumentException("Invalid count") /* Do something else */ }
  25. fun doSomething(count: Count) { /* Do something */ } fun

    doSomethingElse(count: Count) { /* Do something else */ } class Count(var value: Int) { init { if (value < 1 || value > 100) throw IllegalArgumentException("Invalid count") } }
  26. - Passing empty objects instead of crash - Traverse nested

    object/array to check the key Overly Defensive Code
  27. // DON'T! @Throws(Exception::class) fun doNotSpecifyException() { doSomething() } // DO

    THIS! @Throws(NumberFormatException::class, IllegalArgumentException::class) fun doSomething() { // do something }
  28. val result = 0.1 + 0.2 - 0.3 println("0.1 +

    0.2 - 0.3=$result") => 0.1 + 0.2 - 0.3 = 5.551115123125783E-17
  29. val result = 0.1 + 0.2 - 0.3 val resultRounded

    = BigDecimal(result).setScale(2, BigDecimal.ROUND_HALF_UP) println("0.1 + 0.2 - 0.3=$resultRounded") => 0.1 + 0.2 - 0.3 = 0.00
  30. - BigDecimal(String) constructor should always be preferred over BigDecimal(Double) because

    using BigDecimal(double)is unpredictable due to the inability of the double to represent 0.1 as exact 0.1. - If double must be used for initializing a BigDecimal, use BigDecimal.valueOf(double), which converts the Double value to String using Double.toString(double) method - Rounding mode should be provided while setting the scale - StripTrailingZeros chops off all the trailing zeros - toString() may use scientific notation but, toPlainString() will never return exponentiation in its result - BigDecimal