idioms
the compiler settles most questions of style. names are snake_case, a predicate's name ends in ?, declarations go in one order, and whitespace has one rendering. appendix c lists those rules and appendix a the messages that enforce them. this appendix covers the decisions the compiler leaves to you. each entry states a rule and names the chapter that argues for it, where you can see it run.
ask about shape with an arm, and about content with if
when the question is which kind of value you have, write one arm per kind. a new kind is then a new arm beside its siblings, and no other code changes. when the question is about one value's content, such as whether a number is negative, use if. there is no else if. a third case is a nested if, or more often a sign that the question was about shape after all. chapter 03 makes the case in "if is for content, dispatch is for shape".
none for a question, a marker for a verdict, err for a refusal
a function that may not find what it was asked for answers none, and the caller handles it with an arm. a function that reaches an answer its caller will act on, such as "this is not a flag", returns a marker type named for that answer. a function that cannot do its job, and will not hand the problem to its caller, makes an err with a reason. use err last: only a caller in another module can rescue it, and the report a user reads names your function, so write the reason for them. chapter 04 covers all three in "none is for asking" and "designing the sad path".
keep the decisions pure and the i/o at the edge
put the logic in functions that take values and return values. put reading files, arguments and standard input in one small file that hands those values in. the pure functions are tested by calling them, and nothing has to be faked. wordfreq keeps all of its i/o in cli.kso. the web service's handler takes a request and the current state and returns a response and the next state, so its tests call it like any function. chapter 05 explains why in "testing without mocks", and chapter 09 and chapter 10 build both programs.
let order come from data
a value reaches the next step only through a name or a .>. lines that do not depend on each other go side by side as bare lines, and they run as green threads. write .> (_ -> ...) only where a step must wait until the steps before it have finished without failing. each one you add where nothing depends on it makes two pieces of work run one after the other when they could have overlapped. chapter 06 sums up the model in "the whole model in five lines".
keep a chain a recipe until you need a list
adapters such as map and select return a recipe. a consumer at the end runs the whole chain as one loop, and no list is built between the steps. call list/to_list only when the result has to be a list, which is usually just before you print it. find, all? and any? stop at the answer, so they are also the cheap way to ask a question about a long sequence or an infinite one. chapter 08.
show callers as little as you can
a top-level name is private until you mark it pub, so a module's surface is exactly the names you marked. mark what a caller needs and leave the helpers bare. tests live in _test.kso files beside the module and see only what an importer sees. when a test seems to need a private name, either the name belongs on the surface or the test belongs on a public function that uses it. split a module into files by job: its files share one namespace, so a split adds no imports. chapter 07.
a project is an entry and a module
put the entry, main.kso, at the top of the project directory and give it one job: handing the arguments to the module. name the module something other than the project, because kanso build names the binary after the project directory and will not write a file beside a directory with the same name. chapter 09 lays one out in "the layout".
count before you time
to compare two versions of a program, run each with KANSO_COUNTERS=1. the counts it prints come out the same on every run, so a difference is the change and nothing else, and a cost golden that ci compares exactly will catch a regression of a few percent. time the program last, on a release build and a large input, several times, to see which way a change went and roughly how far. chapter 11.