Skip to content

Commit

Permalink
refactor: improve code clarity
Browse files Browse the repository at this point in the history
  • Loading branch information
tassiluca committed Jan 12, 2024
1 parent 942e80a commit b9d6d8e
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 52 deletions.
6 changes: 5 additions & 1 deletion src/main/scala/io/github/tassiLuca/posts/PostsModel.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import java.util.Date
/** The model of a simple blog posts service. */
trait PostsModel:

/** The author identifier. */
type AuthorId

/** The posts title. */
Expand All @@ -14,4 +15,7 @@ trait PostsModel:
type Body

/** A blog post, comprising of an author, title, body and the information about last modification. */
case class Post(author: AuthorId, title: Title, body: Body, lastModification: Date)
case class Post(author: Author, title: Title, body: Body, lastModification: Date)

/** A post author and their info. */
case class Author(authorId: AuthorId, name: String, surname: String)
8 changes: 0 additions & 8 deletions src/main/scala/io/github/tassiLuca/posts/Utils.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,3 @@ extension (component: String)
println(s"[$component - ${Thread.currentThread()}] $action")
Thread.sleep(Random.nextInt(10_000))
println(s"[$component - ${Thread.currentThread()}] ended $action")

extension [T](p: (T, T))
def both(f: T => Boolean): Boolean = f(p._1) && f(p._2)

@main def testBoth(): Unit =
println(
(Success(true), Failure(IllegalStateException())).both(r => r.isSuccess && r.get)
)
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
package io.github.tassiLuca.posts.direct

import gears.async.AsyncOperations.sleep
import gears.async.default.given
import gears.async.{Async, Future, Task}
import gears.async.{Async, Task}
import io.github.tassiLuca.boundaries.either
import io.github.tassiLuca.boundaries.either.{?, ThrowableConverter}
import io.github.tassiLuca.posts.{PostsModel, simulates, both}
import io.github.tassiLuca.posts.{PostsModel, simulates}

import java.util.Date
import scala.util.{Failure, Success, Try}
Expand Down Expand Up @@ -34,30 +33,31 @@ trait PostsServiceComponent:
def apply(): PostsService = PostsServiceImpl()

private class PostsServiceImpl extends PostsService:

opaque type PostContent = (Title, Body)

given ThrowableConverter[String] = (t: Throwable) => t.getMessage

override def create(authorId: AuthorId, title: Title, body: Body): Either[String, Post] =
override def create(authorId: AuthorId, title: Title, body: Body): Either[String, Post] = either:
Async.blocking:
val post = Post(authorId, title, body, Date())
if post.verifyAuthor.run.zip(post.verifyContent.run).await.both(r => r.isSuccess && r.get) then
either { context.repository.save(post).? }
else Left("Error")

extension (p: Post)
private def verifyAuthor(using Async): Task[Try[Boolean]] = Task:
Try:
sleep(10_000)
"PostsService" simulates s"verifying author '${p.author}'"
true

private def verifyContent(using Async): Task[Try[Boolean]] = Task:
Try:
"PostsService" simulates s"verifying post '${p.title}' content"
false
val author = authorBy(authorId).run
val content = verifyContent(title, body).run
val post = Post(author.await.?, content.await.?._1, content.await.?._2, Date())
context.repository.save(post).?
post

private def authorBy(id: AuthorId)(using Async): Task[Either[String, Author]] = Task:
either:
"PostsService" simulates s"getting author $id info..."
Author(id, "Luca", "Tassinari")

private def verifyContent(title: Title, body: Body)(using Async): Task[Either[String, PostContent]] = Task:
either:
"PostsService" simulates s"verifying content of the post '$title'"
(title, body)

override def get(title: Title): Either[String, Post] = either:
Async.blocking { context.repository.load(title).? }

override def all(): Either[String, LazyList[Post]] = either:
Async.blocking(context.repository.loadAll().?)
Async.blocking { context.repository.loadAll().? }
Original file line number Diff line number Diff line change
Expand Up @@ -15,43 +15,40 @@ trait PostsServiceComponent:

/** The service exposing a set of functionalities to interact with blog posts. */
trait PostsService:
/** Creates a new blog post with the given [[title]] and [[body]], authored by [[authorId]], or a string explaining
* the reason of the failure.
*/
def create(authorId: AuthorId, title: Title, body: Body): Future[Unit]
/** Creates a new blog post with the given [[title]] and [[body]], authored by [[authorId]]. */
def create(authorId: AuthorId, title: Title, body: Body): Future[Post]

/** Get a post from its [[title]] or a string explaining the reason of the failure. */
/** Get a post from its [[title]]. */
def get(title: Title): Future[Post]

/** Gets all the stored blog posts in a lazy manner or a string explaining the reason of the failure. */
/** Gets all the stored blog posts in a lazy manner. */
def all(): Future[LazyList[Post]]

object PostsService:
def apply(): PostsService = PostsServiceImpl()

private class PostsServiceImpl extends PostsService:

opaque type PostContent = (Title, Body)
given ExecutionContext = ExecutionContext.global

override def create(authorId: AuthorId, title: Title, body: Body): Future[Unit] =
val post = Post(authorId, title, body, Date())
val authorVerification = Future { post.verifyAuthor }
val contentVerification = Future { post.verifyContent }
override def create(authorId: AuthorId, title: Title, body: Body): Future[Post] =
val author = authorBy(authorId)
val content = verifyContent(title, body)
for
resultAuthor <- authorVerification
if resultAuthor
resultVerification <- contentVerification
if resultVerification
a <- author
c <- content
post = Post(a, c._1, c._2, Date())
_ <- context.repository.save(post)
yield ()
yield post

extension (p: Post)
private def verifyAuthor: Boolean =
"PostsService" simulatesBlocking s"verifying author '${p.author}''"
if Math.random() > 0.3 then true else false
private def authorBy(id: AuthorId)(using ExecutionContext): Future[Author] = Future:
"PostsService" simulatesBlocking s"getting author $id info..."
Author(id, "Luca", "Tassinari")

private def verifyContent: Boolean =
"PostsService" simulatesBlocking s"verifying post '${p.title}' content"
if Math.random() > 0.3 then true else false
private def verifyContent(title: Title, body: Body)(using ExecutionContext): Future[PostContent] = Future:
"PostsService" simulatesBlocking s"verifying content of the post '$title'"
(title, body)

override def get(title: Title): Future[Post] = context.repository.load(title)

Expand Down

0 comments on commit b9d6d8e

Please sign in to comment.