-
Notifications
You must be signed in to change notification settings - Fork 97
Improve Documentation for internal facades #1413
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve Documentation for internal facades #1413
Conversation
fairroot/base/steer/FairRun.cxx
Outdated
void FairRun::FillEventHeader() | ||
{ | ||
if (fSource) { | ||
fSource->FillEventHeader(fEvtHeader); | ||
} else { | ||
LOG(warning) << "FairRun::FillEventHeader: No Source!"; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First, a pure stylistic suggestion:
void FairRun::FillEventHeader() | |
{ | |
if (fSource) { | |
fSource->FillEventHeader(fEvtHeader); | |
} else { | |
LOG(warning) << "FairRun::FillEventHeader: No Source!"; | |
} | |
} | |
void FairRun::FillEventHeader() | |
{ | |
if (!fSource) { | |
LOG(warning) << "FairRun::FillEventHeader: No Source!"; | |
return; | |
} | |
fSource->FillEventHeader(fEvtHeader); | |
} |
The idea is to not use an explicit block for the else case by default to reduce the amount of blocks (indented code). Then there is a choice what to put inside the remaining block - here I followed the idea to keep the "good"/"healthy" code path without blocks and the "exceptional"/"special cases" in the conditional block. At least to me, this style improves readability. What do you think?
The next comment may very well be out of scope of this PR, but I make it anyways, while at it; if you like it, we can pick it up later:
Using logs to communicate program logic errors feels off. I would like to propose to promote the warning into a "precondition check". There are two standard approaches to do this that come to mind:
Option A: throw
void FairRun::FillEventHeader()
{
if (!fSource) {
throw std::runtime_error("fSource not set"); // should probably be a different exception type
}
fSource->FillEventHeader(fEvtHeader);
}
This could fit, if FairRoot in general wants to make much more use of exceptions.
Option B: assert
void FairRun::FillEventHeader()
{
assert(fSource);
fSource->FillEventHeader(fEvtHeader);
}
This would be the less invasive version, but will mostly be similar to a comment as people usually do not work with debug builds at all. At the end, this may also be subject to a project-wide style discussion on how to express function preconditions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for reminding me about reducing indented blocks! (It's actually one reason, why I like 80 column rules: It forces people to avoid too much indentation.)
And I like the style of "check things and exit/return early".
About pre-conditions, etc:
- I don't know, whether fSource not being set is actually a valid scenario. I doubt it, but I am really not sure. So before going to
LOG(error)
orthrow
I wanted to increase awareness a bit. - Yes, I would prefer exceptions for this type of error. People can catch them, handle them, etc. Yes, we probably should discuss this in a broader community.
- I haven't looked deeper into
Expects
, but this sounds like a nice thing!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know, whether fSource not being set is actually a valid scenario. I doubt it,
This would support that it should be understood as a classic pre-condition. I was looking at it from this angle: What can the user do to get rid of this warning?! Probably mostly by a code change. Which is a design time activity, so I would want to consider design time checks/hints. Since we also interpret everything optionally, it becomes more complex what/when design time is and which type of check is the best. but anyways, out of scope of this PR. LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have two suggestions:
-
Always prefer exceptions to abort
Using exception could lead to stack unwinding, releasing memories allocated in heap before the operating system kills the program. On the other hand,abort
(or other functions that calls it in the end, such asassert
andstd::terminate
) doesn't do any stack unwinding and leave the memory cleaning to the operating system. Some operating systems do not do the cleaning job and there could be memory leak. Of course there are many situations when we have no choice but to call abort. -
Include MS/GSL library into FairSoft?
I don't know when FairRoot will move to C++20 or even C++23. But some features in GSL are really useful. Contract (expect and ensure) is one of them. gsl::span, gsl::not_null, Range are also pretty useful.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I leave the merging to you, in case you want to apply the suggested style changes.
Co-authored-by: Dennis Klein <@dennisklein>
ef2092a
to
4c79fe9
Compare
Hi, :D This follows the discussion from PR #1254
To be honest, I don't think
In case of FairRoot developers who need to design a derived class from The signature of this function is also concerning: void FillEventHeader(); What is the purpose of this "front-facing" interface that takes nothing and outputs nothing? If everything the function does is just to fill an internal event header into an internal file source, why should a "front-end" user be concerned? Generally speaking, if the function doesn't require anything, it should be closed (declared as private) and executed internally. |
I don't understand this, really. So you would say, that Anyway: Some of our "facades" (maybe let's call them "convenience helpers"?) can be considered part of a bigger refactoring (which also is listed as a point on the facade wikipedia page). Having very concise calls in the main control flow makes it a lot easier to spot refactoring options. Maybe we learn that ReadEvent is always followed by |
Sorry, I was too general. Yes, you are right. User should be concerned about functions like For me, I also kind of think |
Yes. Please! I think, it will also reduce the size of your patchset (because you like don't need to change so many places). |
I learned about the Facade pattern from @dennisklein and he also suggested to improve the documentation about this.
For the current cases:
From the page:
simplified: Yes
Trying to improve the readability (of the callers): Yes
Yes!
Well, not everything is validated. But see the
\todo
.Maybe.
Note: The Facade pattern talks about objects, while this here is more applied to member functions.
Checklist: