Replies: 2 comments
-
I like the sound of using a guard library, since we effectively do it already, and it makes code a bit more readable. Also, it is typical to use function/method guards in GTK/C code. For example, GtkLabel's implementation: // gtklabel.c - Line 1915
// From: https://gitlab.gnome.org/GNOME/gtk/-/blob/master/gtk/gtklabel.c#L1915
const char *
gtk_label_get_label (GtkLabel *self)
{
g_return_val_if_fail (GTK_IS_LABEL (self), NULL);
return self->label;
}
As for which library, I like the look of LiteGuard because it's small enough that we could maintain it in-tree if we ever needed to. Thoughts @na2axl?
I'm happy to do this with pure functions because it can make code much clearer. One point I'd like to make is that I'm strongly against nesting non-pure (e.g. stateful) methods though. If we're going to be changing and updating class variables, this should only happen in the top-level method being called, so the behaviour of the method is clearly visible, even if it means unnecessarily long functions. Using pure functions tends to make code more reliable and testable, and I've caught myself early on several issues by doing it this way. Here's a good read that illustrates what I mean. |
Beta Was this translation helpful? Give feedback.
-
This got obsolete with .NET 6 and nullable reference types. |
Beta Was this translation helpful? Give feedback.
-
I found the LiteGuard library which is from the author of our already used libraries SimpleExec and Bullseye.
With my recent commits I started to try to bring more readability to code. I try to stay at the same logical level inside one single method. Meaning if one method is generating some code through e.g. a Scriban template there is another method which checks the input, and another one which generates a template object and another that finally creates the template string and so on. This means the reader of this high level method does not need to know the details of the called methods (even if it is just one line of code in the called method).
E.g. from the new
TypeDescriptorRegistry
:In this way I try to keep the readers mind clear of obfuscation. This supports better code separation and better reusability of those methods as they are simple and just fulfill one task.
Now I wonder what to do with constructors like the
Generator
one:Especially if we imagine there are multiple dependencies defined in the constructor the code will be quite cluttered just because it is very unreadble. After some time one will become used to it and just ignore those line and not consider them. But somehow they are distracting.
LiteGuard (MIT License) offers a Syntax like:
This would split the "Guarding" and the assignment in two rows which is more lines of code but from my point of view it is a lot better to read.
The following code is just copied from the samples of some different projects which have the same goal but at least from my point of view do not improve the readability that much. I prefer LiteGuard because of it's simplicity.
There are other libraries like Guard:
For me this is still quite cluttered.
Another library GuardClauses:
I like the first approach. This approach has minimal more overhead compared to LiteGuard as there is the
Against
object used. The good thing about this is that it allow us to write some extension method to provide our own guardings.But actually from my own experiences of writing/generating a whole lot (I suppose multiple hundreds) of those
throw new ArgumentNullException
constructs I never came across guarding some actual values in constructors.If for example a price of zero is not allowed the actual classes which calls our imaginary
Order
class should make sure there is no price of 0 (what the code probably does).The guard clause would only protect us in case of a bug in the callers class but then the app would crash with the guard clause. The solution to this would be unit tests, which make sure the caller provides the correct amount and not the guard clause.
In case the customer want's some day to have products for a price of zero we would need to remember this guard clause because just adopting the logic in the calling class would not be sufficient because of our Guard which would crash us.
@firox263 @na2axl What do you think of introducing some gaurd library in general and LiteGuard as a concrete implementation?
Beta Was this translation helpful? Give feedback.
All reactions