1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
|
Omni.Dev is the namespace for development. Here we define the tools and
infrastructure for internal dev work.
# Goals of the workflow
- have minimal ceremony
- default to asynchrony, but allow for synchronous work when necessary
- automate the boring stuff
- standardize environments, tooling, and versions to minimize friction
while collaborating
- support the longevity and self-sustainability of the project
Ideally, each contributor should be able to go off grid for a day or a
week or more, continue working offline, submit their work when finished,
and have no or minimal conflicts. This also refers to the resilience of
the production systems.
We should never need "out of office" email auto-replies, or urgent
contact. No pager duty, no daily stand-ups. Yes, this policy will affect
what code we write, not just how we write it; that is by design.
# Getting started
Jump into a development shell:
nix-shell
Then run `help` to see the dev commands.
# Repository organization
The source tree maps to the module namespace, and roughly follows the Haskell
namespace hierarchy (although nothing is enforced).
The namespace for all products that we own is `Biz`; proprietary applications,
products, and related infrastructure lives under there. The `Omni` namespace is
used for internal development tooling and infrastructure that are not related to
individual products. Stuff that can be open sourced or otherwise externalized
should be outside of `Biz` or `Omni`.
Development aspects should be localized to their sub-namespaces as much as
possible. Only after sufficient iteration such that interfaces are solidified
and functionality is well-established should some code be promoted up the
namespace hierarchy.
Start with small namespaces: use `Omni/Thing.hs` before `Omni/Thing/Service.hs`.
Try to keep all related code in one spot for as long as possible.
Boundaries and interfaces between namespaces should be singular and
well-defined. Likewise, the functionality and purpose of a particular
namespace should be singular and well-defined. Follow the unix principle
of "do one thing and do it well."
Namespaces are always capitalized. I would prefer always lowercase, but `ghc`
_really_ wants capitalized files, so we appeas `ghc`. In Scheme and Python this
actually translates quite well and helps distinguish between types/classes and
values.
File extensions denote _type_ and indicate to the build system how to
handle the file. So for example:
- `.hs` is Haskell source code, the build system compiles it
- `.scm` is Scheme source code, ditto
- `.jnl` is a journal for accounting, the build system will check our
balances, make sure we're profitable
- `.md` for notes and docs, mostly ignored by the build system
# Setting up remote builds
The `Omni.Dev` machine acts as a remote build server and Nix cache. To use it from
your local machine, your public key must be at `Omni/Keys/$USER.pub` and your
user added to `Omni/Users.nix`, then bild will automatically use your key to run
builds on `Omni.Dev`.
To use distributed builds for all nix commands, add the following to your NixOS
configuration:
nix = {
distributedBuilds = true;
buildMachines = [
{
hostName = "dev.simatime.com";
sshUser = "yourUserName";
sshKey = "/path/to/your/private/key";
system = "x86_64-linux";
supportedFeatures = [
"x86_64-linux"
"big-parallel"
];
}
];
};
|