Avoid code duplication when checking input

Suppose you have a subsystem that does some work. It could be anything. Obviously, there will be certain entry restrictions at the entry point (s) of this subsystem. Suppose this subsystem is primarily called a GUI. The subsystem needs to check all the data it has entered to make sure that it is valid. We do not want FireTheMissles () to be invalid. The user interface is also interested in checking because it needs to be informed what went wrong. The user may have forgotten to indicate a goal or targeted gaps in the launchpad itself. Of course, you can simply return a null value or throw an exception, but this does not tell the user SPECIALLY what went wrong (unless, of course, you write a separate exception class for each error that I'm fine with,if this is best practice).

Of course, even with exceptions you have a problem. The user may want to know if the login is valid before clicking “Fire Missles!”. button. You can write a separate validation function (of course, IsValid () doesn’t help much because it doesn’t tell you what went wrong), but then you will call it from the button handler and again from FireTheMissles () (I really don’t know how this has changed from an indefinite subsystem to a shooting program). Of course, this is not the end of the world, but it seems silly to call the same verification function twice in a row without changes, especially if this verification function requires, for example, computing a 1gb hash of a file.

If the preconditions of the function are clear, the graphical user interface can perform its own input verification, but then we simply duplicate the input verification logic, and a change in one may not affect the other. Of course, we can add a check to the GUI to make sure that the purpose of the bowl is not in an allied nation, but if we forget to copy it into the FireTheMissles () procedure, we will accidentally blow up our allies when we move to the console interface.

So, in short, how do you achieve the following:

  • An input check that tells you not only that something went wrong, but what specifically went wrong.
  • The ability to run this input check without calling a function that relies on it.
  • No double check.
  • No duplicate code.

, , FireTheMissles(). GUI , , GUI.

+3
5

" , , "

, , , .

IsValid, , IsValid . , , . .

TargetMissiles, MissileFiring, , , , / . , .

. .

?

+3

, Model-View-Controller.

(, , ), , /. ( , <ENTER> , ), , .. (Eclipse , .)

, , , . , , , validate_light , , .

, ( stderr), .

+2

. (, FK ). . , - #. , .

, (, Fire Fireile , ), , .

+1

, () "" IsValid.

IsValid TRUE FALSE . OUT, . , , GUI, .

, ( Delphi, ):

//different types of data we might want to validate
TValidationType = (vtMissileLaunchCodes, vtFirstName, 
  vtLastName, vtSSN);  

TInputValidator = class
public
  //call the constructor with the validation type
  constructor Create(ValidationType: TValidationType);

  //this should probably be ABSTRACT, implemented by descendants
  //if you took that approach, then you'd have 1 descendant class
  //for each validation type, instead of an enumeration
  function IsValid(InputData: string; var msg: string): boolean;

, , - :

procedure ValidateForm;
var
  validator: TInputValidator;
begin
  validator := TInputValidator.Create(vtSSN);
  if validator.IsValid(edtSSN.Text,labelErrorMsg.Text) then 
    SaveData;  //it valid, so save it!
  //if it wasn't valid, then the error msg is in the GUI in "labelErrorMsg".
end;
0

Each piece of data has its own metadata (type, format, unit, mask, range, etc.). Unfortunately, this is not always indicated.

GUI controllers should check the input with metadata and give warnings / errors if the data is invalid.

Example: a number has a range. The range is set by metadata, but the range is controlled by the control.

0
source

Source: https://habr.com/ru/post/1708644/


All Articles