Check: Caller vs. Called
Version TL; DR are both.
The long version means who, why, when, how, and what.
AND
Both should be prepared to answer the question "can this data work reliably?" Are we aware of this data in order to do something meaningful? Many believe that data reliability should never be reliable, but this only leads to a chicken and egg problem. Pursuing him endlessly from both ends will not provide significant value, but to some extent this is important.
Both should validate the data form to ensure database usability. If any of them does not recognize or understand the data form, there is no way to find out how to further handle it with any reliability. Depending on the environment, the data may need a certain “type”, which is often an easy way to validate the form. We often consider types that present evidence of a general lineal back to a specific ancestor, and retain important traits in order to have the correct form. Other characteristics may be important if the data is something other than a memory structure, for example, if it is a stream or some other resource, external context.
Many languages include data form validation as a built-in language feature through type or interface validation. However, when the preference of the composition over inheritance, the provision of a good mechanism for checking the existence of signs lies with the performer. One strategy to achieve this is through dynamic programming, or in particular through introspection, inference, or type reflection.
Called
The caller must check the domain (set of inputs) of the given context to which he will work. The design of the called always assumes that it can only handle so many input cases. Typically, these values are broken down into specific subclasses or input categories. We check the domain in the called because the call is intimate with localized restrictions. He knows best of all what is a good contribution and what is not.
Normal Values: These domain map values are in range. For each foo there is one and only one bar .
Out of range / out of range values: these values are part of a common domain, but will not be displayed in a range in the context of the called. There is no specific behavior for these values, and therefore no valid exit is possible. Out-of-range checks often include ranges, restrictions, or valid characters (or numbers or compound values). A power check (multiplicity) and then a presence check (zero or empty) are special forms of range checking.
Values that lead to Illogical or undefined behavior: these values are special values or extreme cases that are otherwise normal, but may result in unexpected results due to the design of the algorithm and known environmental constraints. For example, a function that works with numbers should protect against dividing by zero or the accumulators that will overflow, or the inadvertent loss of accuracy. Sometimes the operating environment or the compiler may warn that these situations may occur, but relying on the runtime or the compiler is not good practice, because it cannot always output what is possible and what is not. This step should be verified to a large extent by a secondary check that the caller provided good, useful, meaningful input.
Caller
The caller is special. The caller has two situations in which he must check the data.
The first situation is a change in an assignment or an explicit state, when the change occurs with at least one data element using some explicit mechanism, inside or outside of something in its container. This is somewhat beyond the scope of the question, but something needs to be kept in mind. It is important to take into account the context when a state change occurs and one or more elements describing the state are affected.
- Self / Referential Integrity: Consider using an internal mechanism to check the status if other participants can reference the data. When data does not have consistency checks, it can be safely assumed that it is in an undefined state. This is not intermediate, but vague. Know yourself. When you do not use the mechanism to check for internal consistency during a state change, the data is not reliable and leads to problems in the second situation. Make sure the data for the caller is in a known good condition; alternatively, in a known transition / recovery state. Do not call until you are ready.
The second situation is when the data calls the function. The caller can expect only so much from the caller. The caller must know and respect that the caller recognizes only a specific domain. The caller must also be interested in himself, as he can go on and on long before the callers complete. This means that the caller must help the caller be not only successful, but also appropriate for the task: bad data as a result generates bad data. At the same time, even good data in relation to and called in relation to the called cannot match the following thing in terms of the calling. Good data can actually be bad data for the caller. The caller’s output can invalidate the caller for the current state of the caller.
Ok, enough comments, what should a specific caller check?
It’s logical and normal: considering the data, is a good strategy called that corresponds to the goal and intention? If we know that this will work with certain values, there is no longer any reason to make a call without the appropriate guards. If we know that a call cannot process zero, do not ask for it, as it will never succeed. What is more expensive and more difficult to manage: [redundant (do we know?)] Security proposal or exception [which occurs late in a possibly longer resource, depending on external resources)? Implementations can change and change suddenly. Providing security to the caller reduces the impact and risk of changing this implementation.
Return Values: Check for failure. This is what the caller may or should not do. Before using or relying on the returned data, check for alternative results if the design of the system takes into account successful and unsuccessful values that may accompany the actual return value.
Footnote: In case this is not clear. Null is a domain problem. It may or may not be logical and normal, so it depends. If zero is the natural input to the function, and the function can be reasonably expected to produce meaningful output, then leave it to the caller to use it. If the caller’s domain is such that null is not logical, then protect it in both places.
The important question is: if you pass null to the callee and the caller produces something, is it not a hidden creation template that creates something from nothing?