3. Why?
result match {
case Success(_) =>
case Failure(ex) =>
Logger.error(s"Failed to comment project ${project.id}”)
}
I HATE BOILERPLATE
result.logException(s"Failed to comment project ${project.id}”)
And even logs the exception,
that sometimes we love to
hide...
4. Implementation
implicit class TryExtension[T](nativeTry: Try[T]) {
private val defaultMsg: String = "Try is a failure"
def logException(logger: String => Unit = defaultLogger, msg: String = defaultMsg): Try[T] = {
nativeTry match {
case Success(_) =>
nativeTry
case Failure(e) =>
val msgWithStacktrace =
s"""
|$msg
|message: ${e.getMessage}
|${e.getStackTrace.mkString(System.lineSeparator)}
""".stripMargin
logger(msgWithStacktrace)
nativeTry
}
}
private def defaultLogger(msgWithStacktrace: String): Unit = Logger.error(msgWithStacktrace)
}
5. Although it uses “implicit”, remember that
you still have to call the methods explicitly!
So the “hate on implicits” arguments don’t
apply ;)
6. It’s not about knowing how to do it, it is
about doing it! Instead of copypasta more
bolierplate..
.orElse {
Logger.error(s"Failed to updated Heroku user: RequestURL=$url Response=${response.json}")
None
}
Pretty much as we did a .logException(), we can easily do a
.logNone()!
.logNone(s"Failed to updated Heroku user: RequestURL=$url Response=${response.json}")
7. It can be more than
just logs
Although I like to use the extensions
on logs, (because we don’t care about
them, we just want the bad guys to be
logged, and it always the same thing)
there are MANY MORE cases where
we can use them.
if (!updated) {
ProjectRules.addUserToProject(
projectId,
teamMember.userIdentifier,
teamMember.permission
)
}
updated
8. Boolean Extension :D
updated.onFalse {
ProjectRules.addUserToProject(
projectId,
teamMember.userIdentifier,
teamMember.permission
)
}
updated //not needed
.onFalse() returns the boolean itself, so no need to repeat
the “updated”
9. Plenty of great use cases!
//potatos: Seq[A]
potatos.distinctBy(_.weight) //Instead of CollectionHelper.distinctBy(potatos, _.weight)
//res: Option[A]
res.toResponse(msg = “Failed xxx”)
//res: Try[A]
res.toResponse()
…….
10. Implicit Classes Everywhere???
The “Extension” types are just a way to achieve
extension methods. Never use their types!
For example “TryExtension” should only be mentioned
on the import itself, shouldn’t be use anywhere else! We
just want the methods, not the type of the class
And also, PLEASE don’t do implicit extensions on
classes that we own!
If if is our code, we can just go there and add a method!
“Don’t wanna update foundation” is not an excuse to
start making implicit classes that extend our Response!
11. “he who yields the chalice shall have
everlasting awesomeness”
- The ancient council of elders