TIL, 2018-04-04, Result Objects and Callee.
Musings, JS and React
- Formspree is awesome!
- HTML5 form validation is okay as a first declarative validation layer.
Musings, Ruby
undef_method
: Only in class definitions, you can probably use this in a file.- Getting method names:
__method__
to get the name of the method, good for passing to another abstraction thing.__callee__
looks up the name dynamically and refers to the name under which the method was called.
- Updating with bang methods:
ActiveRecord::RecordInvalid
inheritsActiveRecord::ActiveRecordError
, which inherits fromStandardError
.- When updating via
update_attributes
, we getActiveModel::Errors
, notActiveRecord::RecordInvalid
.
- Is the adapter design pattern an Anti-corruption layer?
- Single vs Multi-tenant SaaS:
- Create a database, provision some servers, add a load balancer, add some caching, and call it a day.
- Any-scale system: a system that’s built to remove scale from that equation.
- Multi-tenant: Load balancer, gateway, subnets, kinesis, lambdas, Redshift…
- Multi-tenant: Teams share resources. Higher cost up front but each new cx doesn’t really cost much.
- Single-tenant: More expensive except for the human aspect.
- At Kumu, every project is backed by a CouchDB database.
- Rubocop tells us to put mixins in separate attachments.
- Ruby and Amazon Lambda: Currently, it doesn’t support Ruby, but you can use it as a go-between for your S3 to Rails use case.
lambda
or proc?- Flaky Ruby tests:
- Capybara: Avoid dangerous methods that do not wait:
visit(path)
andcurrent_path
,all(selector)
, accessors (text
,value
,title
). Use safe methods that do wait:find(selector)
,find_field
,has_selector?
. - DB pollution:
database_cleaner
: transaction vs truncation. Truncation is required when running request specs with Capybara. The thread running your Rails server uses a separate database connection from the one running your test. - Non-deterministic attributes: Don’t use faker, just hardcode.
- ID-dependent things: When tests run in a transaction, the auto-increment value still runs. Truncation = auto-increment will be reset.
- To reproduce: run RSpec using the same seed, run the entire list of files, use the
--bisect
flag.
- Capybara: Avoid dangerous methods that do not wait:
- Sentinel value: “A special value in the context of an algorithm which uses its presence as a condition of termination.”
Result Objects: Errors without Exceptions
- Resonad gem:
- Errors are part of the return value, not an exception.
- Expected errors are available through
result.error
, and unexpected bugs are exceptions. - All expected error cases are automatically “caught”, without having to guess what they are.
result = register_new_user(params)
if result.success?
handle_success(result.value)
else
handle_failure(result.error)
end
- When not to use:
- When the method should always succeed.
- When there is only a single failure case, just return
nil
or whatever. - If you can recover Locally, and you can just return a Null Object.
- Result objects are appropriate:
- When an operation can fail in multiple different ways.
- When operations need to be chained together, and each individual operation can fail.
- When it’s important for callers to know that the method can fail.
- Works with service/interactor/command objects.
-
Implementation:
Resonad
, dry-monads, Github::Result,monadic
,result-monad
. - Refactoring to data: “This is an example of what I call “data-driven design” or just “thinking in data”. All the specific details are described in data: numbers, strings, arrays, hashes, structs, etc. All the behaviour (i.e. the implementation) is generic, and controlled by the data.”
- When thinking of inheritance, ask yourself if it is possible to think of the inheritance chain in terms of just data (array, hash, and do a concretion based on that).