Work in Progress.
Unlike Django & Rails, chi
does not enforce
structure. This is an attempt to layout such a structure.
models/
views/
services/
app/
config/
middleware/
auth.go
templates/
public/
main.go => main() & init()
Makefile => run app, run tests,
# generated by Makefile
_build/
- Initializes logging
- Runs Gorm migrations
Pulls the app (app/
) and starts the http listener.
Optional flag is used to start docgen. See here for an example.
HandlerFuncs should always be lowercased (i.e. "private") with the first word being the method (e.g. "POST", "GET", "PUT", etc).
Template names should be prefixed by the dominant model if there is one.
E.g. post_detail.html.tmpl
, post_list.html.tmpl
,
post_new.html.tmpl
, etc.
Optimization is the root of all bugs. That means gorm
is leveraged without
any functions on top (e.g. no GetPostByUuid(...)
). In the future, you'd
probably remove this so as to leverage raw SQL queries.
We can, in fact, share the database
object. This is because, under
the covers, Gorm uses
the sql.DB
which explicitly
allows for this. It will create and free connections internally. More
docs here.
Write utility functions! Type enforcement becomes annoying with golang.
POST/PUT/PATCH requests will all need a Content-Type: application/x-www-form-urlencoded
added to the header.
It's not worth testing every folder. One of the folders that really
doesn't matter is /templates
.
Functions should do one thing and with little to no side effects. This makes it easy to follow logic around. Tests are an exception! They can test multiple functions at once. This is allowed because it more closely resembles how your program works. It also allowed for daisy chaining how functions can work (e.g. you create and then query, which might be testing two separate operations). In practice, your tests should run entirely correctly or not at all so any breaking functionality will break a test somewhere that you can then diagnose and fix.
Two linters are used: staticcheck
and golangci-lint
. Both are given stock configurations but can be configured to taste.
The list of available checks for staticcheck
are listed here.
The list of available checks for golangci-lint
are listed here. Unlike staticcheck
, it is not installed by default via the make install
.
If using encryption, encryption keys need to be exactly 16, 24, or 32. Authentication keys can be any length.
Views (views/
) take in the request, pass all business logic to the
controller (services/
) which can use models (models/
) to persist
and modify the underlying data. They then return to the view, which
populates a template (templates/
) -- or not -- and returns a
response.
Views never handle business logic. That is solely the job of a service. This makes it easier to not only debug but also build because we can "stub" out the business logic when making sure the view logic looks correct.
The solely exception to above are value for templating. This includes the count of a list of posts submitted.
See TODO.md
-
Write tests for models as examples of what to do, don't bother with special functions to do specific work because you don't know the domain space yet
-
using names to make sure that pieces don't get accessed outside of where they should (app.session)
-
do you test that auth works or not? Only for end-to-end. Because services are separated from routes, this means you can test business logic separately. A helper function should be written for making the authentication process simple.