Chaining conditions without IF or CASE
Coding a batch process with numerous steps that can succeed or fail, while keeping control in calling program whether the whole process has succeeded and, if not, knowing the reason why, can end up with an unreadable program because of the multiple if ... endif
or do case ... case ... endcase
indented blocks.
Using if m.success... endif
ends up with unreadable nested indentations and makes it difficult to change the tasks order:
procedure do_task as Boolean
local success as Boolean
... some code ...
if m.success
... some code ...
if m.success
... some code ...
if m.success
endif
endif
endif
assert m.success
return m.success
endproc
Using if !m.success... endif
repeats code and adds multiple returns, but makes task order changes easier:
procedure do_task as Boolean
local success as Boolean
... some code ...
if !m.success
assert .F.
return .F.
endif
... some code ...
if !m.success
assert .F.
return .F.
endif
... some code ...
if !m.success
assert .F.
return .F.
endif
endproc
Using do case ... case ... endcase
requires sub-procedures and is still uselessly verbose and somewhat difficult to understand as it relies on negations:
procedure do_task as Boolean
local success as Boolean
do case
case !do_task_step1()
case !do_task_step2()
case !do_task_step3()
otherwise
success = .T.
endcase
assert m.success
return m.success
endproc
We found a convenient way to make program more readable by:
- moving all concrete work to sub-procedures using a standard scheme for naming, parameters and returned value
- chaining the calls to sub-procedures into a single logical expression
Let’s say main procedure is do_task
with step1
, step2
, etc.
First create one procedure per step:
procedure do_task_step1 as Boolean
lparameters result && @ expected by reference -- always 1rst parameter
local success as Boolean; && for step 1
, cResult as String && local result
... some code ...
cResult = iif(m.success, '', "reason for failure")
result = m.result + iif(empty(m.result), '', CRLF) + m.cResult && add to global result
assert m.success message m.cResult && stop right where error has occurred!
return m.success
endproc
Then create the main procedure:
procedure do_task as Boolean
lparameters result && @ expected by reference
result = evl(m.result, '') && makes sure m.result is a string
return .T.; && .T. and anything is anything
and do_task_step1(@m.result); && pass m.result by reference
and do_task_step2(@m.result);
...;
and do_task_stepN(@m.result);
and .T.
endproc
Very convenient is the ability to change the tasks’ order by just swapping 2 lines.
Of course, do_task_stepX()
could be further broken into do_task_stepX_phaseY
, etc.
tags: code productivity quality
Watch FoxInCloud Marketing Videos :: Watch FoxInCloud Technical Videos :: Stay tuned on FoxInCloud Roadmap :: Learn how to use FoxInCloud :: Download FoxInCloud Adaptation Assistant for free :: Download FoxInCloud Web Application Studio for free