Very often (to not say everyday), as an IT Consultant, you will have to face with Customer’s Request Versatility. Indeed, there is lot of cases where the customer is not very sure to what to do, and they change their mind as the wind is turning!

Of course, you will have to adapt your programs consequently and be sure you do not have introduced any bug.

Yep, the bug issue can be addressed by using some kind of TDP techniques or anything else, but what about your code?
How will you easily adapt the existing code in reaction of the customer requests changes?
The answer is by anticipating it in the early stages of your program’s design!

And PowerBuilder has everything you need to do it!

How to produce Versatile Code?

First of all, design business classes (Custom non Visual Object) that match Customer’s Client Business.

The tip here is to decompose each process in the following way:

  • The starting point should be a dedicated user event
  • The subsequent actions procedures or functions should be called in the adequate sequence from the adequate starting user event.

Iterates like this for every Business Process you need to implements. Try to extract methods that handles very specific task as much as possible. Ideally, these methods should implements only one basic task, if possible. Do not forget that is more a common sense rule than anything else.

It is very often, when not always, useful to create virtual classes as ancestor for every big kind of process to implement, containing only empty user events as processes starting points, and needed methods. Again, don’t be more catholic than the pop, code directly the methods that you are sure you will use in the most cases but keep the starting events empty at this level!

That way, if a new process deviates slightly from an existing one you can inherit from it, and add/modify needed inner process under the form of new/modified function or procedure. Then call them in the adequate order from the already existing starting point user event.

There you may need to play with the “Override/Extends” event options at concrete descendant level.
To adapt the methods, the overloading technique will be helpful to kept existing code compatibility.

Try to avoid as much as possible to use complex interfaces with lot of various parameters. Try to make the class autonomous to find & get needed data, using inner datastores for example. If it isn’t possible, try to use dedicated classes and events to manage them outside of classical interfaces. Data Dictionary generic classes are good candidates for this.

Example

This example will be very simple, but will illustrate the power of the technique explained above.

Here we will design the building of a bicycle wheel. At the beginning, the customer build only front wheel in one size and type. They wanted to know only if the processes launched were successful or not. So we have designed it like this.


/wp-content/uploads/2015/10/versatile_1_804069.png


As you can see, the ancestor class, again with virtual events, contains everything that we need to build, store and sell a bicycle front wheel.
The implementation of the build process through the “n_cst_wheel_standard” concrete class looks like this:

{ue_build event }

if this.of_GetParts() = -1 then return -1
if this.of_AssembleParts() = -1 then return -1

return 1


{of_GetParts method}
If of_GetTire() = -1 then return -1
If of_GetValve() = -1 then return -1
if of_GetRim() = -1 then return -1
if of_GetAxe() = -1 then return -1
if of_GetHub() = -1 then return -1
if of_GetSpokes() = -1 then return -1
Return 1


{of_AssembleParts method}
If of_AssembleTireWithRim() = -1 then return -1
If of_ AssembleRimWithValve() = -1 then return -1
if of_ AssembleSpokesWithRim () = -1 then return -1
if of_ AssembleSpokesWithHub() = -1 then return -1
if of_ AssembleHubWithAxe () = -1 then return -1
Return 1

Then after a period of usage, the customer asked to optimize the build process by assembling first the hub with the axe and only then assemble the spokes with the hub and with the rim.

Nothing easier, to implement this request I only have to changes the order of the two concerned methods in the of_AssembleParts method like this:

{of_AssembleParts method}
If of_AssembleTireWithRim() = -1 then return -1
If of_ AssembleRimWithValve() = -1 then return -1
if of_ AssembleHubWithAxe () = -1 then return -1
if of_ AssembleSpokesWithHub() = -1 then return -1
if of_ AssembleSpokesWithRim () = -1 then return -1
Return 1

After a while, the customer decided to also build rear wheel. The only difference with the front wheel is that the axe needs to be completed by a Speed gears set and a rear derailleur. So we can derive it from our existing front wheel the following way:

/wp-content/uploads/2015/10/versatile_2_804070.png

We had to create some new methods and modify the of_GetParts and of_AssembleParts methods in order to call the new methods to get and assemble the SpeedGears and RearDerailleur. We also decided to create the new “n_cst_front_wheel_std” class in order to clearly make the difference between both type of wheels produced now. 

The code is then being made more readable by replacing reference of “n_cst_wheel_standard” object by “n_cst_front_wheel_std” one. As the new one inherit from the old one, a simple rebuild of the code is necessary after the reference replacement, using a tool like “Global Replace”, it took only a few minutes to adapt the existing code!

A little bit later on, the customer asked to keep trace of some sort of statistics about the time consumed to build a wheel. Again, we added two new user events (ue_start_statistics & ue_end_statistics) and methods (of_set_start_time & of_get_elapsed_time), one to start and another to stop statistics measures at the n_cst_wheel_ancestor level. We also add a Time property called it_start.

The corresponding code is then:

{n_cst_wheel_ancestor::of_set_start_time}
It_start = now()


{n_cst_wheel_ancestor::of_get_elapsed_time}
Return relativeTime( it_start, now()  )


{n_cst_wheel_standard::ue_build}
This.event ue_start_statistics()
if this.of_GetParts() = -1 then return -1
if this.of_AssembleParts() = -1 then return -1
return this.event ue_end_statistique()


{n_cst_wheel_standard::ue_start_statistics}
This.of_set_start_time()


{n_cst_wheel_standard::ue_end_statistics}
Return this.of_get_elapsed_time()


So as you can see, with a little bit of anticipation in your design, you can produce easy to maintain “Defensive programming” made programs.

To report this post you need to login first.

Be the first to leave a comment

You must be Logged on to comment or reply to a post.

Leave a Reply