Kirk Brooks:

Thank you for your kind words. My son (Adam Bevan) and I have multiple 
motivation for writing our shell the way we are. ‘Bleed Through/Butterfly 
effect’ were one of them. It is likely that our very large application we 
previously had showed us that it can bite one too easily without strict 
discipline in coding.

Once we got comfortable with v12 we started creating forms with dynamic 
variables. With the multiple ongoing jurisdictional requirement changes and 
certifications we just never got enough time to implement them much. Therefore 
when rewriting the shell which I usually did ever ~ 5 years, we are doing the 
most ambitious rewrite. Every line of code is being rewritten in a clean room 
concept. We want to encourage ourselves to write all the code with the latest 
tools 4D provides us.

Another reason for not using process Variables is to reduce the memory foot 
print. As every process variable no matter how little it is used gets memory 
reserved for it in every process, no matter how small the process is or little 
the process is.

It is always easy to slip in to old tried and proven paths (ruts) when coding. 
There are times when we have slipped into putting in some process variables. I 
just looked at our COMPILER_Prov_Var method. We currently have 7 Process 
Variables. I know we had more but as the shell reaches its feature set we are 
removing them.

I understand what you are saying about flag variables. It is so easy and 
convenient to use a process variable for this. On our journey of writing the 
shell we have done that. At times though we have reassessed our use of them. It 
made us take some time and say how else can we do this. Our Object module is 
evolving very nicely. We are getting very used to putting flags, and many other 
things into these objects and then looking for them there. It is becoming 
natural to do so now.

One of the first items that Adam built was dot notation object handlers 
(Set/Get/Clear). I am sure he could have used Cannon’s highly rated module, but 
he wanted to do for himself. The next was to create an Object Viewer. The 
Object Viewer supports viewing a whole tree in the dot notation, and diving 
deeper into the tree to focus on specifics. It also permits us to modify the 
object values which is a huge time saver when initially developing a new 
feature.

A side benefit of the Object Viewer is that it is available in a compiled 
application. Therefore all of these flags, etc are available to be viewed at 
runtime in the compiled application. So great to getting a view of all this 
management information that we have. We are building our shell to handle all of 
the things that we encountered in our previous regulatory world out of the box. 
As we encountered back then there are jurisdictions that have little regulation 
so users would opt for little controls (typically a small 2 user site where 
trust was implicit). Therefore the shell is designed to have items turned on or 
off. All of this control data is stored in a few objects so that they are quick 
to access and modify. We something strange happens it is easy for us to at 
least see what the settings are.

We are also including many of the wonderful interface features that we 
accumulated over the years in our previous shell. These are things that I would 
hate not to have if I was working with the system. This includes things like 
the size and position of a window that the user likes for that specific window. 
How many items in a popup list they want as a maximum, after which it will be a 
scrollable selection dialog. There are literally hundreds of these options / 
features that we are building in.

As a user logs out and another use in, the objects are changed out and the 
application behaves differently. The Object feature of 4D makes this all very 
possible and efficient (we used ObjectTools in the past).

There are several forms. The first three are the most heavily used:

- Single Output Form.
- Included Button Tool Bar form
- Alert/Request/Confirm Dialog

Single Output Form

There is only one Output form for the whole application. We use selection 
Listbox. Of course every table will have different possible fields to be loaded 
into the output form. Not only that each person will have a different 
requirement for which fields they are permitted to see, or would like to see. 
In addition to this there may be calculated values (non-field data) that they 
would like displayed.

Therefore like all our listboxes in the shell they are built dynamically via 
code. This ability lets the users feel like they have control over the 
application rather than the other way around. The system administrator sets up 
default output forms for each role of users. Therefore if they are not so 
included to set them up they are done for them. We also have a ‘factor setting’ 
so that even the System Administrator does not have to do this work. 

With all the controls available for controlling listboxes we can provide many 
user controllable features (min / max width), default width, alternate colours, 
font, font style, font size, sort orders, column positions, and many more.

Of course underneath all of this is the security of records. Who can view who 
cannot view, are there fields of data they cannot view etc. This is all handled 
for all the tables with the one Output Form.

We also have many standard features that are available on the form. Security 
underpins it all and removes the items that the user does not have access to. 
Therefore a user with little access will always have a very simple form which 
means much less training for them, less clutter for them to filter out.

Many of these features will automatically appear once the user adds an item 
(saved search, saves sets, saved reports, etc). The user / system Admin can 
determine which users have access to these items as well. The beauty of this is 
that all tables have exactly the same appearance as all others - simply because 
there is only one form.

If there is a bug we fix it once - done. If we add a feature we only need to 
add it in one place - it is everywhere.

This is the shell we plan on using to develop other applications for. It is 
only good as a shell if it saves time. The Single Output Form is a huge time 
saver in so many ways.

The form itself has zero process variables or interprocess variables. All flags 
etc are stored in our standard objects. Therefore once you get to know where 
this is you know exactly where to look. I am writing the programmers manual for 
the shell as we write the shell. 

Inherited Button Tool Bar Form

This really should be considered as much more than just the button tool bar, 
but that is the biggest part. We could have gone the way of having a single 
form for the whole application (like the Output), but for now at least, we 
decided not to go that far with it. Input forms can have such dramatically 
different features. Having said that we know from training and supporting 
thousands of users on our last system that consistency is critical to faster 
learning, more complete usage, and fewer support calls. 

To this end having a specific button bar is key,  (with custom designed 
buttons). Again the same data in the objects is used to control the visibility 
of the various buttons, popups, administrative tools in the input.

As you might be getting, security is a foundational concern. Therefore which 
fields show up for a specific user or user’s role is controlled by the 
information in the objects. This is where we have a strict object naming 
convention for our fields, and labels. By doing this when the security code is 
gone through the appropriate fields, labels, groups, etc are made visible, 
non-visible, enterable, non-enterable.

We recognized that the same form may be opened in different processes, and in 
some cases within the same process. Therefore our object structure needed to 
support this. One of the key ideas was that we have a process object. This 
object contains process specific items. Which forms open, sets, named 
selections, form open, window Ids (important for Call Worker / Call Form), 
Process Ids, Table number, table name, Status of the form, status of specific 
form objects, and so much more. Having all this information in one easy to 
access location makes coding issues so much easier to handle.

Trying to write this for each input form would be a huge job. By writing it 
from scratch with this in mind from the beginning makes this a joy when 
creating a new input form. Our ‘Inherited input Form’ makes so much of the work 
easier. It even has built in vertical and horizontal guides for helping us 
place objects on each form in a consistent manner. Really all we need to deal 
with on an Input form is the table / form specific items. This saves us lots of 
time - a key requirement of a shell.

Alert/Request/Confirm Dialog

We have one form for these three types of dialogs. Each part of the form is 
‘controlled’ by the data in our Parameter Object.
        - Window Type, Window Title, Which of the 4 buttons to show (with their 
title), Message to User, User Response, Button Access to Help, Which button 
clicked, Response by the user.

We have a DEV Macro that sets this all up so setting up the code for a dialog 
and for responding to the dialog takes 2 seconds to place the code. Then just 
set up the specifics in the code by highlighting and changing as appropriate.

The form has no process variables. This ensures there is no butterfly effect 
ever. The code is easy to write as we just get a pointer to each object that we 
know what the name of the object is. The form itself will change it’s size up 
to a defined limit if the message to or from the user is longer text.

The code that sets up the control for the dialog creates a sub object within 
the process object. Once the response from the user is obtained by the calling 
method that specific object is deleted from memory. This way there is not a 
problem with multiple dialogs open within the whole application or within a 
process. 

These are just some of the forms we do this with. We have several others that 
we have developed within the shell. Of course when an application is created 
with the shell the same approach will be taken. 


re: I caught a lot of flak last year when I suggested process variables had
> become passe in favor of a single process object for managing the random
> bits of information they are usually used for. 

I am not certain if I understand you or you understand me. I do not think that 
for other than some forms we have gone to not having field information on it. 
We have though removed all process variables by placing form variables on 
screen that do not get an object name instead of a variable name. With some of 
our forms it is true that the data on the form is contained in an object and 
the form is really just a temporary container for that object information.

