Some thoughts on use cases in Kotlin

Originally published here on Medium: https://medium.com/@jordanfterry/some-thoughts-on-use-cases-in-kotlin-6ac8021cbcf1

Recently at the Guardian we’ve started to apply the use case pattern to our business logic. A high level overview of a use case is a class that will encapsulate a particular piece of business logic, or behaviour in your app. You may know of this as an interactor pattern as advocated for by Robert Martin in Clean Architecture. They are easy to interpret and test, which will in turn increase both developer productivity and confidence in the quality of a team’s code.

I like to call our use cases “functional use cases”? Why? Well, we make use of operator overloading to override the invoke function to make execution look like a function. Pretty simple really! Here is an example of how this might look:

class FunctionalUseCase() {
   operator fun invoke() {
       // Do something snazzy here.
   }
}

And when we invoke it:

val useCase = FunctionalUseCase()
useCase() // Not a function, but calling overloaded invoke function

It isn’t revolutionary but I like writing our use cases like this. Here are some reasons, and some other musings I have on the topic of use cases.

Overloading the invoke function is straightforward and flexible and allows you to make use of a great Kotlin feature. It is, as you might say, more idiomatic!

It is straightforward because you only have to implement the invoke function and you are good to go. Anyone with knowledge of operator overloading should be able to look at our code and know what is happening.

It is flexible as you can add parameters whatever parameters you like to the invoke function to suit the needs of the particular use case. I think this is great as we can provide any class dependencies as a constructor parameters and provide contextual information as function parameters.

One thing I’ve learned from use case “efforts” in the past is creating an opinionated use case such as one that uses RxJava to handle threading could be a mistake. It might look like this:

abstract class SingleUseCase<T>(
private val observeOn: Scheduler,
private val subscribeOn: Scheduler
) {
    fun execute(): Single<T> {
return Single
.fromCallable { doTheUseCase() }
.observeOn(observeOn)
.subscribeOn(subscribeOn)
}
    abstract fun doTheUseCase(): T
}

This could lead to some sneaky misdirection making it hard for developers to find usages of their implementation of the abstract class, as generically wrapping some behaviour in another type will require an abstract function to fill in that behaviour. A developer won’t be able to find all usages of their implementation as their implementation will always be used in the super class.

This is Rx specific, but you may have to implement multiple classes to handle Observable, Flowable, Completable or Maybe . This just adds a bit of extra complexity to your use cases.

Something I think about regularly is the single responsibility principle (I need more hobbies). It says aclass should only ever have a single reason to change. But in the above implementation, your use case can change if your business rules change or if you decide to stop using RxJava. It breaks SRP in a very subtle way!

Talking of developer experience, there is a particularly annoying gotcha with overloading the invoke function in Kotlin, it relates more to some behaviour in Android Studio/IntelliJ. But lets look at this class:

class AViewModel(private val useCase: UseCase) {
    fun start() {
useCase()
}
}

If you wanted to go to the source of useCase you would be forgiven for thinking you could click on useCase within the start function but you would be wrong. You will actually be taken to the definition of the property. To be taken to the source you’ll have to carefully aim your cursor on the final bracket: useCase(). This is very frustrating if you are trying to quickly navigate through some code!

This quickly turned into me complaining about some old code I have written and applauding some code I’m currently writing. I expect I’ll change my mind on this in the next year or so, but I hope some of these thoughts will be useful to someone!

January 2019 in sports

As the year counter ticked over from 2018 to to 2019 I kicked into motion my plan to get better at this sports thing. This mainly took the shape of doing a lot more exercise and trying to stick to my training plan as closely as I can.

Here’s some numbers from Training Peaks:

Total time – 40 hours 29 minutes
Total distance – 726km

Running time – 9 hours 40 minutes
Running distance – 93.4km

Cycling time – 20 hours 6 minutes
Cycling distance – 620km

Swim time – 4 hours 37 minutes
Swim distance – 11,845m

Strength time – 3 hours 15 minutes

