Skip to content

Instantly share code, notes, and snippets.

@ZakTaccardi
Created December 16, 2020 17:15
Show Gist options
  • Save ZakTaccardi/8055bc677f17882840a4c1b08f65c125 to your computer and use it in GitHub Desktop.
Save ZakTaccardi/8055bc677f17882840a4c1b08f65c125 to your computer and use it in GitHub Desktop.
Function Interception (composition)
/**
* An abstraction around a 3rd party SDK that does some magic to
* identify if a user is a bot or not.
*
* The real implementation may have direct Android dependencies,
* so being able to swap this out is useful for unit testing
*/
interface VendorSdk {
suspend fun isUserABot(): Boolean
}
// Construct a `VendorSdk` implementation with all the
// bells and whistles
fun VendorSdk(
// could swap out for a fake for testing
realVendorSdk: VendorSdk = RealVendorSdk(),
logger: Logger,
analytics: Analytics,
performanceMonitor: PerformanceMonitor
): VendorSdk = realVendorSdk
// add logging for each interaction with the vendor sdk
.withLogging(logger)
// add analytics for each interaction
.withAnalytics(analytics)
// add performance monitoring for each interaction
.withPerformanceMonitoring(performanceMonitor)
fun VendorSdk.withLogging(logger: Logger): VendorSdk {
return LoggingVendorSdk(delegate = this, logger = logger)
}
fun VendorSdk.withAnalytics(analytics: Analytics): VendorSdk {
// follow same pattern as `LoggingVendorSdk` to add analytics
// to each interaction with a `VendorSdk` instance
TODO()
}
fun VendorSdk.withPerformanceMonitoring(
performanceMonitor: PerformanceMonitor
): VendorSdk {
// follow same pattern as `LoggingVendorSdk` to add
// performance monitoring to each interaction with a
// `VendorSdk` instance
TODO()
}
/**
* An abstraction around the real vendor SDK - [BotChecker].
*
* Useful because this could be swapped out for a
*/
class RealVendorSdk(
private val botChecker: BotChecker = BotChecker.getInstance()
) : VendorSdk {
override suspend fun isUserABot(): Boolean {
return botChecker.isUserABot()
}
}
class LoggingVendorSdk(
// the actual `VendorSdk` implementation that
// `LoggingVendorSdk` adds logging to
private val delegate: VendorSdk,
private val logger: Logger
) : VendorSdk {
override suspend fun isUserABot(): Boolean {
logger.log(Level.INFO, "Will check if user is a bot")
val isUserABot = delegate.isUserABot()
logger.log(
Level.INFO,
if (isUserABot) {
"user was a bot!"
} else {
"user was not a bot!"
}
)
return isUserABot
}
}
class FakeVendorSdk(var isUserABot: Boolean) : VendorSdk {
override suspend fun isUserABot(): Boolean {
return isUserABot
}
}
// pretend this is the real vendor SDK
class BotChecker {
suspend fun isUserABot(): Boolean {
TODO()
}
companion object {
fun getInstance(): BotChecker {
TODO()
}
}
}
fun `swap out real implementation for fake`() {
val vendorSdk: VendorSdk = VendorSdk(
realVendorSdk = FakeVendorSdk(isUserABot = true),
analytics = TODO(),
logger = TODO(),
performanceMonitor = TODO()
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment