FinTech Project - Part 2

In our latest blog post, we talked about our latest project, a fintech product we built for a US company based in California. In that blog post, we described the main challenges we faced and how we solved them. However, today we are going to review the most visible part of the project, the iOS app we built for them.

Our client needed to implement an iOS app letting the user log into the application using an invitation-based system that used either invitation codes or QR codes. Once logged in, users can link their bank account to make deposits and withdrawals from the app. Additionally, they can review their activity in the platform, including all their money movements performed from the app.

When we started to build this app we decided to base our project scaffolding on the following libraries:

  • SwiftLint - A powerful and fully configurable linter.
  • Bitrise - Our favorite continuous integration system
  • Fabric - Fatal and nonfatal error reporting made easy.
  • SwiftGen - A tool to generate Swift code for accessing the project resources.
  • BothamUI - A Model View Presenter framework for Swift we built.
  • BrightFutures - A framework for using Promises in Swift.
  • Sourcery - Meta-programming for Swift, to stop writing boilerplate code.
  • SwiftyBeaver - A powerful logger we linked to Crashlytics for nonfatal error reporting.
  • SwiftDate - All you need to deal with Dates in Swift.
  • Lottie - An iOS library to natively render After Effects vector animations.
  • SDWebImage - Asynchronous image downloader with cache support as a UIImageView category.
  • XCTest - The popular testing framework Apple created.
  • KIF - An iOS Functional Testing Framework.
  • iOSSnapshotTestCase - Snapshot view unit tests for iOS.
  • SwiftCheck - Property-based testing for Swift.
  • OHHTTPStubs - A library to make HTTP stubbing.
  • Swagger Code Gen - A tool to generate clients based on a Swagger spec.

These are the most relevant tools we used to build this product. But including a bunch of GitHub repositories is not the only thing we did. How we used these tools was the key to success in this project.

Thanks to Sourcery and all the meta-programming templates they already implemented for us we were able to write tests with mocks automatically generated in build time.

class CredentialStorageMock: CredentialStorage {

    // MARK: - save

    var saveSignInInfoHasSignedInCallsCount = 0
    var saveSignInInfoHasSignedInCalled: Bool {
        return saveSignInInfoHasSignedInCallsCount > 0
    }
    var saveSignInInfoHasSignedInReceivedArguments: (signInInfo: SignInInfo, hasSignedIn: Bool)?

    func save(signInInfo: SignInInfo, hasSignedIn: Bool) {
        saveSignInInfoHasSignedInCallsCount += 1
        saveSignInInfoHasSignedInReceivedArguments = (signInInfo: signInInfo, hasSignedIn: hasSignedIn)
    }

    // MARK: - read

    var readCallsCount = 0
    var readCalled: Bool {
        return readCallsCount > 0
    }
    var readReturnValue: (signInInfo: SignInInfo, hasSignedIn: Bool)?

    func read() -> (signInInfo: SignInInfo, hasSignedIn: Bool)? {
        readCallsCount += 1
        return readReturnValue
    }

    // MARK: - clear

    var clearCallsCount = 0
    var clearCalled: Bool {
        return clearCallsCount > 0
    }

    func clear() {
        clearCallsCount += 1
    }

}

Thanks to the usage of lottie, we could add impressive animations implemented using After Effects in our application. The walkthrough we implemented thanks to these animations is impressive.

The usage of different testing strategies such us property-based testing or screenshot testing let us write automated tests like these:

    // Screenshot test example
    func test_verify_email_try_to_sign_in_once_it_is_opened() {
        givenThereIsAnErrorVerifyingTheAccount()

        serviceLocator.rootNavigator.goToVerifyEmail()

        verify(serviceLocator.currentWindow?.rootViewController?.view)
    }
    
    // Property-based tests
    property("NextAutoDepositDateCalculator should return the same day if it's today") <- forAll(Date.arbitrary) { today in
            let calculator = NextAutoDepositDateCalculator(dateProvider: { today })

            let nextAutoDepositDate = calculator.execute(repeating: Repeating.Weekly(at: WeekDay(rawValue: today.weekday)!))

            return nextAutoDepositDate == today
        }

Swagger Code Gen combined with an already documented API allowed us to generate the API Client code automatically from the command line. This speeded up our development speed considerably and reduced the number of bugs found in our API layer.

The usage of all these tools and our excellent engineers ended up with an awesome project you can already enjoy in the Apple Store. If you need to develop any similar product and you need help, we'll always be happy to review your project needs and try to find the best way to create the platform your users are going to love! Contact us at hello@karumi.com

Pedro Gómez

I'm a software engineer focused on new technologies, open source, clean code, and testing. Right now I'm working as a Senior Software Engineer at Karumi, a little software development studio.