An example where we do this is for all the Preferences we have in the system. 
There are hundreds of them. Some are boolean, some are ‘pictures’, others 
colours, numbers, and text. All of the preferences are stored in an object. 
Therefore the form when displaying them is just displaying what is in the 
object. The Listbox with the 4D View Pro feature set of being able to have an 
object column that displays different controls based on the type of data in the 
object is a great enhancement to the user interface. Way back in v12 we had 50 
pages of preferences (System Admin, Organization, Site, Computer, and User) all 
totalled. The feature set of Listboxes in 16R2 is critical to being able to do 
all of this - as it is all dynamic within code. 

Now we have one preference page for each of the types. On each page is a single 
Listbox with a Group selector popup. We may move this onto a single input form 
just changing the titles etc in the future. For now though we see great 
advantage in time saving, and simplicity for the user over what we had 
previously. Now we can add a new preference and it will typically just show up 
in the appropriate place. No extra space on a form, no coding on the form to 
handle it.

We wanted this as our vision for the shell is that it will be used to create 
many different application - simple to very sophisticated, from one user to 
thousands of users at once. Our goal is that we can use the shell to jump start 
a project with all of these features while not burdening them down with things 
they do not want.

I cannot see any reason to have a process variable on a form any more. Now that 
we have our Object Viewer and the underlying Object ‘Dynamic Library’ there is 
no need. Too many advantages in doing it this way compared to a variable on a 
form.


re: Are you willing to talk about how you manage the fields and data in the
> process object?

I suppose I have my head too deep into our project to understand what you are 
asking for. It now just all seems so obvious. Having said that if you talk to 
my son a year ago he would likely have expressed frustration by my lack of 
getting it. It is a paradigm shift working with objects for storing the data 
rather than variables.

re: ​This opens up a lot of options for things like inherited forms too as I
> 
> think of it. Instead of having different inherited forms in different sizes
> there can be one and the objects simply sized as appropriate. ​

Absolutely! This way of coding reduces the number of forms greatly. I expect 
that the memory footprint used by applications developed by the shell will be 
significantly reduced from what it would be.

re: What are some examples of the generic form methods you are using?​

There are many that we have. So many that we created a DEV Macro palette that 
we use while coding. When we need a new Input form we just select the macro for 
that type of a form. The code is in. If we need a listbox on a page we just use 
the DEV Macro Pallet to select the code for building a listbox. We currently 
have many generic methods. As this is the shell most of our code is generic. 
Some examples are:

- STD_inputMethod: This method calls a whole set of other generic methods. 
Based on object data, and object names it will do things like:
        - Set up the form help caller, add to the count of that user using the 
form
        - Handle security of access to the form (view/modify/delete), same for 
field access, Audit trail of access, window title, colours
                field background colours, Setup Menu, button access (and more). 
All of these tasks I mention are controlled by generic                  
methods. 
                Therefore the code is done, do not need to be touched for this 
code to be written for the form. LOVE THIS!

- Logging: This code is very standardized. This is a lesson we learned hard 
over the last 30 years. Logging of our code progress
        is critical for finding crashing, or problems. Therefore all our Dev 
Macros have calls to our logging. We have three types
        of logging that we do (beyond what is built into 4D itself). The 
logging can be turned on or off as required. As well we can
        set the level of the logging. Of course the logs can be sent back to us 
automatically. The importance of logs cannot be
        understated. LOVE THIS - even now while still programming!

- Listbox Setup: We have a few lines of code that we paste in from the 
DEV_Macros to setup a listbox. Need more columns, just copy a line, and adjust 
a few strings in the line.

- Listbox Configuration by User: This is all built into the Listbox Setup. The 
method for this is called automatically from within the Listbox. The user’s 
configuration for the listbox is all stored for each listbox for that user. 
They set it once and they have it just the way they like it. So jurisdiction 
requirements, user preferences, business type, business needs etc. All of this 
is handled within the generic code of our listbox. LOVE THIS!

- Clairvoyance for fields. This is a single set of code that is generic (of 
course). Pasting in from the Dev Macro and change a few strings and it is set 
up. It handles which lists, show description, or code, and much more. Very 
sophisticated. The whole feature set of the Clairvoyance fields was one of the 
favourite among our user base. Though not really clairvoyance, our date handler 
for fields is also very good. No more improperly entered dates / times, yet 
entering them is very very quick.

As I say there are many more. I just looked quickly at an input form. We have 
not written any application specific code as of yet so most of the code we have 
written are generic. This is all done without any process variables (other than 
the few I mentioned). We will delete these as we needed them initially to build 
and test our Object code, and other generic code. Now that we have the objects 
feature sophisticated enough, we do not need these process variables. The only 
Interprocess variables are the objects.


Kirk, I hope this is what you were looking for.

Sincerely

Jody


> On Jun 18, 2017, at 3:13 PM, Kirk Brooks via 4D_Tech <4d_tech@lists.4d.com> 
> wrote:
> 
> Jody,
> 
> ​Nice post. I've also implemented several of these ​ideas but you're really
> going more deeply than I have. My motivation didn't have anything to do
> with bleed through. They came about as I was working more and more with
> objects and dynamic variables.
> 
> On Sat, Jun 17, 2017 at 2:35 PM, Jody Bevan via 4D_Tech <
> 4d_tech@lists.4d.com> wrote:
> 
>> 1. On all forms we never use variables.
>> 
> ​Assuming you're talking about process variables. I agree mostly but there
> are some times when they are still useful. Most recently as a dataChanged
> flag. But that could be stored in the process object you t​ouch on later.
> 
>> 
>> 2. We have a generic form that has several objects on it. At runtime we
>> will make objects visible or not, and change their titles, positions, etc.
>> This permits us to have one form that handles Alerts, Requests, and
>> Confirms. We provide more features than that with these dialogs (like help
>> buttons, trace, etc). This means this dialog gets used extensively.
>> 
> ​I've played with this idea a bit too. Could you talk more about what kinds
> of forms or records you're using this for? They are easy enough to
> implement in concept but to make them look nice and such has been a
> challenge for me. ​
> 
> 4. Dialogs that a process call up though will need to get the input from
>> the user. We accomplish this through an object we call our Process Object.
>> Inside the process object a object is created for every running process.
>> When a form is opened within the process an object is created for that
>> form. When a dialog is opened an object is created within that form object.
>> There we set what all the dialog objects are to be, and we also return the
>> results from the user input. The form that called the dialog gets the
>> information it is looking for from this object. Once the information is
>> obtained that dialog object is deleted from memory.
>> 
> ​I caught a lot of flak last year when I suggested process variables had
> become passe in favor of a single process object for managing the random
> bits of information they are usually used for. I must admit I hadn't
> thought about this approach. I like it. The form becomes more like a
> reflection of the data (stored in the object) instead of the data actually
> residing on the form. ​
> 
> Are you willing to talk about how you manage the fields and data in the
> process object?
> 
> ​This opens up a lot of options for things like inherited forms too as I
> think of it. Instead of having different inherited forms in different sizes
> there can be one and the objects simply sized as appropriate. ​
> 
>> 
>> It seems complex and it would be if we had to write the code each time. We
>> have written nice generic methods for its use. We also created macros as we
>> do for all this stuff that makes it very quick to build a request dialog
>> (for example) in our code.
>> 
> ​What are some examples of the generic form methods you are using?​
> 
> ​You know, this also allows for you to create a hell of an error log - you
> could ​write the process object to the error record in addition to the
> other stuff.
> 
> -- 
> Kirk Brooks
> San Francisco, CA

**********************************************************************
4D Internet Users Group (4D iNUG)
FAQ:  http://lists.4d.com/faqnug.html
Archive:  http://lists.4d.com/archives.html
Options: http://lists.4d.com/mailman/options/4d_tech
Unsub:  mailto:4d_tech-unsubscr...@lists.4d.com
**********************************************************************

Reply via email to