Those are the biggest numbers I’ve ever done, which is pretty exciting. I still have three whole months of preparation for Ironman 70.3 Barcelona so I need to make sure I can keep this up.

Somethings I need to work on:

  • Swim sessions – I was pretty lax in doing them and sticking to the target distances
  • Strength and injury prehab I have the time to expand these sessions
  • Sleep – I’m not getting in enough sleep. I should be aiming for over 8 hours a day
  • Food – I’m not regularly doing the meal prep I should be which means I am eating rubbish every now and then.

The Great South Run 2018

Definitely need new running shorts. 

Between my Sister, Dad and Mum the Terry family have completed The Great South Run a total of six times. Every year a family member has completed it I have never found myself quite ever wanting to run the 10 miles (16km) around Portsmouth. However, given my new found love for endurance sport I thought this year would be as good a year as any to give it a go.

I can tell you already that having done a few sprint triathlons, some long bike rides and few casual training runs does not translate to a very pleasant 10 mile run. 

The first 6km started out pretty well. I started chugging along the Southsea seafront at just under my target pace of 5 min/km and I felt fine. As we worked our way into through Old Portsmouth and into the Portsmouth Naval base I started to feel a bit sore around my chest, perhaps a sign that I was running a little bit too fast? I decided to keep my pace and carry on running and the pain quickly faded – a good sign, or so I thought. 

One part of the run takes you through the city centre and out to a roundabout and back. This is where the wheels quickly came off the wagon! I made it through the first water station and I was as much of a terror to the volunteers as Patrick Lange as I tried to grab bottles of water:

The bottles were a bit of a pain to open as I was running along so I found myself running with bottles for a while as I opened and then tried to drink gracefully. In hindsight I don’t think it is possible to drink gracefully whilst running; in future races I will just accept that water face happens and take in what I can. After the aid station I had to navigate a short obstacle course of jelly babies as someone ahead of me must have demonstrated some poor hand eye co-ordination whilst picking them up.

Anyway, back to the de-wheeling of the wagon. The run leg to the roundabout and back was tough. For some reason the long straight road with a view of people running back the other way didn’t sit well with me. Somehow I survived but I think the mental hit resulted in me losing about 20 seconds a kilometer with half the distance remaining that meant I was very quickly losing time on my target time – shouldn’t have been so vocal about thinking I could hit that time oh well. 

The next leg of the race featured a run back towards Southsea and into some spectator heavy territory. The worst time to be thinking a quick walk wouldn’t be too bad. I managed to perceiver through the negative thoughts and stumbled by my Mum and Dad. Unfortunately I had been looking down at my watch at the time and the video of me stumbling along doesn’t look too great!

It had really started to get warm by this point and I was starting to feel the effects of it and seeing a water station bought a lot of relief to me! Shame it took me about three attempts to grab a bottle of water from someone. A couple of sips of water bought me back to life and for some reason I didn’t drink anymore than that! Got. To. Force. The. Water. Down. Me. 

Soon I was approaching the final turn in the course and heading back along the sea front to the finish line. This bit actually wasn’t too bad. I had a fixed goal of a helicopter hovering over the finish line so I was able to focus on running towards that. Felt a bit sad as the pacer for 1h 25 ran past me and I couldn’t make myself run any faster to keep up with him but I powered through. 

Before I knew it I was at the final 800m and then what felt like 800ms later I was at the 400m sign and then about another 800m I was crossing the finishing line. Which looked like something out of Saving Private Ryan but with people vomiting and the shell shock effect replaced by my hearing going for a bit and me feeling a bit wobbly.

So I made it through the race, definitely wasn’t what I hoped for but I’m glad I got it done anyway. Definitely need to pay more attention to training correctly for an event, completing the training plan and then making sure I fuel correctly during the event. 

The only fuelling on the course was provided by water, jelly babies and a free Sports in Science Gel. The gel was provided too late in the course for me; with about 15/20 minutes left which I don’t think is enough time for the carbs to actually get into the system. However, the electrolyte top up was very much appreciated!