429 karma · joined November 17, 2018
The previous posts were about why I'm doing it and how to setup an authoritative DNS server [0], and how I monitor these machines [1].
This post provides an overview of how I automated the deployment of these servers.
[0]: https://www.joshmcguigan.com/blog/run-your-own-dns-servers/
[1]: https://www.joshmcguigan.com/blog/low-cost-infrastructure-mo...
The idea is, by explicitly marking things which can be null (wrapping them in an Option[T], for example), you can be sure that everything else is not null. This alone relieves the developer of a large cognitive load.
Further, the language can provide syntax to make handling optional types obvious without being painful. Rust match statements are one example of this.
Can you provide a specific example of how using an optional type makes a potential "missing-thing" type of bug harder to see?
Optional[T] exists to make it very obvious when a value is nullable. Having non-nullable types as default, with Optional[T], allows a developer to model a system more accurately. This is helpful both to the compiler as well as anyone else who reads/maintains that code.
> Imagine, for example, in an Optional based language, that you just map the optional to a lambda to execute on the optional, and the behaviour of the optional is to then simply silently do nothing if it's optional.none. That'd be a much harder to find bug than a nullpointer error. (errors with stack traces pointing at the problem are obviously vastly superior to mysterious do-nothing behaviour with no logs or traces of any sort!).
This is just one of the things a developer could decide to do when faced with an optional which is none. It is up the language design to make it easy to express this behavior (or any other behavior they might choose) without hiding it.
[0]: https://doc.rust-lang.org/std/primitive.f64.html#method.powi
So it sounds like it is not so much the allocation/de-allocation savings that matters, but rather that you get to skip initializing the memory because it is already known to be a valid instance of a given struct type?
As someone not very familiar with systems programming, I would have expected this is an optimization that would already happen automatically within the system memory allocator. Is that not the case?
This blog post outlines why and how I run my own authoritative DNS servers.
[0]: https://www.folklore.org/StoryView.py?story=Calculator_Const...
Not sure if OP is here, but I'd be interested in hearing about which debug options are easily exposed on that board. Can you use the port you are flashing the drone with as a standard serial port after your code is loaded? Looking forward to the future post about SWD that is introduced at the end of this post as well.
[0]: https://www.joshmcguigan.com/blog/betafpv-drone-flight-contr...
[1]: https://www.joshmcguigan.com/blog/betafpv-drone-flight-contr...
Can you talk more about the data infrastructure?
I find this idea to be very effective, as long as the scope can be kept to a minimum (think MVP). I've seen it work not only for CLI apps, but also for simple HTTP API servers.
Hmm, this is interesting, and something I hadn't thought of before. I'd probably try to solve it with a combination of the newtype pattern (create wrapper types for `MyThing`, like `MyThingJson` and `MyThingToml`) and the Serde flatten attribute. Then you could, for example, add `#[serde(rename_all = "lowercase")]` to the `MyThingJson` struct and `#[serde(rename_all = "snake_case")]` to the `MyThingToml` struct.
I haven't tested this though, so I'm not sure if the `rename_all` would flow through the flatten attribute as expected. Worst case you could duplicate the struct (or more likely, find or build a macro to do it for you) rather than use the newtype/flatten technique.
As a specific example, I take the use case of understanding how keypresses are handled within Alacritty [3], a terminal emulator written in Rust.
[0]: https://www.youtube.com/watch?v=dSqLt8BgbRQ
[1]: https://github.com/SimonKagstrom/kcov
One question about the code, why does the LedPanel struct use a String as a buffer rather than using a Vec<u8>?
edit - I think I see the reason now. Using a string made it easy to print the u8 as a string of bits, which you could then iterate over using chars. This was used to help perform the conversion from bits directly representing colors to the on the wire representation.
Generally, my process for writing is google around until I have some base level of knowledge, then building one or more demo applications to ensure my understanding is correct. Then as I'm writing the blog post I'll be refining the demo applications into examples for the blog post and/or library code that I want to open source.
[0]: https://www.gnu.org/software/bash/manual/html_node/Programma... [1]: https://www.gnu.org/software/bash/manual/html_node/Programma... [2]: https://hackaday.com/2018/01/19/linux-fu-custom-bash-command... [3]: https://github.com/scop/bash-completion [4]: https://github.com/git/git/blob/master/contrib/completion/gi...
In any event, thanks for bringing this up.
Thank you for the detailed feedback.