treehouse/content/programming/opinions.tree

162 lines
7.6 KiB
Plaintext
Raw Normal View History

2023-10-03 15:05:12 +02:00
% id = "01HBTSXTTAAAHGKD4TZZW14KFK"
- "bad opinion zone"
% id = "01HBTSXTTAMWJ2BM6395YS72FN"
+ log verbosity levels are stupid
% id = "01HBTSXTTA946PJ04NN50P393T"
- because when should you use any log level other than `error`, `warn`, or `info`?
% id = "01HBTSXTTAA873BYW2X3499W4P"
- for debug info that doesn't affect most users, there will always be lower verbosity levels
than `info`, but in my experience these are *always* extremely specific, and clumping them
all into `debug` or `trace` doesn't make much sense
% id = "01HBTSXTTAQ9S7Q1SSPN0BCG8F"
+ in that case I believe it is better to declare separate channels that can be filtered individually, and use `info` for everything
% id = "01HBTSXTTAHCQ5YH1FZT3WKNTZ"
- you say `info` sounds wrong for debug info? well,
% id = "01HBTSXTTATA4GW13QBC8YMWP1"
- guess what, it's debug ***info***
% id = "01HBTSXTTANNMHXDGG1M4W70XN"
- the very concept of logs is to dump a load of (debug) info for later analysis,
so making some distinction between debug and non-debug info while logs are
_inherently_ for debugging seems a little silly to me
% id = "01HBTSXTTADJCTV9RTWT4NPASS"
+ use severities instead of verbosities
% id = "01HBTSXTTA3KN26DS4QMPSHEEC"
- `error` is "OH SHIT OH FUCK UHHH"
% id = "01HBTSXTTATK9W0TRGM50SKWRE"
- `warn` is "ding ding ding! something ain't right, but I'll carry on"
% id = "01HBTSXTTA8Z5JJHFKH4T88G0B"
- `info` is just that - info
% id = "01HBTSXTTANQXBN7FQQSBXTSB1"
- and there is really no need for anything lower, because guess what: [`debug` and `trace`](https://docs.rs/tracing/latest/tracing/struct.Level.html)
and [`Display` and `Verbose` and `VeryVerbose`](https://docs.unrealengine.com/4.26/en-US/API/Runtime/Core/Logging/ELogVerbosity__Type/)
and what have you - they're all just more `info` for you
% id = "01HBTSXTTAE94HEE60GZFBEAW7"
- and while writing logging code it's always hard to decide which info should be
stuffed into which verbosity, because which info will be interesting to you at the
time you read logs depends on what you're looking for at a given moment
% id = "01HBTSXTTAKZ3MKD3EJPX84J9N"
+ this is something I haven't tried yet, but one day I wanna build a logging framework one day that associates severities with whole categories rather than individual log messages
% id = "01HBTSXTTAD4TQ0A8JP71KZMXA"
- but at that point, do we even need severities at all? would a hierarchy of categories suffice?
% id = "01HBTSXTTAW160GH44JV3JYV3Y"
- I have no clue how well that will work but it would be pretty interesting
% id = "01HBTSXTTASQDZK2HMCZXR3JJ4"
+ tracing is better than logging
% id = "01HBTSXTTA08SCA313HSFWB13T"
- information about time spans is very valuable for profiling
% id = "01HBTSXTTAAHQ0Q8GY78Z1RYFN"
- and you do not have to worry about "should I log before I start the operation, or after I end the operation?"
% id = "01HBTSXTTAJ6R319P2N6HT54CA"
+ additionally, traces made of spans are way easier to visualize than tonnes of logs
% id = "01HBTSXTTA3M93STVPHA898GM4"
- if you've never tried [Perfetto](https://ui.perfetto.dev/) or similar tools, I highly recommend giving it a shot
% id = "01HBTSXTTAB9WD17FNDE5RYP8Y"
+ I also imagine visualizing traces live in your CLI could yield a very nice user experience,
with a visible progress indicator as to what eg. [your compiler][branch:programming/projects/muscript]
is working on right now at a glance, reassuring you that it is not stuck on some
`while (true) {}` in constant evaluation
% id = "01HBTSXTTA3Q36Y98GSBRVCS3B"
- perhaps emitting warnings along the road for things that take alarmingly long, so that you
can keep your build times in check
% id = "01HBTSXTTAA89CXD17GBNR3FEQ"
- though printing to stdout is quite slow, so perhaps limiting the frequency or depth would
be a worthwhile thing to do
2023-10-10 19:09:24 +02:00
% id = "01HCD90XT3G0J8G9Y48H5QT1GJ"
+ don't use [`RefCell<T>`](https://doc.rust-lang.org/std/cell/struct.RefCell.html)
% id = "01HCD90XT3X82R37WTJJABZF4Y"
+ usually if you have to resort to `RefCell<T>`, it means something is wrong with your architecture
% id = "01HCD90XT3QQA9MCB77Q04W148"
- `Cell<T>` less so but still you should avoid it whenever possible
% id = "01HCD90XT36Q0WTZNRCEWZQE1X"
- `Rc<RefCell<T>>` is an immediate red flag when I read someone's code. it means they don't
really know what they're doing and are just trying to sidestep the language
% id = "01HCD90XT3QNZ7H77Z4QMW66QJ"
- it's really not that hard to avoid, try bumping your resources up a scope and borrow them
from there
% id = "01HCD90XT32M4F61W5QRRRXG0K"
+ using `RefCell` has a few disadvantages
% id = "01HCD90XT3R214HQM03TSRZV6K"
+ first, `RefCell` is _literally_ turning off the borrow checker
% id = "01HCD90XT3V4K4RKRQXX5BCCRB"
- or really deferring it until runtime, but then what's the point. Rust's borrowing
rules are meant to prevent bugs, not cause more of them
% id = "01HCD90XT3DVTHP82Z5NAAF7RP"
+ second, your program can now panic in unexpected places, because it turns out runtime
borrows can be really hard to predict
% id = "01HCD90XT34QD8MCN0BA35AV0F"
- as evidenced by a random crash I once got while using [druid](https://lib.rs/crates/druid)
which was caused by a overlapping mutable then immutable borrows at runtime
% id = "01HCD90XT39NZ0BSY630MFNG1X"
- therefore maybe uhhh... don't use it in libraries? :pleading:
% id = "01HCD90XT3GT9G16EQDAK76WEC"
+ third, it incurs a runtime overhead for the borrow checking, which in 99% of cases is
totally unnecessary
% id = "01HCD90XT3V3B1TVPX7GS8SPDQ"
- (this is more about non-pessimization rather than premature microoptimization, so
don't yell at me with your "it'll be fast enough" arguments please)
% id = "01HCD90XT37138S38DN0V3DKHF"
+ fourth, and this one is extremely easy to spot - your code becomes really verbose!
% id = "01HCD90XT3WNGWD4GA2Y63D42H"
- yes please, `.borrow()` me everywhere!
% id = "01HCD90XT361QQB2YNFBY51N2A"
- and you end up with lots of temporaries because of the [`Ref<'b, T>`](https://doc.rust-lang.org/std/cell/struct.Ref.html)
guards you have to keep in scope.
% id = "01HCD90XT34K9BREXAKA5FFP3M"
- remember that you cannot do `&ref_cell.borrow().some_field` because that would
drop the temporary `Ref<'b, T>` guard after the expression ends
2023-10-11 22:42:33 +02:00
% id = "01HCG7KTGGAFS07QYJXZG6WHJJ"
+ `None` or `Invalid` cases in enums are a bad idea
% id = "01HCG7KTGGHWTT1ME9GQ5VPFPR"
- by having them, you're forcing your users into an API that forces them to think about the
invalid case every time they read the value.
% id = "01HCG7KTGGBJRX5JGQTFD59P4W"
- you're repeating the million dollar mistake - `null`
% id = "01HCG7KTGGYQ8EQB97AMFJPWYK"
- instead, use an explicit `Option<T>` or `std::optional<T>` or `T?` or ... when you need
to represent a possibly-invalid case