{"id":17997406,"url":"https://github.com/thma/polysemycleanarchitecture","last_synced_at":"2025-05-07T15:46:52.115Z","repository":{"id":41416180,"uuid":"238771607","full_name":"thma/PolysemyCleanArchitecture","owner":"thma","description":"Showcasing how the Polysemy library can be used to implement a REST application conforming to the guidelines of the Clean Architecture model.","archived":false,"fork":false,"pushed_at":"2023-12-15T08:39:42.000Z","size":1678,"stargazers_count":192,"open_issues_count":1,"forks_count":16,"subscribers_count":10,"default_branch":"master","last_synced_at":"2025-03-31T11:35:30.005Z","etag":null,"topics":["algebraic","algebraic-effects","architecture","clean-architecture","domain-driven-design","haskell","hexagonal-architecture","io-monad","onion-architecture","persistence-layer","polysemy","polysemy-effects","polysemy-library","ports-and-adapters","servant","sqlite","swagger-documentation","swagger-ui","testability","warp"],"latest_commit_sha":null,"homepage":"","language":"Haskell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/thma.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-02-06T19:52:32.000Z","updated_at":"2025-01-30T13:38:42.000Z","dependencies_parsed_at":"2023-12-15T09:46:00.272Z","dependency_job_id":null,"html_url":"https://github.com/thma/PolysemyCleanArchitecture","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thma%2FPolysemyCleanArchitecture","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thma%2FPolysemyCleanArchitecture/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thma%2FPolysemyCleanArchitecture/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thma%2FPolysemyCleanArchitecture/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/thma","download_url":"https://codeload.github.com/thma/PolysemyCleanArchitecture/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252908959,"owners_count":21823525,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["algebraic","algebraic-effects","architecture","clean-architecture","domain-driven-design","haskell","hexagonal-architecture","io-monad","onion-architecture","persistence-layer","polysemy","polysemy-effects","polysemy-library","ports-and-adapters","servant","sqlite","swagger-documentation","swagger-ui","testability","warp"],"created_at":"2024-10-29T21:18:26.492Z","updated_at":"2025-05-07T15:46:52.088Z","avatar_url":"https://github.com/thma.png","language":"Haskell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Implementing Clean Architecture with Haskell and Polysemy\n\n[![Actions Status](https://github.com/thma/PolysemyCleanArchitecture/workflows/Haskell%20CI/badge.svg)](https://github.com/thma/PolysemyCleanArchitecture/actions)\n\n## tl;dr\n\nThis article shows how algebraic effect systems can be used to maintain a clear separation of concerns between \ndifferent parts of software systems. From a practical programming perspective this improves composability and \ntestability of software components.\n\nI'm demonstrating this idea by using the Polysemy library to implement a multi-layered REST application conforming to the \nguidelines of the Clean Architecture model.\n\n## Motivation\n\nWhile writing [Why Haskell Matters](https://github.com/thma/WhyHaskellMatters#readme) I prepared a little \ndemo application that was meant to showcase a cleanly designed REST application in Haskell. \nIn particular, I wanted to demonstrate how the clear separation of *pure* and *impure* code helps to\nprovide strict separation of concerns and state-of-the-art testability of all application layers.\n\n**I failed!** \n\nI was able to write the domain logic in *pure* code consisting only of *total* functions. \nIt was a great pleasure to write unit tests for them!\n\nHowever, as soon as I started writing controllers that coordinate\naccess to the domain logic as well as to a persistence layer to retrieve and store data, I was stuck in the IO Monad.\nThat is, in test cases I was not able to test the controllers independently of the concrete backend.\n\nThen I tried to apply the *final tagless* pattern for the persistence layer. This allowed abstracting out the concrete \npersistence layer and writing controller tests with a mocked persistence backend.\nBut when it came to testing the REST API handlers (written with Servant) I was again stuck in the IO Monad as the Handler type is defined as \n`newtype Handler a = Handler { runHandler' :: ExceptT ServerError IO a }`.\nMaybe it's not a principle issue but just my brain being too small...\n\nI was desperately looking for something that allowed me to combine different types of effects \n(like persistence, logging, configuration, http handlers, error handling, etc.) in controllers and handlers but still to be able to\nwrite tests that allow using mocks or stubs to test components in isolation.\n\nAs I reached a dead end, I had a look at some of the *algebraic effect systems* available in Haskell, like \neff, extensible-effects, fused-effects, freer-simple and Polysemy. \n\nIn algebraic effect systems, effectful programs are split into two separate parts: \nthe specification of the effects to be performed, and the interpretation (or semantics) given to them.\n\nSo my idea was to provide special effect interpretations that would allow building mocked effects for my test suite.\n\nAfter seeing a [presentation on maintainable software architecture with Polysemy](https://youtu.be/kIwd1D9m1gE) which answered\nmany of my questions I rewrote my application based on Polysemy powered algebraic effects.\n\nI'm pretty satisfied with the result, and of course I'm eager to share my approach with you!\n\n## The Challenge\n\nA very small boutique restaurant (serving excellent vietnamese food) is looking for a reservation system that allows managing reservations.\nThe restaurant has only twenty seats, they also take only a maximum of twenty reservations per day. (So guests can stay \nthe whole evening and don't have to leave after some time.)\n(I adopted this scenario from a inspiring [talk by Mark Seemann](https://youtu.be/US8QG9I1XW0))\n\nThey have asked us to write the REST backend for their reservation system.\n\nThe chef insists on a scrupulously clean kitchen and is also a lover of clean code. \nHe has read about clean architecture and wants his new software to be a perfect example!\n\nSo we cannot just hack away but first have to understand what is expected from us when we are to deliver a\nclean architecture.\n\n## What makes a Clean Architecture ?\n\nI'm following the introduction to clean architecture by Robert C. Martin on his\n[Clean Code blog](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html). \nHe states that his concept builds up on \nseveral earlier approaches like [hexagonal architecture](https://en.wikipedia.org/wiki/Hexagonal_architecture_(software)),\n[ports and adapters](https://en.wikipedia.org/wiki/Hexagonal_architecture_(software)) or [Onion Architecture](https://jeffreypalermo.com/2008/07/the-onion-architecture-part-1/).\n\nAccording to him all these approaches share a similar objective: achieve separation of concerns by dividing a software system into different layers. \nAll approaches result in system designs that share a common set of features:\n\n1. The architecture does not depend on any specific software libraries or frameworks. This allows to freely choose such tools\naccording to the actual needs. This avoids \"vendor lock in\".\n\n2. High testability. The business logic can be tested without any external element like UI, DB, Web Server, etc.\n\n3. The UI is loosely coupled to the core system. So it can be easily changed or replaced without affecting the rest of the system.\n\n4. The Database is also \"external\" to the core system. It can be easily changed (even from an RDBMS to NonSQL DB) without affecting the business logic.\n\n5. The Business logic is agnostic of the outside world. It has no dependencies to any external systems like DB, ESB, etc.\n \n### Layers with clearly separated responsibilities\n \nThe architecture consists of four layers, each of which contains components with a specific scope and a limited set of responsibilities.\n\n1. At the centre sits the **Domain** layer consisting of entities and core business logic.\n\n2. Next comes the **Use Cases** layer where all resources are coordinated that are required to fulfill a given use case.\n   In particular, it uses entities and logic from the domain layer to implement use cases. But typically it must also \n   interface to a persistent storage to retrieve and store entities.\n   \n3. The **Interface Adapters** layer holds code for UI controllers and presenters as well as adapters to external \n   resources like databases, message queues, configuration, Logging, etc.\n   \n4. The **External Interfaces** layer contains the technical implementation of external interfaces. For example,\n   a concrete REST service assembly, Web and UI infrastructure, databases, etc. \n \n ### The Dependency Rule\n  \n\u003e The overriding rule that makes this architecture work is The Dependency Rule. This rule says that source code \n\u003e dependencies can only point inwards. Nothing in an inner circle can know anything at all about something in an outer \n\u003e circle. In particular, the name of something declared in an outer circle must not be mentioned by the code in the an \n\u003e inner circle. That includes, functions, classes. variables, or any other named software entity.\n\u003e\n\u003e Quoted from [Clean Architecture blog post](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html)\n\nThis dependency rule leads to a very interesting consequence: If a use case interactor needs to \naccess a component from an outer circle, e.g. retrieve data from a database, this must be done\nin a specific way in order to avoid breaking the dependency rule:\nIn the use case layer we don't have any knowledge about the components of the outer circles.\n**If we require access to a database (or any other external resources), the call interface, \nas well as the data transfer protocol must be specified in the use case layer.**\n\nThe components in the outer circles will then implement this interface. Using this kind of interfaces, \nit is possible to communicate accross the layer boundaries, but still maintain a strict separation of\nconcerns. \n\nIf you want to dive deeper into clean architecture I recommend the\n[Clean Architecture blog post](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html)\nas an entry point. Robert C. Martin later also published a whole book \n[Clean Architecture: A Craftsman's Guide to Software Structure and Design](https://www.amazon.com/Clean-Architecture-Craftsmans-Software-Structure/dp/0134494164) \non this concept.\n\nIn the following sections I'll explain how the clean architecture guidelines can be implemented in a \nHaskell REST API application by making use of the algebraic effect library \n[Polysemy](https://github.com/polysemy-research/polysemy#readme).\n\n## The Domain layer\n\nThe [ReservationDomain](src/Domain/ReservationDomain.hs) module implements the business logic for \nseat reservations in a very small boutique restaurant. The restaurant has only one big table with 20 seats.\nEach day the restaurants accepts only 20 reservations. (There is no limited time-slot for each guest.)\n\nPlease note: \n- all functions in this module are **pure** (they don't do any IO) and **total** (they produce defined \nresults for all possible input values).\n\n- The definitions in this module do not have dependencies to anything from the outer circles.\n\nAt the core of our Domain lies the `Reservation` data type:\n\n```haskell\n-- | a data type representing a reservation\ndata Reservation = Reservation\n    { date     :: Day    -- ^ the date of the reservation\n    , name     :: String -- ^ the name of the guest placing the reservation\n    , email    :: String -- ^ the email address of the guest\n    , quantity :: Natural    -- ^ how many seats are requested\n    }\n    deriving (Eq, Generic, Read, Show)\n```\n\nThis type can be used to express facts like *Mr. Miller reserved two seats on 2020-06-01, \nhe can be reached via his email address: manfred@miller.com*:\n\n```haskell\nreservation = Reservation {name = \"Mr. Miller\", quantity = 2, date = read \"2020-06-01\", email = \"manfred@miller.com\"}\n```\n\nAll reservations of a specific day are represented as a list of reservations: `[Reservation]`.\n\nA `ReservationMap` is a map from `Day` to `[Reservation]`:\n\n```haskell\n-- | a key value map holding a list of reservations for any given day\ntype ReservationMap = Map Day [Reservation]\n```\n\nThat is, we can keep track of all reservations by maintaining them in such a map:\n\n```haskell\nfromList \n  [\n    (\n      2020-06-01,\n        [\n          Reservation {date = 2020-06-01, name = \"Mr. Miller\", email = \"manfred@miller.com\", quantity = 2}, \n          Reservation {date = 2020-06-01, name = \"Andrew M. Jones\", email = \"amjones@example.com\", quantity = 4}\n        ]\n    )\n  ]\n```\n\nBased on these data types we can define domain logic like computing the used capacity of a list of reservations:\n\n```haskell\n-- | computes the number of reserved seats for a list of reservations\nusedCapacity :: [Reservation] -\u003e Natural\nusedCapacity [] = 0\nusedCapacity (Reservation _ _ _ quantity : rest) = quantity + usedCapacity rest\n```\n\nBased on this we can compute the number of available seats (given a maximum capacity and a list of reservations):\n\n```haskell\n-- | computes the number of available seats from a maximum capacity and a list of reservations.\navailableSeats :: Natural-\u003e [Reservation] -\u003e Natural\navailableSeats maxCapacity reservations = maxCapacity - usedCapacity reservations\n```\n\nThe `Reservation` data type and some of the domain logic functions are depicted in the in the following\ndiagram:\n\n![The Domain layer](domain.png)\n\n### Testing the domain layer\n\nAs already mentioned: this layer has no knowledge of the world and it's all pure code.\nTesting domain logic in isolation therefore is straight forward, \nas you can see from the [DomainSpec](test/DomainSpec.hs) code.\n\nThe data types and functions of the domain layer can be used directly, without any mocking of components:\n\n```haskell\nday = fromGregorian 2020 1 29\nres1 = Reservation day \"Andrew M. Jones\" \"amjones@example.com\" 4\nres2 = Reservation day \"Thomas Miller\" \"tm@example.com\" 3\nreservations = [res1, res2]\ntotalCapacity = 20\n\nspec :: Spec\nspec =\n  describe \"Domain Logic\" $ do\n    it \"computes the used capacity for an empty list of reservations\" $\n      usedCapacity [] `shouldBe` 0\n\n    it \"computes the used capacity for a list of reservations\" $\n      usedCapacity [res1, res2] `shouldBe` 7\n      \n    it \"computes the available seats for a list of reservations\" $\n      availableSeats totalCapacity [res1, res2] `shouldBe` 13\n```\n\n## The Use Case layer\n\n\u003e The software in this layer contains application specific business rules. It encapsulates and implements all of the \n\u003e use cases of the system. These **use cases orchestrate the flow of data to and from the entities, and direct those \n\u003e entities to use their enterprise wide business rules to achieve the goals of the use case.**\n\u003e\n\u003e Quoted from the [Clean Architecture blog post](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html)\n\nThe module [ReservationUseCase](src/UseCases/ReservationUseCase.hs) specifies the available use cases for the reservation system.\nIt coordinates access to Effects and the actual domain logic.\nThe module exposes service functions that will be used by the REST API in the ExternalInterfaces layer.\n\nImplemented Use Cases:\n\n1. Display the number of available seats for a given day\n\n2. Enter a reservation for a given day and keep it persistent.\n   If the reservation can not be served as all seats are occupies provide a functional error message stating\n   the issue.\n\n3. Display the list of reservations for a given day.\n\n4. Delete a given reservation from the system in case of a cancellation.\n   NO functional error is required if the reservation is not present in the system.\n\n5. Display a List of all reservation in the system.\n\nIn the Use Case layer we have left the garden Eden of *world agnostic* code:\n\nIn order to compute the number of available seats for a given day, we will have to\nfirst look up the actual reservations for that day from a persistent storage, \nand only then can we call the domain function `availableSeats`.\nIn addition we also will have to write a Log message when calling the functions\nto provide an audit trail.\n\n**However, the dependency rule of clean architecture bans all direct access to a database or a \nlogging-infrastructure from the use case layer!**\n\n### How can we define such a use case without violating the dependency rule?\n\nAlgebraic Effect systems offer a consistent answer: \n1. We **declare effects** in the use case layer by defining them as an abstract interface.\n\n2. We also specify the actual **usage of effects** in the use case layer by having calls against the abstract interface.\n\n3. We provide an **interpretation** of these effects only in the outer layers.\n   This also allows us to provide different implementations. \n   So we can easily swap backends, e.g. migrating from MySQL to PostgreSQL, \n   and it can be used to provide mock implementations for testing purposes.\n\nLet's see how all this looks like when using Polysemy.\n\n### Usage of effects\n\n```haskell\n-- | compute the number of available seats for a given day. the result must be a natural number, incl. 0\navailableSeats :: (Member Persistence r, Member Trace r) =\u003e Day -\u003e Sem r Natural\navailableSeats day = do\n  trace $ \"compute available seats for \" ++ show day\n  todaysReservations \u003c- fetch day\n  return $ Dom.availableSeats maxCapacity todaysReservations\n\n-- | fetch the list of reservations for a given day from the key value store.\n--   If no match is found, an empty list is returned.\nfetch :: (Member Persistence r, Member Trace r) =\u003e Day -\u003e Sem r [Dom.Reservation]\nfetch day = do\n  trace $ \"fetch reservations for \" ++ show day\n  maybeList \u003c- getKvs day\n  return $ fromMaybe [] maybeList\n\n-- | the maximum capacity of the restaurant.\nmaxCapacity :: Natural\nmaxCapacity = 20\n```\n\nThe type signature of `availableSeats` contains two constraints on the *effect stack* type `r`: `(Member Persistence r, Member Trace r)`\nThis means that the function may perform two different effects: persistence via the `Persistence` effect and \nLogging via the `Trace` effect.\n\nThe type signature also specifies that we need an input of type `Day` and will return the `Natural` result\nwrapped in the `Sem r` monad.\n\nThe `Sem` monad handles computations of arbitrary extensible effects.\nA value of type `Sem r` describes a program with the capabilities of the effect stack `r`.\n\nThe first step of the function body of `availableSeats` specifies a Log action based on the (Polysemy built-in) \n`Trace` effect:\n\n```haskell\n  trace $ \"compute available seats for \" ++ show day\n```\n\nI repeat: `trace ` does not directly do any logging. The actual logging action - the effect interpretation - will be \ndefined in the application  assembly or in a test setup.\n\nThe next line specifies a lookup of the reservation list for `day` from the persistence layer:\n\n```haskell\n  todaysReservations \u003c- fetch day\n```\n\nwhere fetch is defined as:\n\n```haskell\nfetch :: (Member Persistence r, Member Trace r) =\u003e Day -\u003e Sem r [Dom.Reservation]\nfetch day = do\n  trace $ \"fetch reservations for \" ++ show day\n  maybeList \u003c- getKvs day\n  return $ fromMaybe [] maybeList\n```\n\n### Declaration of effects\n\nTo understand the `fetch` function, in particular the expression `maybeList \u003c- getKvs day` we first have to know the \ndefinition of the `Persistence` effect:\n\n```haskell\ntype Persistence = KVS Day [Dom.Reservation]\n```\nWhere KVS (standing for Key/Value Store) is a type that is \nalso defined in the use case layer ([KVS.hs](src/UseCases/KVS.hs)):\n\n```haskell\n-- | a key value store specified as a GADT\ndata KVS k v m a where\n  ListAllKvs :: KVS k v m [(k, v)]\n  GetKvs     :: k -\u003e KVS k v m (Maybe v)\n  InsertKvs  :: k -\u003e v -\u003e KVS k v m ()\n  DeleteKvs  :: k -\u003e KVS k v m ()\n\nmakeSem ''KVS\n```\n\nThe four operations of the key value store are defined in the GADT as type constructors.\n`makeSem ''KVS` then uses TemplateHaskell to generate effect functions (or smart Constructors) from the GADT definition.\nThis call results in the definition of the following four functions that represent the specific operations of the key value store:\n\n```haskell\nlistAllKvs :: Member (KVS k v) r =\u003e Sem r [(k, v)]\ngetKvs     :: Member (KVS k v) r =\u003e k -\u003e Sem r (Maybe v)\ninsertKvs  :: Member (KVS k v) r =\u003e k -\u003e v -\u003e Sem r ()\ndeleteKvs  :: Member (KVS k v) r =\u003e k -\u003e Sem r ()\n```\n\nThese functions can be used in the `Sem` Monad. So now we understand much better what is going on in `fetch`:\n\n```haskell\nfetch :: (Member Persistence r, Member Trace r) =\u003e Day -\u003e Sem r [Dom.Reservation]\nfetch day = do\n  trace $ \"fetch reservations for \" ++ show day\n  maybeList \u003c- getKvs day\n  return $ fromMaybe [] maybeList\n```\n\nAs `fetch` operates in the `Sem` monad, `maybeList` is bound to a `Maybe [Dom.Reservation]` value, \nwhich results from the `getKVs day` action.\nThe function finally uses `fromMaybe` to return a list of reservations that were retrieved (or `[]` in case `Nothing`\nwas found for `day`).\n\nThen, back in `availableSeats` we call the domain logic function `Dom.availableSeats` to compute the number of available seats.\nThe resulting `Natural` value is lifted into the `Sem r` monad, thus matching the signature of the return type `Sem r Natural`.\n\nIn the next diagram I'm depicting the layers Use Cases and Domain. The arrow from Use Cases to Domain represents the dependency\nrule: use case code may only reference domain logic but the domain logic may not reference anything from the use case layer.\n  \nOn the left side of the diagram we see the use case controllers (aka *use case interactors*) like `availableSeats` that \ncoordinate all activities and resources to fulfill a specific use case.\n\nOn the right we see the gateway (or interface) code like the `KVS` abstraction of a key-value store or the `fetch` \noperation that wraps the access to the key-value store.\n\n![Use Cases layer](use-cases.png)\n\n### Interpretation of effects / Testing\n\nThe key value store functions like `getKvs` don't perform any concrete operation. They just `declare` access to\nan abstract key-value store interface.\n\nThe concrete interpretation of these calls will be specified in the application assembly (typically in `Main.hs`) or\nin the setup code of test cases.\nIf we provide a *pure* interpretation then the resulting code will also be pure. \nThis allows writing tests in the same pure way as for the domain logic.\n\nAs an example, in [UseCasePureSpec](test/UseCasePureSpec.hs) I'm providing pure interpretations \nfor all effects. \n\nThe `runPure` function takes a program with effects and handles each effect till it gets reduced \nto `Either ReservationError (ReservationMap‚ a)`:\n\n```haskell\nrunPure :: ReservationMap \n        -\u003e Sem '[UC.Persistence, State ReservationMap, Error UC.ReservationError, Trace] a \n        -\u003e Either UC.ReservationError (ReservationMap, a)\nrunPure kvsMap program =\n  program\n     \u0026 runKvsPure kvsMap              -- run the key-value store on a simple ReservationMap\n     \u0026 runError @UC.ReservationError  -- run error handling to produce an Either UC.ReservationError (ReservationMap, a)\n     \u0026 ignoreTrace                    -- run Trace by simply ignoring all messages \n     \u0026 run                            -- run a 'Sem' containing no effects as a pure value\n```\n\nIn addition to that I'm providing wrapping functions like `runAvailableSeats` that use `runPure` to interprete the effects of\nthe use case functions (eg. `UC.availableSeats`) and extract the actual result from the \n`[Either UC.ReservationError (ReservationMap, a)]` return value:\n\n```haskell\nrunAvailableSeats :: ReservationMap -\u003e Day -\u003e Natural\nrunAvailableSeats kvsMap day = do\n  case runPure kvsMap (UC.availableSeats day) of\n    Right (_, numSeats) -\u003e numSeats\n    Left err            -\u003e error \"availableSeats failed\"\n```\n\nThis is all that it takes to abstract away persistence layer, logging facility and exception handling. \nWe can now write tests in pure code:\n\n```haskell\n-- setting up test fixtures\ninitReservations :: ReservationMap\ninitReservations = M.singleton day res\n\nday = read \"2020-05-02\"\nres = [Reservation day \"Andrew M. Jones\" \"amjones@example.com\" 4]\n\nspec :: Spec\nspec =\n  describe \"Reservation Use Case (only pure code)\" $ do\n  \n    it \"computes the number of available seats for a given day\" $ do\n      (runAvailableSeats initReservations day) `shouldBe` 16\n```\n\n## The Interface Adapters layer\n\nThis layer holds code for adapters to external resources like databases, message queues, \nconfiguration, Logging, etc.\n\nThe Logging effect `Trace` ships with Polysemy, so we don't have to implement anything here.\n(Of course we could overzealously implement our own Graylog adapter here, but I leave this as an exercise for the reader... )\n\nHowever, as the `KVS` type is our own invention we'll have to provide our own implementations.\n(We could have used the `KVStore` type from [polysemy-zoo](https://hackage.haskell.org/package/polysemy-zoo-0.7.0.0/docs/Polysemy-KVStore.html),\nbut for didactic purposes we will roll our own.)\n\nThe following code is the in-memory \nimplementation from the [KVSInMemory](src/InterfaceAdapters/KVSInMemory.hs) module.\nIt defines a key-value store in terms of `State (Map k v)` that is a `Map k v` in a `State` effect context:\n\n```haskell\nrunKvsOnMapState :: ( Member (State (M.Map k v)) r, Ord k) \n                 =\u003e Sem (KVS k v : r) a \n                 -\u003e Sem r a\nrunKvsOnMapState = interpret $ \\case\n  ListAllKvs    -\u003e fmap M.toList get\n  GetKvs k      -\u003e fmap (M.lookup k) get\n  InsertKvs k v -\u003e modify $ M.insert k v\n  DeleteKvs k   -\u003e modify $ M.delete k\n```\n\nSo whenever the `interpret` functions detects a `GetKvs k` value, that was constructed by a call to `getKvs k` in the use case layer,\nit pattern-matches it to a `Map` lookup of `k` that is executed against state retrieved by `get`.\n \nInterestingly `get` is a smart constructor of the `State` effect. This means that by interpreting the `KVS` we have\ncreated new effects that in turn have to be interpreted. \n\nThe `runKvsPure` functions (which we already have seen in the use case testing) \nchains interpretation of the effects `KVS` and `State` and thus allows us to work with pure Maps as\nmocks for a key-value store:\n\n```haskell\nrunKvsPure :: Ord k \n           =\u003e M.Map k v\n           -\u003e Sem (KVS k v : State (M.Map k v) : r) a \n           -\u003e Sem r (M.Map k v, a)\nrunKvsPure map = runState map . runKvsOnMapState\n```\n\n### A key-value store with a SQLite backend.\n\nAs we are in the interface adapters layer, we are allowed to get our hands dirty with\n*real world code*, like database access. As an example I have provided a SQLite based interpretation of the `KVS` effect\nin [KVSSqllite.hs](src/InterfaceAdapters/KVSSqlite.hs).\n\nThe effect interpreting function is `runKvsAsSQLite`:\n\n```haskell\n-- | Run a KVStore effect against a SQLite backend. Requires a Config object as input.\nrunKvsAsSQLite :: (Member (Embed IO) r, Member (Input Config) r, Member Trace r, Show k, Read k, ToJSON v, FromJSON v)\n                   =\u003e Sem (KVS k v : r) a\n                   -\u003e Sem r a\nrunKvsAsSQLite = interpret $ \\case\n  GetKvs k      -\u003e getAction k\n  ListAllKvs    -\u003e listAction\n  InsertKvs k v -\u003e insertAction k v\n  DeleteKvs k   -\u003e deleteAction k\n```\n\nThe function's type signature introduces a two more constraints on the effect stack type `r`: \n`Member (Embed IO) r` and `Member (Input Config) r`. \n`(Embed IO)` is needed as accessing SQLite will require IO, which can be lifted into the `Sem r` monad with `Embed IO`.\n\nSQLite always needs a file name to create a database connection. As we want to be able to keep this name configurable, we\nuse the `(Input Config)` effect. `\nConfig` is a data type that I created to represent global application configuration,\nincluding the database file name.\n`Input` is a Polysemy built-in effect which can provide input to an application, quite similar to a `Reader` monad.\n\nThese effects are introduced by the actual implementations of the `KVS` constructors, like `getAction k`, which retrieves\na value from the database by looking up the key `k`:\n\n```haskell\ngetAction :: (Member (Input Config) r, Member (Embed IO) r, Member Trace r, Show k, Read k, ToJSON v, FromJSON v) =\u003e k -\u003e Sem r (Maybe v)\ngetAction key = do\n  conn \u003c- connectionFrom input\n  rows \u003c- embed (SQL.queryNamed conn\n                      \"SELECT key, value FROM store WHERE key = :key\"\n                      [\":key\" := show key] :: IO [KeyValueRow])\n  trace $ \"get: \" ++ show rows\n  case rows of\n    []                          -\u003e return Nothing\n    (KeyValueRow _key value):xs -\u003e return $ (decode . encodeUtf8) value\n\n-- | create a connection based on configuration data, make sure table \"store\" exists.\nconnectionFrom :: (Member (Embed IO) r) =\u003e Sem r Config -\u003e Sem r SQL.Connection\nconnectionFrom c = do\n  config \u003c- c\n  embed (getConnection (dbPath config))\n    where\n      getConnection :: FilePath -\u003e IO SQL.Connection\n      getConnection dbFile = do\n        conn \u003c- SQL.open dbFile\n        SQL.execute_ conn \"CREATE TABLE IF NOT EXISTS store (key TEXT PRIMARY KEY, value TEXT)\"\n        return conn\n```\n\nLet's have a closer look at what is going on in `getAction`:\n\nFirst `connectionFrom input` is used to create a database connection based on the `Config` object obtained by `input` \n(the smart Constructor of the `Input` effect).\nThe `Config` type contains a field `dbPath` which is read and used to create the connection with `getConnection`.\nAs this is an IO operation we have to use `embed` to lift it into the `Sem r` monad.\n\nIn the second step `SQL.queryNamed` is used to perform the actual select statement against the db connection.\nAgain `embed` must be used to lift this IO operation.\n\nFinally the resulting `[KeyValueRow]` list is pattern matched: if the list is empty `Nothing` is returned.\nOtherwise `Aeson.decode` is called to unmarshal a result value from the JSON data retrieved from the database.\n\nThe JSON encoding and decoding to and from the DB is the reason for the `ToJSON v, FromJSON v` constraints on the value type `v`.\n\nThis implementation is inspired by key-value store of\n[a password manager in Polysemy](https://haskell-explained.gitlab.io/blog/posts/2019/07/31/polysemy-is-cool-part-2/index.html).\n\n### Declaring the REST API\n\nOur task was to build the backend for the reservation system. We will have to implement a REST API to allow access to the\nbusiness logic that we defined in the use case layer.\n\nThe overall idea is to provide a REST route for all exposed functions of the `ReservationUseCase`.\nThe following table shows the mapping of those functions to the REST routes that we want to achieve:\n\n```\nlistAll        GET    /reservations\nfetch          GET    /reservations/YYYY-MM-DD\ntryReservation POST   /reservations\ncancel         DELETE /reservations\navailableSeats GET    /seats/YYYY-MM-DD\n```\n\nI'm using [Servant](http://www.servant.dev/) to define our REST API.\nThe great thing about Servant is that it allows us to define REST APIs in a typesafe manner by using a\ntype level DSL.\n\nHere comes the declaration of our API (please note that we declare our routes to accept and emit data in JSON format):\n\n```haskell\n-- | in order to allow JSON serialization for the Dom.Reservation type, it must instantiate FromJSON and ToJSON.\ninstance ToJSON Dom.Reservation\ninstance FromJSON Dom.Reservation\n\n-- | Declaring the routes of the REST API for Restaurant Reservations\ntype ReservationAPI =\n       \"reservations\" :\u003e Summary \"retrieve a map of all reservations (Day -\u003e [Reservation])\"\n                      :\u003e Get     '[ JSON] Dom.ReservationMap -- GET    /reservations\n\n  :\u003c|\u003e \"reservations\" :\u003e Summary \"retrieve list of reservations for a given day\"\n                      :\u003e Capture \"day\" Day\n                      :\u003e Get     '[ JSON] [Dom.Reservation]  -- GET    /reservations/YYYY-MM-DD\n\n  :\u003c|\u003e \"reservations\" :\u003e Summary \"place a new reservation\"\n                      :\u003e ReqBody '[ JSON] Dom.Reservation\n                      :\u003e Post    '[ JSON] ()                 -- POST   /reservations\n\n  :\u003c|\u003e \"reservations\" :\u003e Summary \"cancel a reservation\"\n                      :\u003e ReqBody '[ JSON] Dom.Reservation\n                      :\u003e Delete  '[ JSON] ()                 -- DELETE /reservations\n                      \n  :\u003c|\u003e \"seats\"        :\u003e Summary \"retrieve number of free seats for a given day\"\n                      :\u003e Capture \"day\" Day\n                      :\u003e Get     '[ JSON] Natural                -- GET    /seats/YYYY-MM-DD\n```\n\nNext we have to create the connection between the declared routes and the actual business logic. This will be our\nREST service implementation. In our case we simply delegate to the use case controller functions.\nOff course, we might also implement additional functionality here like validation:\n\n```haskell\nimport qualified UseCases.ReservationUseCase as UC \n\n-- | implements the ReservationAPI\nreservationServer :: (Member UC.Persistence r, Member (Error UC.ReservationError) r, \n                      Member Trace r, Member (Input Config) r) =\u003e ServerT ReservationAPI (Sem r)\nreservationServer =\n        UC.listAll        -- GET    /reservations\n  :\u003c|\u003e  UC.fetch          -- GET    /reservations/YYYY-MM-DD\n  :\u003c|\u003e  UC.tryReservation -- POST   /reservations\n  :\u003c|\u003e  UC.cancel         -- DELETE /reservations\n  :\u003c|\u003e  UC.availableSeats -- GET    /seats/YYYY-MM-DD\n```\n\nI really love how **declarative** this code is. **We don't have to tell how** to exchange data between the REST server and\nthe use case controllers.\n\nWe **just tell what we want**: a mapping from the routes to the controller functions.\nThat's all!\n\nIn the following diagram, we now see the third layer. Again, the arrow symbolises the dependency rule, which prohibits\naccess from domain or use case layer to the interface adapters layer.\nTo the left we see the `ReservationAPI` and its `reservationServer` implementation, which we just explored. They interact with\nthe use case controller functions like `availableSeats`, `listAll`, etc.\n\nTo the right we see the interpretations of the `KVS` effect (which was defined in the use case layer): `KVSInMemory`, \n`KVSSqlite` (and also two other implementastions `KVSFileServer` and `KVSAcidState`, which you will find in [the InterfaceAdapters package](src/InterfaceAdapters/)).\n\n![Interface Adapters layer](interface-adapters.png)\n\n### Testing the KVS implementations\n\nWe'll have a closer look at the [test of the SQLite implementation](test/InterfaceAdaptersKVSSQLiteSpec.hs)\nof the `KVS` effect.\n\nAs Polysemy effects are involded we will need to provide an interpretation to actually perform the SQLLite operation.\n\nThe test setup looks quite similar to the tests in the use case layer.\n\nWe want our test to evaluate the KVS implementation independently of the domain logic and the use case layer.\nTherefore, we first define an example use case, featuring a data type `Memo` and a set of typical CRUD operations. The CRUD \noperations are using the `KVS` smart constructors and thus exhibit the typical Polysemy effect signatures:\n\n```haskell\n-- | a key value table mapping Natural to a list of Strings\ntype KeyValueTable = KVS Int [String]\n\ndata Memo = Memo Int [String]\n    deriving (Show)\n\npersistMemo :: (Member KeyValueTable r)  =\u003e Memo -\u003e Sem r ()\npersistMemo (Memo id lines ) = insertKvs id lines\n\nfetchMemo :: (Member KeyValueTable r) =\u003e Int -\u003e Sem r (Maybe [String])\nfetchMemo = getKvs\n\nfetchAll :: (Member KeyValueTable r) =\u003e Sem r (M.Map Int [String])\nfetchAll = fmap M.fromList listAllKvs\n\ndeleteMemo :: (Member KeyValueTable r)  =\u003e Int -\u003e Sem r ()\ndeleteMemo = deleteKvs\n```\n\nNext we define a set of helper functions that allow us to execute the CRUD operations as ordinary `IO ()` actions,\nwhich we can use in our test code:\n\n```haskell\n-- Helper functions for interpreting all effects in IO\nrunPersist :: Memo -\u003e IO ()\nrunPersist memo = runAllEffects (persistMemo memo)\n\nrunFetch :: Int -\u003e IO (Maybe [String])\nrunFetch k = runAllEffects (fetchMemo k)\n\nrunFetchAll :: IO (M.Map Int [String])\nrunFetchAll = runAllEffects fetchAll\n\nrunDelete :: Int -\u003e IO ()\nrunDelete k = runAllEffects (deleteMemo k)\n```\n\nThese wrapper function make use of the `runAllEffects` function that takes a program with effects \nand handles each effect till it gets reduced to `IO a`:\n\n```haskell\nrunAllEffects :: Sem '[KeyValueTable, Input Config, Trace, Embed IO] a -\u003e IO a \nrunAllEffects program =\n  program\n    \u0026 runKvsAsSQLite       -- use SQLite based interpretation of the (KVS Int [String]) effect\n    \u0026 runInputConst config -- use the variable config as source for (Input Config) effect\n    \u0026 ignoreTrace          -- ignore all traces\n    \u0026 runM                 -- reduce Sem r (Embed IO a) to IO a\n  where config = Config {port = 8080, dbPath = \"kvs-test.db\", backend = SQLite, verbose = False}\n\n-- errors are rethrown as Runtime errors, which can be verified by HSpec.\nhandleErrors :: IO (Either err a) -\u003e IO a\nhandleErrors e = do\n  either \u003c- e\n  case either of\n    Right v -\u003e return v\n    Left _  -\u003e error \"something bad happend\"\n```\n\nWith these preliminaries at hand we can now write our test cases:\n\n```haskell\nkey = 4711\ntext = [\"In the morning\", \"I don't drink coffee\", \"But lots of curcuma chai.\"]\nmemo = Memo key text\n\nspec :: Spec\nspec =\n  describe \"The KV Store SQLite Implementation\" $ do\n    it \"returns Nothing if nothing can be found for a given id\" $ do\n      maybeMatch \u003c- runFetch key\n      maybeMatch `shouldBe` Nothing\n\n    it \"persists a key-value pair to the SQLite database\" $ do\n      runPersist memo\n      maybeMatch \u003c- runFetch key\n      maybeMatch `shouldBe` Just text\n\n    it \"fetches a Map of all key-value entries from the KV store\" $ do\n      map \u003c- runFetchAll\n      M.size map `shouldBe` 1\n\n    it \"deletes an entry from the key value store\" $ do\n      runDelete key\n      maybeMatch \u003c- runFetch key\n      maybeMatch `shouldBe` Nothing\n```\n\n### Testing the REST API\n\nThe actual code for testing the REST API looks pretty straightforward. We create a [WAI](https://hackage.haskell.org/package/wai) \n`Application` instance with `createApp` and execute REST operations like `get` and `postJSON` against it:\n\n```haskell\nreservationData :: LB.ByteString\nreservationData = \"{\\\"email\\\":\\\"amjones@example.com\\\",\\\"quantity\\\":10,\\\"date\\\":\\\"2020-05-02\\\",\\\"name\\\":\\\"Amelia Jones\\\"}\"\n\npostJSON   path = request methodPost   path [(hContentType, \"application/json\")]\ndeleteJSON path = request methodDelete path [(hContentType, \"application/json\")]\n\nspec :: Spec\nspec =\n  with (createApp) $\n    describe \"Rest Service\" $ do\n      it \"responds with 200 for a call GET /reservations \" $\n        get \"/reservations\" `shouldRespondWith` \"{\\\"2020-05-02\\\":[{\\\"email\\\":\\\"amjones@example.com\\\",\\\"quantity\\\":4,\\\"date\\\":\\\"2020-05-02\\\",\\\"name\\\":\\\"Andrew M. Jones\\\"}]}\"\n      it \"responds with 200 for a valid POST /reservations\" $\n        postJSON \"/reservations\" reservationData `shouldRespondWith` 200\n      it \"responds with 412 if a reservation can not be done on a given day\" $\n        (postJSON \"/reservations\" reservationData \u003e\u003e postJSON \"/reservations\" reservationData) `shouldRespondWith` 412\n      it \"responds with 200 for a valid DELETE /reservations\" $\n        deleteJSON \"/reservations\" reservationData `shouldRespondWith` 200\n```\n\nPlease note that these tests don't need a deployment of the WAI application to a web server. ALl testing can be done\nwithin  a single process. We stick to the dependency rule not to use anything from a more outward layer.\n\nThe interesting part is the creation of the `Application` instance.\n\nIf we had a simple implementation `myServer` of a REST API `myApi`, not using any Polysemy effects, we\ncould create an `Application` instance like so:\n\n```haskell\ncreateSimpleApp :: Application\ncreateSimpleApp ::= serve myApi myServer\n```\n\nIn contrast, our `reservationServer` has a type signature that contains Polysemy effects:\n\n````haskell\nreservationServer :: (Member UC.Persistence r, Member (Error UC.ReservationError) r, \n                      Member Trace r, Member (Input Config) r) =\u003e ServerT ReservationAPI (Sem r)\n````\n\nInstead of building the `Application` instance directly, as in the simple example, \nwe use `liftServer` to lift `reservationServer` into the required `ServerT ReservationAPI Handler` \ntype by running all effects and by lifting the business logic exception `ReservationNotPossible` \ninto a Servant `ServerError`.\nThis time we also use the SQLite based interpretation of the `KVS` effect:\n\n```haskell\ncreateApp :: Config -\u003e IO Application\ncreateApp config = return $ serve reservationAPI (liftServer config)\n\nliftServer :: Config -\u003e ServerT ReservationAPI Handler\nliftServer config = hoistServer reservationAPI (interpretServer config) reservationServer\n  where\n    interpretServer config sem =\n      sem\n        \u0026 runKvsAsSQLite\n        \u0026 runInputConst config\n        \u0026 runError @ReservationError\n        \u0026 ignoreTrace\n        \u0026 runM\n        \u0026 liftToHandler\n    liftToHandler = Handler . ExceptT . (fmap handleErrors)\n    handleErrors (Left (ReservationNotPossible msg)) = Left err412 {errBody = pack msg}\n    handleErrors (Right value) = Right value\n```\n\n## The External Interfaces layer  \n\n\u003e The outermost layer is generally composed of frameworks and tools such as the Database, the Web Framework, etc. \n\u003e Generally you don’t write much code in this layer other than glue code that communicates to the next circle inwards.\n\u003e  \n\u003e This layer is where all the details go. The Web is a detail. The database is a detail. \n\u003e We keep these things on the outside where they can do little harm.\n\u003e \n\u003e Quoted from [Clean Architecture blog post](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html)\n\nFor the database we are already finished as the [SQlite-Simple](https://hackage.haskell.org/package/sqlite-simple) library\nincludes the SQLLite C runtime library and is thus self-contained.\n\nWe will use [WARP](http://www.aosabook.org/en/posa/warp.html)  as our Web Server, which can be used as a library within\nour `Main` program. \nWhat we still have to do though, is to assemble a Servant web `Application` so that it can be executed on the warp server.\n\nWe have done this step already for the testing of the REST service. The `createApp` function that we define in the \n[ApplicationAssembly module](src/ExternalInterfaces/ApplicationAssembly.hs) will look quite familiar, \nit just provides some more bells and whistles to integrate all the features that we have developed so far.\n\n- `createApp` accepts a `Config` parameter which is used to configure application settings.\n- `selectKvsBackend` selects the concrete `KVS` interpretation.\n- `selectTraceVerbosity` selects the `Trace` interpretation:\n  \n```haskell\n-- | creates the WAI Application that can be executed by Warp.run.\ncreateApp :: Config -\u003e IO Application\ncreateApp config = do\n  return (serve reservationAPI $ hoistServer reservationAPI (interpretServer config) reservationServer)\n  where\n    interpretServer config sem  =  sem\n      \u0026 selectKvsBackend config\n      \u0026 runInputConst config\n      \u0026 runError @ReservationError\n      \u0026 selectTraceVerbosity config\n      \u0026 runM\n      \u0026 liftToHandler\n    liftToHandler = Handler . ExceptT . (fmap handleErrors)\n    handleErrors (Left (ReservationNotPossible msg)) = Left err412 { errBody = pack msg}\n    handleErrors (Right value) = Right value\n\n-- | can select between SQLite or FileServer persistence backends.\nselectKvsBackend :: (Member (Input Config) r, Member (Embed IO) r, Member Trace r, Show k, Read k, ToJSON v, FromJSON v)\n                 =\u003e Config -\u003e Sem (KVS k v : r) a -\u003e Sem r a\nselectKvsBackend config = case backend config of\n  SQLite     -\u003e runKvsAsSQLite\n  FileServer -\u003e runKvsAsFileServer\n  InMemory   -\u003e error \"not supported\"\n\n-- | if the config flag verbose is set to True, trace to Console, else ignore all trace messages\nselectTraceVerbosity :: (Member (Embed IO) r) =\u003e Config -\u003e (Sem (Trace : r) a -\u003e Sem r a)\nselectTraceVerbosity config =\n  if verbose config\n    then traceToIO\n    else ignoreTrace\n```  \n\nThe application assembly also features a function to load a `Config` instance. Typically, this would involve loading\na configuration file or reading command line arguments. We take a shortcut here and just provide a static instance:\n\n```haskell\n-- | load application config. In real life, this would load a config file or read commandline args.\nloadConfig :: IO Config\nloadConfig = return Config {port = 8080, backend = SQLite, dbPath = \"kvs.db\", verbose = True}\n```\n\nWith the whole application assembly written as library code, there is not much left to do in the `Main` module:\n\n```haskell\nimport           ExternalInterfaces.ApplicationAssembly (createApp, loadConfig)\nimport           InterfaceAdapters.Config\nimport           Network.Wai.Handler.Warp               (run)\n\nmain :: IO ()\nmain = do\n  config \u003c- loadConfig\n  app    \u003c- createApp config\n  putStrLn $ \"Starting server on port \" ++ show (port config)\n  run (port config) app\n```\n  \nThe following diagram shows the elements added by the External Interface layer:\n\n- On the left we have application assembly code like `createApp` used by the `Warp` server or some of the different\n  `runPure` functions that we used in HSpec tests.\n- On the right we have the SQLite runtime library that provides access to the SQLite database\n  and the Haskell runtime in general, which provides access to the filesystem and the OS in general.\n\n![External Interfaces layer](clean-architecture.png)\n\n### Testing the application assembly\n\nTesting the application assembly is quite straightforward and resembles the testing of the REST service:\n\n```haskell\nloadConfig :: IO Config\nloadConfig = return Config {port = 8080, backend = SQLite, dbPath = \"kvs-assembly.db\", verbose = False}\n\nspec :: Spec\nspec =\n  with (loadConfig \u003e\u003e= createApp) $\n    describe \"Rest Service\" $ do\n\n      it \"responds with 20 for a first call to GET /seats/YYYY-MM-DD\" $\n        get \"/seats/2020-05-02\" `shouldRespondWith` \"20\"\n\n      it \"responds with 200 for a valid POST /reservations\" $\n        postJSON \"/reservations\" reservationData `shouldRespondWith` 200\n\n      it \"responds with 200 for a call GET /reservations \" $\n        get \"/reservations\" `shouldRespondWith` \"{\\\"2020-05-02\\\":[{\\\"email\\\":\\\"amjones@example.com\\\",\\\"quantity\\\":12,\\\"date\\\":\\\"2020-05-02\\\",\\\"name\\\":\\\"Amelia Jones\\\"}]}\"\n\n      it \"responds with 412 if a reservation can not be done on a given day\" $\n        (postJSON \"/reservations\" reservationData \u003e\u003e postJSON \"/reservations\" reservationData) `shouldRespondWith` 412\n\n      it \"responds with 20 for a first call to GET /seats/YYYY-MM-DD\" $\n        get \"/seats/2020-05-02\" `shouldRespondWith` \"8\"\n\n      it \"responds with 200 for a valid DELETE /reservations\" $\n        deleteJSON \"/reservations\" reservationData `shouldRespondWith` 200\n```\n\n## Swagger Documentation\n\nFor all those who have been patient enough to stay with me until here, I now have a little bonus.\n\nThere is a [servant-swagger-ui addon](https://github.com/haskell-servant/servant-swagger-ui) available \nwhich allows to serve a [SwaggerDoc UI](https://swagger.io/tools/swagger-ui/) for any Servant API. \nThis UI renders an automatically generated documentation of our Reservation API and even \nallows to test all API operations directly.\n\nYou can launch it by executing `stack build --exec PolysemyCleanArchitecture` in the root folder of the project.\n\nThis will launch the REST service and open up the Swagger UI in your Web browser: \n\n![Swagger UI](swaggerUI.png)\n\nThe code for this goody can be found in the \n[SwaggerUI](app/SwaggerUI.hs) module.\n\n\n## Conclusion\n\nRobert C. Martin concludes his blog post with a brief summary:\n\n\u003e Conforming to these simple rules is not hard, and will save you a lot of headaches going forward. \n\u003e By separating the software into layers, and conforming to The Dependency Rule, you will create a system \n\u003e that is **intrinsically testable**, with all the benefits that implies. When any of the external parts of the \n\u003e system become obsolete, like the database, or the web framework, you can **replace those obsolete elements \n\u003e with a minimum of fuss**.\n\u003e\n\u003e Quoted from the [Clean Architecture blog post](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html)\n\nI have emphasized the testability aspect quite a lot in this article. However, this \napproach allows switching freely between alternative backends in production environments as well.\n\nAs we have seen Polysemy \u0026mdash; or algebraic effect systems in general \u0026mdash; make this possible by the separation of\neffect *declaration*, effect *usage* and effect *interpretation*.\n\nFurthermore, Polysemy also allows you to freely combine several effects. This is a huge gain in software composability.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthma%2Fpolysemycleanarchitecture","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthma%2Fpolysemycleanarchitecture","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthma%2Fpolysemycleanarchitecture/lists"}