danidiaz / comments-project

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

What's this

A trivial web application created to test the cauldron dependency injection library.

How to run

After cloning the project repository, checkout the submodules:

git submodule init
git submodule update

Before running the server for the first time:

sqlite3 db.sqlite < schema.sql

Then:

cabal build all
cabal run comments

And navigate to http://localhost:8000/comments.

Useful while developing

ormolu --mode inplace $(git ls-files '*.hs')

Some things to note

  • There is not a central configuration record. Each component registers some configuration bean, which is parsed independently from the raw JSON configuration.

  • Beans often have an "interface" module which defines a record-of-functions type, and an "implemementation" module (potentially more than one) which provides a constructor for the record-of-functions.

    This is not a hard rule; for other beans the record-of-functions and the constructor are defined in the same module.

  • Some bean constructors require the records-of-functions they return to be parameterized by ReaderT env IO, but others (like Comments.Repository.Sqlite.make) could be polymorphic over the monad. But then I would have to specify constraints like MonadLog m, MonadIO m and MonadUnliftIO m so I decided to stay concrete for now.

  • The env in ReaderT env IO is only used for storing request-dependent info, particular to the request's servicing thread. Currently we store the Sqlite Connection allocated to each request, which is set by the Runner.

    Unlike in other application architectures, the reader's env is not used for storing static dependencies (like, say, a logger function). Those are instead passed as regular parameters of the bean constructor functions.

  • Beans don't have to know about their own dependencies' dependencies. The Runner doesn't care that the CommentsServer uses a CommentsRepository for example.

  • At the composition root of the application, all types are known. It's a good place to add extra logging (using a decorator) without touching the bean implementations.

    Because the composition root sits near the top of the module dependency chain, recompilations after having modified it should (?) be fast.

Links

About

License:Other


Languages

Language:Haskell 96.5%Language:CSS 2.3%Language:HTML 1.2%