Code after validations

Share this topic:



Link to this posting

Postby Ursego » 21 Feb 2013, 15:51

If a large code fragment is executed after a few validations (and is placed inside a few if-s), take them all (the fragment and the validations) into a new function and exit that function just after the first failed validation.

It will not only save your code from extra indenting but also convey the following idea:

The whole algorithm (not its part!) is executed after ALL the preliminary validations.

If the first line of the function is if not <condition> then return and the code is longer than one screen then the reader immediately knows that all next stuff is done only if the condition is satisfied.

But if the executed stuff is placed between if and end if (the bad way) then the developer is forced to scroll down to see if there is any code after the end if.
See how you can convert a code from monstrous to elegant:


*** BAD code: ***

PB:
Code: Select all
if this.uf_data_ok_1() then
    if this.uf_data_ok_2() then
        if this.uf_data_ok_3() then
            [code fragment with its own indenting levels]
        end if
    end if
end if

C#:
Code: Select all
if (this.DataOk1())
{
    if (this.DataOk2())
    {
        if (this.DataOk3())
        {
            [code fragment with its own indents]
        }
    }
}

*** GOOD code (taken into a new function): ***

PB:
Code: Select all
if not this.uf_data_ok_1() then return
if not this.uf_data_ok_2() then return
if not this.uf_data_ok_3() then return

[code fragment with its own indenting levels]

C#:
Code: Select all
if (!this.DataOk1()) return;
if (!this.DataOk2()) return;
if (!this.DataOk3()) return;

[code fragment with its own indents]

Here you can ask: and what about the "single point of exit" rule? I don't want to discuss it here, but this idea produces more problems than solves. I agree with Dijkstra who was strongly opposed to the concept of a single point of exit (it can simplify debugging in particular circumstances, but why do I have suffer from everyday working with more complicated code only for the sake of simplifying possible debugging which, may be, will never happen?).

If a code fragment after many validations is not very long and you don't want to extract it into a special function then use the exceptions mechanism: put the whole fragment between try and catch, throwing an exception on failure of any of the sub-validations and processing it locally (without propagating outwards).

If your programming language doesn't support exceptions then use one of the following tricks: the "flag method" or the "fake loop method" - but not the "multi-indents method"! Both PB and C# have exceptions (PB - beginning from version 7), but anyway I will use them to demonstrate the idea:

*** GOOD code ("flag method"): ***

PB:
Code: Select all
boolean lb_ok

lb_ok = this.uf_data_ok_1()
if lb_ok then lb_ok = this.uf_data_ok_2()
if lb_ok then lb_ok = this.uf_data_ok_3()
if lb_ok then
    [code fragment with its own indenting levels]
end if

C#:
Code: Select all
bool ok;

ok = this.DataOk1();

if (ok)
{
    ok = this.DataOk2();
}

if (ok)
{
    ok = this.DataOk3();
}

if (ok)
{
    [code fragment with its own indenting levels]
}

*** Another GOOD code ("fake loop method"): ***

PB:
Code: Select all
boolean lb_ok

do while true
    lb_ok = false
    if not this.uf_data_ok_1() then break
    if not this.uf_data_ok_() then break
    if not this.uf_data_ok_3() then break
    lb_ok = true
    break
loop

if lb_ok then
    [code fragment with its own indenting levels]
end if

C#:
Code: Select all
bool ok;

while (true) // or "for(;;)", if you wish
{
    ok = false;
    if (!this.DataOk1()) break;
    if (!this.DataOk2()) break;
    if (!this.DataOk3()) break;
    ok = true;
    break;
}

if (ok)
{
    [code fragment with its own indenting levels]
}

As you see, the fake loop is an eternal loop with unconditional break in the end of the first iteration, so the second iteration will never happen. This solution is looking strange (a loop construction which never loops!), but it works!
User avatar
Ursego
Site Admin
 
Posts: 112
Joined: 19 Feb 2013, 20:33

Link to this posting

Postby Berg Steven » 15 Mar 2013, 15:58

Code: Select all
lb_ok = this.uf_data_ok_1()
lb_ok = lb_ok and this.uf_data_ok_2()
lb_ok = lb_ok and this.uf_data_ok_3()

if lb_ok then
    [code fragment with its own indenting levels]
end if

Would be more elegant.
User avatar
Berg Steven
 
Posts: 1
Joined: 15 Mar 2013, 15:55

Link to this posting

Postby Ursego » 01 Apr 2013, 11:31

Your method can be used only if the subsequently called functions are extremely lightweight. But if they go to DB or call web services then it's better not to invoke them at all (if we know in a given point of time that it fill be FALSE). Please read here.
User avatar
Ursego
Site Admin
 
Posts: 112
Joined: 19 Feb 2013, 20:33


Return to Managing Functions

Who is online

Users browsing this forum: No registered users and 1 guest


Code after validations

Share this topic:


If you think that this site is not too bad, please LIKE it in Facebook. Thanks!





free counters

eXTReMe Tracker