DEV Community

David Geirola
David Geirola

Posted on • Updated on

Semantic of a functional app in Scala

Introduction

Functional applications offer numerous benefits in modern software development. They enhance testability, modularity, and composability, leading to more maintainable and scalable codebases. In this article, we'll explore the syntax and semantics of functional applications and introduce the app-toolkit library—a powerful tool for building functional applications more efficiently.

Syntax and Semantic of an App

At its core, an app can be represented as a function that takes an input (I) and produces an output (O). By incorporating side effects, we extend this representation to I => F[O], where F[_] denotes the ability to handle side effects.

Resources

To build an app, we rely on resources such as app information, input arguments, a logger, and configuration settings.

With this concept in mind, we can merge these resources with the input (I) since the only input we have are the app arguments, resulting in:

(AppInfo, F[Config], Args, F[Logger], F[OtherResources]) => F[O].

Dependencies

Dependencies represent application-specific services and repositories used in the app's logic.

Combining resources and dependencies, we arrive at:

(AppInfo, F[Config], Args, F[Logger], F[OtherResources]) => (AppInfo, Config, Args, Logger, OtherResources, F[Dependencies]) => F[O].

Because we need resources to build the dependencies and we need dependencies to build the app logic.
Dependencies also includes the resources.

Provided services

Now, let's imagine that given all the resources and dependencies, we can define a list of tasks to run in parallel (including never-terminating tasks like an HTTP server).

Thus, the final definition of the app logic F[O] is actually the result of the parallel execution of all the provided services, which are expressed as:

AppDependencies => F[List[Any]]

Giving an example a service that provide an HTTP server is just a single never-ending task app.

An app that provide an HTTP server and consume from a Kafka topic is 2 parallel tasks app.

Flattening

We have zoomed inside the app's semantics to better understand its parts, but in the end, the app can be typed as:

F[Unit] or F[ExitCode]

Since the output of the app must be delivered through the provided services, the output will always be Unit or ExitCode.

The app consists of multiple steps:

  • Loading resources
  • Building dependencies
  • App logic: executing parallel tasks

App-toolkit

https://github.com/geirolz/toolkit

App-toolkit is a lightweight and functional non-intrusive library for building typed and declarative Scala applications with managed resources and dependencies. It has been developed with the aforementioned concepts in mind. It provides a nice syntax for defining and building applications, and it manages the resources, allowing you to focus on the important parts of the application.

Here's an example:

import cats.effect.{ExitCode, IO, IOApp}
import com.geirolz.app.toolkit.App
import com.geirolz.app.toolkit.logger.ToolkitLogger
import com.geirolz.app.toolkit.error.*

object Main extends IOApp {
  override def run(args: List[String]): IO[ExitCode] =
    App[IO]
      .withInfo(
        SimpleAppInfo.string(
          name = "app-toolkit",
          version = "0.0.1",
          scalaVersion = "2.13.10",
          sbtVersion = "1.8.0"
        )
      )
      .withLogger(ToolkitLogger.console[IO](_))
      .withConfigLoader(_ => IO.pure(Config("localhost", 8080)))
      .dependsOn(AppDependencyServices.resource(_))
      .provideOne(deps =>
        // Kafka consumer
        deps.dependencies.kafkaConsumer
          .consumeFrom("test-topic")
          .evalTap(record => deps.logger.info(s"Received record $record"))
          .compile
          .drain
      )
      .beforeRun(_.logger.info("CUSTOM PRE-RUN"))
      .onFinalize(_.logger.info("CUSTOM END"))
      .run(args)
}
Enter fullscreen mode Exit fullscreen mode

Conclusions

In this article, we explored the syntax and semantics of functional applications. We viewed applications as functions with inputs and outputs, considering side effects with the F[_] type.

Resources and dependencies played crucial roles in building and executing these applications. We also introduced the app-toolkit, a lightweight and functional library that simplifies the development of typed and declarative Scala applications.

By leveraging functional programming principles and tools like app-toolkit, developers can create scalable and reliable applications. Understanding the syntax and semantics of functional applications empowers developers to deliver high-quality user experiences.

Top comments (0)