Library
Module
Module type
Parameter
Class
Class type
Sihl is a framework for building applications with OCaml and Reason.
Check out the tutorial to get started.
Following section outlines the design goals, features and main ingredients of Sihl.
Following five design goals guide Sihl's development.
The overarching goal is to maximize developer happiness. We think it is crucial to like the tools that we use.
This goal is about minimizing the gap between early speed of development and long-term maintanability. Combine functional programming, strict static typing and a modular architecture to quickly build systems that you are not afraid to touch. Thanks to the fast compiler, incremental build time is measured in milliseconds. Run your tests often and quickly. Omit type declarations while prototyping and let the compiler infer the types for you. Once the APIs settle, the compiler infers interfaces.
Apart from a tiny core that deals with dependency injection, everything is built using services and plain functions, even built-in in features. Compose your apps by picking functionality, one by one.
Many frameworks rely on complex macros at compile-time or reflection at runtime to offer ergonomic APIs. Sihl tries to minimize this sort of magic by making things explicit.
Sihl provides consistent and sane defaults while allowing for customizations. Get started with your project and fine-tune your BCrypt rounds and database connection pool sizes later.
Here is a list of some of topics that Sihl is concerned with:
The "framework" is not only the code in the GitHub repo, but also documenation, concepts and architecture. Sihl consists of four parts.
The OCaml ecosystem has many wonderful libraries that are often wrappers around battle tested C libraries. Sihl provides a consistent API on top with sane defaults for web development. Examples are: base64 encoded random byte generation, JWT encoding/decoding, BCrypt hashing, UUID generation.
This document describes an architecture following principles of Domain-Driven Design. You are free to use any other architecture and to pick the parts of Sihl that you need.
Everything is built using services, even built-in functionality. Sihl provides a set of service interfaces and default implementations for common tasks in web development like email sending, job queues, block storage and migrations. Implementing those interfaces is one of the main ways to extend Sihl.
To be 100% honest, there is a tiny core that deals with service dependency injection and life cycle management. But that's it, everything else is using that mechanism to provide its functionality! // TODO link to source of tiny core as a proof
Install opam according to this.
Sihl has not been released to OPAM yet, we plan to release it in the coming days.
Run opaminstallsihl
.
TODO Provide starter skeleton as git repo
TODO
TODO
TODO
On order to navigate the code base of provided Sihl modules and to make most of this documentation, there are some concepts that you need to familiarize yourself with.
Make sure you understand conceptually Option
, Result
and Lwt. You should also familiarize yourself with the basic API of those modules.
TODO vs. null/absence of something
TODO no exceptions, just result
Sihl uses Lwt to do non-blocking I/O. Because we assume that any I/O might fail, almost every API has nested Result.t
inside Lwt.t
like so ('a, 'e) Result.t Lwt.t
. This is in fact so common that Lwt provides a helper module Lwt_result.t
to ergonomically handle the nested Result.t
.
Since OCaml 4.08.1, the language has built in support for let*
syntax. This is similar to async/await in other languages like JavaScript. Sihl makes extensive use of this new syntax to flatten Lwt chains. This is a good primer.
This allows us to express domain logic without obfuscating it with noise that is caused by asynchronous operations.
TODO show common patterns:
TODO show file system