Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Salesforce Developers profile imageAdrian Ruvalcaba
Adrian Ruvalcaba forSalesforce Developers

Posted on

     

Swift and Pure Functions

I worked on the Salesforce Events iOS team from 2016 to 2020. During this time, we used functional reactive principles to improve our codebase. The benefits that stood out to me the most were:

  • Crash rate dropped from one crash in every 100 launches to one in every 40 thousand.
  • Bug rate dropped and bug resolution times decreased.
  • Increased development velocity.

What are Pure Functions?

  1. A function is pure if it always returns the same value for a given set of inputs.
  2. A pure function is free of side effects.

Side effects are: reads or writes to state outside of the function's set of input params.

Here's a contrived example of an impure function.

//not pure//has side effects//doesn't always return same values for inputstruct Adder {    var sum: Int = 0    var left: Int = 0    var right: Int = 0    func add () {        self.sum = self.left + self.right    }}
Enter fullscreen modeExit fullscreen mode

And a pure example which meets our two criteria above: returns same output for given input; and is free of side effects.

func pureAdd (left: Int, right: Int) → Int {    return left + right}
Enter fullscreen modeExit fullscreen mode

Cost Per Test

Writing tests that assert that a given set of inputs produce the correct output is as straightforward as a test can get. No mocking or state initialization are required.

Given the example functions above, testing pureAdd can be done compactly.

assertEqual(pureAdd(1, 99), 100)assertEqual(pureAdd(1, 0), 1)assertEqual(pureAdd(2, 2), 4)
Enter fullscreen modeExit fullscreen mode

While the non pure example requires more setup per assertion.

let adder = Adder()adder.left = 1adder.right = 0adder.add()assertEqual(adder.sum, 1)
Enter fullscreen modeExit fullscreen mode

In general, the more side effects a function has, the higher the cost per test

Test Effectiveness of Pure functions

The goal of unit tests should be to prove that the function under test produces the correct output for the input space.

For the function isTrue(input: Bool) -> Bool the input space has two possibilities: true and false. So, to prove correctness we'll need two assertions:

assertEqual(isTrue(true), true)assertEqual(isTrue(false), false)
Enter fullscreen modeExit fullscreen mode

If we add a second Bool param, we double the input space and double the number of assertions needed to prove correctness:

assertEqual(areTrue(true, true), true)assertEqual(areTrue(true, false), false)assertEqual(areTrue(false, false), false)assertEqual(areTrue(false, true), false)
Enter fullscreen modeExit fullscreen mode

For pure functions, the number of assertions needed to prove correctness is a product of the input space. This means that limiting the input space helps lower testing effort for proving correct output for all input.

To lower the input space we should favor using input parameters with a discrete number of possible values. For example, consider using enum vs String when possible because an enum has a finite set of values while a String has an unbounded number of possible values.

Test Effectiveness of Non-Pure functions

For non-pure functions proving correct output for the input space is considerably more challenging for a few reasons:

  1. The input into a non-pure function may include object and global state.
  2. This expanded input space increases the number of assertions needed to prove correctness.
  3. As seen above, the scaffolding cost per test is often higher for these functions.
  4. Shared state can change externally before the function completes.

Given the increased effort required, proving correctness may become intractable for these functions and we instead target code coverage.

While coverage is a good metric to help make sure functions have some level of unit testing, I don't believe having code coverage is equivalent to ensuring correctness of the function.

Closing Thoughts

Thanks for reading. This post was focused on how pure functions can benefit us with regard to testing. However, there are many more benefits to be gained from functional programming and Swift like concurrency, reactive and composition that are worth exploring.

Top comments(0)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

Tools to build mobile and enterprise apps in the cloud

Trending onDEV CommunityHot

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp