Browse DevX
Sign up for e-mail newsletters from DevX


'Making Reuse Fun' instead of 'Making Fun of Reuse' : Page 4

OK, so the COM team enabled us to develop great binary reusable components in DLLs and OCXs. Using all this functionality you develop this amazing component and now you're waiting for the developers to snap it up and start raving. You discover, however, that having a component that can be reused does not guarantee that it will in fact be reused. Amazing capabilities are overshadowed by ease of use and other trivial issues.




Building the Right Environment to Support AI, Machine Learning and Deep Learning

So, where do you store data that needs to be:

  • Centrally administered
  • Secure
  • Accessible from all workstations on the network

 Active Directory seems to be the ideal answer to all the above questions.  The problem with using Active Directory however is that:

  • Our clients are still migrating from an NT4 domain to Active Directory, and we have to wait for the slowest.
  • Some of our reusable components are used on standalone systems running on Windows Professional, which means no domain is present.

This means we are currently using INI files and the registry as repositories.  As basic as INI files may be, they are still the first choice of our customers.  When we need to fetch information, we first attempt to fetch it from the INI file.  The INI file needs to be in the same directory as the DLL.  Remember that we use SystemName as the key for fetching information, so the  file must be named "SystemName".INI.  This means that, for the Contract sample we used, in the same directory as "ContractCO.DLL" there needs to be an INI file called "Contract.INI".  In the same directory we can have a multitude of INI files, and by changing the SystemName property, configuration information will be fetched from different INI files. 

One of the entries in the INI file is the address of a central INI file.  If this entry points to a valid central file, the entries in the local INI file is ignored and the entries in the central INI file is used.

Should the local INI file not exist, we attempt to fetch the information from the registry using the normal Visual Basic functions "GetSetting" with the key (AppName parameter) as "SystemName".  

With the move towards XML we will be upgrading from INI files to XML files in the near future.  While XML will allow us to store more levels of hierarchical data, the basic functionality still stays the same.

When using a level five reusable object, when changing the SystemName, the programmer has to test whether valid configuration information was found. When using the reusable front end from a level six reusable object however, it pops up a screen prompting the user to supply the relevant configuration information.  This information is then persisted to the INI file or the registry depending on user preference. An OCX goes even further and must pop up configuration screens whenever an instance is dragged onto a form (in the development environment) and no configuration information can be found. 

To show you how this all fits together, let's expand our sample project a little bit and add an OCX with self-configuration abilities.  Let's say our OCX will display client data from our Client sample and lets call the project ClientOCX and the control ctlClient.  Firstly, the OCX will have a reference to an instance of ClientCO.clsSystem layer throughout it's lifetime, so add a property System to ctlClient. Declare a private modular object of type ClientCO.clsSystem and expose it as the property ctlClient.System. (Provide both a Set and Get property procedure, as you may want to set the object to an existing instance of ClientCO.clsSystem from some applications.)

Private mobjSystem as ClientCO.clsSystem

Public Property Get System() as  ClientCO.clsSystem
  if mobjSystem is Nothing Then
    Set mobjSystem = New ClientCO.clsSystem
  End If
  Set Client = mobjClient
End Function

Public Property Set System(pobjSystem as  ClientCO.clsSystem)
    Set mobjSystem = pobjSystem
End Function

When you place a user control on a form, the UserControl_InitProperties event is fired, so this seems like a good place to check for valid configuration information.  If the existing VB project and form is opened up on another PC however, the UserControl_InitProperties does not fire again, so this guy will miss out on all this logic we want to implement, so we rather put the logic in the UserControl_Initialize event, which occurs every time a control is created or re-created.  The logic is pretty simple.  If the connection string property is empty, we want to pop up a form to prompt the user to supply the information.  We add a form to the ClientOCX project with the capability to display/capture configuration information.  I use the following screen as a basis for most of my configuration screens.

You want the configuration form to pop up only when you are inside VB in design mode.  To determine if you are inside VB in design mode, use the UserMode property of the Ambient object that is available inside the user control.

The logic in the UserControl_Initialize event follows:

Private Sub UserControl_Initialize()
Dim frm as frmSetup

  If Len(Me.System.ConnectionString) = 0 and Ambient.UserMode Then
    Set frm = new frmSetup
    frm.Set_System Me.System
    frm.Show 1
  End If

End Sub

Now another issue pops up.  The above works fine when you are using the default system name, but when you want the control to start up using the configuration of its parent, which is the Contract system, you want to fetch the connection string only after you have set the system name.  As the system name is the key to which repository to use, you have to persist the system name to some other central repository.  You can use different repositories for this but I suggest using the property bag.  The property bag travels with the form on which the control is located, which places low admin on you as a developer, which is always good.  In a user control the ReadProperties event is used to initialize properties that needs to be persisted, so this is the right place to get the data for the system name.  The snag however is that the ReadProperties event fires only when you open up/load a form with an existing control on it, which means that if you move the above code to the ReadProperties event, you can collect the correct system name before fetching the correct configuration information from the property bag, but this will not happen until you once close down and re-open the form.  If you do not like this snag, you can implement another repository which is accessable in the Initialize event.  The code for using the property bag follows:

Private Sub UserControl_ReadProperties(PropBag As PropertyBag)

  Me.System,SystemName = PropBag.ReadProperty("SystemName", "ClientCO")


  If Len(Me.System.ConnectionString) = 0 and Ambient.UserMode Then
    Set frm = new frmSetup
    frm.Set_System Me.System
    frm.Show 1
  End If

End Sub

Remember the "happy faces" I mentioned in the first paragraph?  We have a workflow component in the typical 3-Tier environment with an OCX provided to display/configure route and item information graphically.  A developer had to integrate this into an existing product and asked me to assist to get the component configured and functioning.  So we added the reference to the CO and OCX and then dragged the OCX onto a form.  Immediately (OK, after closing and opening the form) a wizard popped up and guided the guy through the necessary setup steps.  When he pressed OK at the end, my work was done.  Now there was a guy with a happy face.

A note on object reuse

Depending on the type of applications you develop, object reuse on a binary level is not always feasible .  I develop mostly in a vertical market where the applications tend to share a lot of logic.  The applications reminds me of an octopus, with the tentacles being reusable subsystems and the body custom developed using core business logic linked with these subsystems in order to accomplish what is required of it.  So, in my environment reuse can be applied and makes a lot of sense.  What about an environment where your one system is always different to the next?  Well, I'm not an OOP guru, and I surely don't always follow all the OOP rules listed by the OOP gurus, but I do strive towards "strong cohesion" and "loose coupling" in my routines, objects and subsystems.

If you strive towards creating routines/object with internal integrity (strong cohesion) and flexible relations to other routines/objects (loose coupling), you will find that very soon  your system will consist of "virtual subsystems".  This is the starting point of reuse although it will most probably be "code reuse".  To move onwards to "binary reuse" the coupling has to be loose enough so that the "core system " has knowledge about the subsystem it is using, with the subsystem being totally independent of the core system.  (This introduces a level of complexity we have not touched on yet, namely what if the subsystem needs to inform the core system of changes etc.  This will be the focus of another article  however)

While from a business perspective it may not make sense to reuse parts of the system you are developing, I would advise you to apply design patterns that will allow reuse,  whether business require it or not.  Business requirements change without your assistance, while code unfortunately does not mutate over night to fit into new business requirements.  As I said in the previous article, one of the biggest lessons I have learned since I started programming is: Find a design pattern (or a set of them) that suits the environment you are in, understand it fully, and apply it!

JC Oberholzer is a software developer (MCSD, MCSE) that works on distributed and Internet based applications on the Microsoft platform.  JC  is currently employed by SDT and works in the financial services industry.  He maintains his own site at www.jcoberholzer.com. You can contact him at jc@jcoberholzer.com
Comment and Contribute






(Maximum characters: 1200). You have 1200 characters left.



Thanks for your registration, follow us on our social networks to keep up-to-date