3 ms·
Thank for such a long and very detailed comment. I'll try to explain our design goals. I think the main difference is that mortar is heavily based on Dependency
by go-masonry 6y ago
Thank for such a long and very detailed comment. I'll try to explain our design goals.
I think the main difference is that mortar is heavily based on Dependency Injection (uber.Fx) and this affects a lot.
If you want you can have multiple instance of the Logger interface, just 'name' the instance and FX will help you inject the one you like. https://godoc.org/go.uber.org/fx#Annotated https://godoc.org/go.uber.org/fx#Annotated
This makes it's extremely easy to inject any instance anywhere you like.
What is not mentioned on the main page is the Builder approach we use https://github.com/go-masonry/mortar/blob/master/wiki/builder.md https://github.com/go-masonry/mortar/blob/master/wiki/builde...
This allows to partially configure any concrete implementation ahead of time, say in some company-platform library and the developer will only need to "Build" it in the final project or adjust parameters if needed.
This project is actually a second version of an internal project we created at Here Mobility, eventually this design helped us to increase developer velocity by introducing
- a unified project structure
- devops preconfigured libraries to help integrate the services within our internal cloud setup
- we had several groups and each had more than one products with backends so we needed to allow every group to develop the way they wanted, but at the same time maintain company standards and devops practices. It's not easy to make sure all your company services are aligned to the same versions unless you work on top of mono repo and we didn't.
Mortar design goal was some what a compromise to allow customization but if not a good and reliable standard.
- jrockway 6y agoYeah, having that sort of framework is essential. It is enough work to add all the instrumentation (and ancillary concerns, like authorization/ACLs) that people will not do it if there isn't a framework for it, and of course the interesting bug will be in the component that wasn't instrumented. Easier to get it right once, and then everyone at your org gets it for free. I haven't really found a way of doing dependency injection that I like. I did a lot of Java in a past life, and the dependency injection framework made it too easy to give unrelated components data they shouldn't have had access to, which ends up making testing (and debugging) a nightmare. (But, I don't miss all those functions that injected a clock instead of calling time.Now. Much easier to test!) Ultimately, I decided to just "manually" do it every time, which is tedious but easy to read. In the future, I may explore codegen on top of gRPC (to unpack things from the context, like the authenticated user, logger, etc. and pass those to handlers that take those as explicit parameters, so tests need less work to setup.) As for monorepos, I am upset whenever I don't have one. For example, I hate that my open source projects are all in separate repositories -- it means there are n places to collect bug reports, n places to write CI rules, n places to write release scripts, etc. As a result, things get missed, and some things fall out of sync with whatever my current "best practices" are. (Sometimes I fear that we have created a new class of software engineer to manage all these concerns, when the computer could be doing it for us with just a little extra tooling.) The actual code is easy to share, but all those ancillary concerns are a huge time sink.