Tag Archives: Uniface 9.6

I love Uniface

If you think ‘hey, this is a strange posting? Where is the technical stuff?’, you are right. Most of you don’t know who I am. My name is Peter Lammersma. I am an entrepreneur and work with Uniface since 1996. Uniface was my employer from 1997 to 2001. The reason I am starting to blog here, is because I am worried. In this first blog posting I will try to explain why. I asked Uniface BV (the company) to give me, although I am not employed by them, permission to write this blog on Uniface.info. Because I believe that we are the solution.

As you might know, I love Uniface. If there were ‘I love Uniface’ coffee mugs, I would drink my coffee out of it. Every day, really. If there were T-shirts, I would take good care and give it a special place in the wardrobe.

This feeling I have since 1996. Twenty year ago I swore that Uniface would be last software development tool I would ever use. As an entrepreneur for many years I am busy with several businesses, a few IT related, most of them not. And Uniface? I tried to escape, but she is always returning on my path. And believe me, I am more experienced with Uniface than I am with English :).

Now I am 45 I dare to admit, I like building software. To be honest, I don’t have a very objective point of view comparing Uniface with other tools. I am not interested in other tools, as long as Uniface serves my needs.

And it certainly does. Don’t you agree? Proven every day when we develop and maintain the software for our customers. With a minimum effort we produce highly effective applications. I believe this is called the return on investment. This is a very important business indicator. Every rational thinking decision maker can calculate and decide to use this wonderful tool forever! I certainly would. But, I have terrible news….

There is something wrong. I am worried and I want to share my worries with you.

Lack of Eagerness

I just realized that I am still using Uniface 9.6. While I should be interested in the new mobile features in 9.7. Wait, let’s skip 9.7. I should have downloaded Uniface 10, from the first day it was available. But I did not. Somehow Uniface 9.6 has everything that I need and I am not eager enough anymore to learn new stuff.

Have you already downloaded version 10? Or do you, like many, work in a version 9 in a way you used to in the previous versions?

And you know what worries me most? We don’t seem to care.

Where is that New Business

On the other hand, why should we use Uniface 10? Because it’s highly productive? The redesigned GUI? It’s not really important, is it. We all work like we did in Uniface 7. Sure, we use some of the new functions or statements, but in the end we try to hold on to what we once learned and used.

And why should we. New business is rare. Building or buying, the oldest question in software. When an organisation decides to build software, they will choose a sexy software development tool. Rather than proven technology with a huge install base. A game changer is always nice to talk about in the businessclub. You never hear someone say: ‘I choose this product because my dad used it in his business twenty years ago’.

Despite all commercial activities, most of us are stuck with the maintenance of the current applications. No need for new stuff.

So what

All above gives me a headache. You see, I want to use Uniface in future too. But I am doubting there is a long future. There is something that must be done. It’s not enough for Uniface (who came up with the idea to give the company the same name as the product?) to release a brand new product and wait what will happen. Nothing will happen by itself.

And we? Are we also just waiting for things to happen? We, the Uniface users, should find a way to regain our enthusiasm, our eagerness. I am thinking about this for a while now. But I wonder. Do you share my worries? I am very interested hearing from you all. So please respond to this blog. I am looking to forward to hearing from you (send me a message or comment below)!

In the meanwhile I’ll need a coffee and wait for something to happen…. Or?

Where to put your code

As a Uniface developer, I’ve seen a lot of Uniface applications first hand. On more than one occasion I encountered a situation where developers put all their code in the component. This happened for a number of reasons—access to the model or the library was constricted, there wasn’t enough time in the project to do it correctly, or just unfamiliarity with Uniface. I cannot speak on behalf of project managers or architects, but I can tell you how I code my projects.

The first rule of Uniface is that you do not copy and paste! (Very obvious movie reference!) If you find yourself in a situation that you think you need to copy code: stop! You are probably better off removing the code from its original source, putting it in either the application model or the library, and then reusing it in both the original component and the component where you wanted to paste it.

Single field implementation

Consider the following:

if (HEIGHT.PERSON < 0)

HEIGHT.PERSON = 0

endif

 

A person can never have a height that is smaller than 0 meters. Maybe there are people with a negative size, but I have never seen one. So if someone enters a negative value we reset the value to 0. If you were to put this in a component, than you need to copy and paste it the next time you need it. Remember the first rule? So where would you put it? The most logical place would be in the trigger of the modeled field HEIGHT in the PERSON entity. Creating an entry on entity level and then calling it from the leave field trigger would score equally well. This way the inheritance in Uniface will provide this piece of code in every component you use the field on.

Multiple field implementation

On record level

But what about two fields in the same entity? The formula for the Body Mass Index of a person would be:

BMI.PERSON = WEIGHT.PERSON/$sqrt(HEIGHT.PERSON)

The content of BMI is calculated by dividing the WEIGHT by the square root of a person’s HEIGHT. In order to calculate the BMI we need the value of two different fields in the entity PERSON.

If you thought about putting it in the modelled entity you’d be correct. I would create an entry that can be reused in (for instance) the value changed triggers of the WEIGHT and HEIGHT field or call it from a collection operation if you wanted to update all the BMI’s in some type of batch.

Between entities

Here is a classic. The total amount of an order is calculated by multiplying the price by the number of items in an order line, and then adding that to the total of the order. :

forentity "ORDERLINE"

   TOTAL.ORDER += PRIZE.ORDERLINE * NUMBERITEMS.ORDERLINE

endfor

 

The second rule of Uniface (you can actually here the voice of Brad Pitt, can’t you?) is that you never make a reference to another entity from a modelled entity. If you do, you need to include the referenced entity on every component you use the modeled entity on or the compiler will keep wagging its finger at you.

So we can’t reference the TOTAL.ORDER field in the trigger of the ORDERLINES entity. The only logical place is to put it in in a component. In this case, I would put it in a service that can be called from other locations as well. I can even activate that service in the modelled trigger of the ORDER entity.

What if it is a non-database entity?

Non-database entities come in two distinct flavors. The modelled ones and the non-modelled ones. An example of a modelled non-database entity is the entity containing a list of buttons containing default behavior that you can reuse when creating components. With these particular non-database entities the same rules apply as for the modelled database entities.

Non-modelled entities are created on the fly on a component. In this case there is only one place to put your code. The component level.

And non-database fields?

Non-database fields, have the same distinct flavors. They are either modelled (for instance a button that shows detailed information about a certain record of a modelled entity) or the non-modelled ones. If the non-database field is in the application model, code it there, otherwise code it in the component.

When I mention the component, there are actually three levels where to place your code. In the triggers of the component, in the triggers of the non-database entity, or in the triggers of the non-database field. Based on the previous rules you should be able to determine the correct position.

There is no entity or field reference

Once more for good measure:

 

if ($status < 0)

   return $status 

endif 

This code contains no field references and is of a more technical nature. This is an example of the smallest form of error handling in Uniface. If you intend to use it only once, the component is the best place to put it. If you need it in other places, you should move the code to the library and include it where required.

Can I use A Global Proc, instead of an Include Proc?

I have not used a Global Proc since the introduction of Include Procs. In my mind it is a deprecated feature of Uniface. From a component based development perspective Include Procs are better (but that is for another story). Besides using Global Procs for error handling purposes has one drawback. What happens when your Global Proc fails? Where are you going to catch that?

Let’s Summarize

Description Logical place
Code references exactly one field in one modeled entity Trigger level of the modelled field
Code references more than one field in one modeled entity Trigger level of the modelled entity
Code references more than one modeled entity In the component, preferably a service.
Code references a non-modeled entity If a non-modeled entity is used more than once, it should be defined as a modeled non-database entity. If it is a very specific non-modeled entity, it can be only in the component.
Code does not reference a field or an entity. Include proc. Never in a global proc. Component only, when it is really specific.

 

 

Structs: More than just an easy way to process XML streams

Struct

During the sixties of the previous century IBM’s Charles Goldfarb et al. developed, what can be considered now, as the first Markup Language. From his Generalized Markup Language (GML) the more generally known Standard Generalized Markup Language SGML was developed.  Several criteria were defined for this SGML. One of these criteria is that SGML should describe a structure and attributes. By describing it this way it was (and is) much more likely that data can be processed, using (future) information technologies. SGML was designed to process huge documents, initially used by the US government. SGML was often experienced as quite complex and the advent of XML-structured data made it possible to use the concept of structured data for smaller documents as well.

Nowadays XML is indispensable in information technology. XML (and its “mutants” like JSON) can be considered as the “de facto” standard for data communication between applications, using web services and more. In multi-tiered architectures XML should be used for data communication. Each development tool must be able to process XML-like data streams as efficient as possible. Considering XML strings as a “simple” string data type is far too easy to process XML streams in a fast and development-friendly way.

Initially Uniface defined scripting code (formerly known as Proc) that was geared towards the processing of XML. Scripting commands like XMLsave(to place component data in an XML stream) and XMLload (to load data from an XML stream into a component)  are good examples of this kind of scripting code. With the fact that the “data world” was getting more and more complex, these simple statements no longer covered the need for efficient coding. Many Uniface developers used string manipulation coding to process more complex data structures like XML and JSON.

A new paradigm was needed for Uniface to process XML, to stay on top of being (and staying) the number one productivity development tool. With Uniface 9.5 and 9.6 the implementation of the Struct datatype, in combination with the development of scripting code to manipulate Struct datatype variables and parameters (ie “Struct”), was the answer.  A Struct can be defined as a tree-like data structure, kept in memory, that is used to dynamically manipulate complex data and transform it from or to XML or Uniface component data. Variables of type struct are used to access the Struct. Scripting code commands, access operators, and information functions enables the developers to create, build, and manipulate the Struct.

The application of Struct, initially designed to process complex and structured data, has many more options. The creativity of the Uniface software developer is the limit for the application of Structs.  Here is a short list of applications for Struct. The list is just a limited one and without any doubt there are many more applications for Structs.

  • There is complex parameter support of web services and transformations of SOAP messages. All XML strings can, with only one statement, being transformed into a Struct. Struct can be transformed into component data, after some manipulation, if needed.
  • The processing of entities and multiple occurrences has been made much easier and faster. Component data can be transformed into Struct with one command. Because Struct is kept in memory manipulation of is very fast.
  • Software development according to the “multi-tier” paradigm is more straight-forward now. In a well-developed software application communication between the different tiers will be handled using XML, JSON or another XML-like data format. The transformation from component data into Struct is a very simple one.
  • Exchange of JavaScript objects is no longer a serious issue. Uniface has a JavaScript API to enable the development of client-side code for web-deployed applications. JavaScript uses JSON strings for data exchange a lot. Uniface supports the transformation between JSON and Struct. Easy to apply this on communication between a browser-based presentation tier and its server-based back end.
  • Uniface lists can be replaced by the use of Structs. Uniface developers that have developed Uniface list into list (into lists into lists… and so on) know that it can be very complicated and hazardous, using “goldkey ;” and goldkey !” for the lists inside lists definitions. Structs make live much easier.
  • Complex data exchange between entries, operations, and components can be implemented. Both parameters and variables are supported by the struct datatype. Using parameters makes it possible to exchange Struct to-and-from entries, local operations and public operations.

 

This was only a limited bulleted list of possibilities that the newly developed Struct data type offers the Uniface developer with Uniface 9.6. I am very convinced that there are many more creative applications for Structs, please show me!

Do we need a JSON data type?

I recently read a few articles raving about how good PostgreSQL is.  One article in particular explained how great it is that they have a JSON data type.  I wondered exactly what that would mean for developers, and whether Uniface needs one too.

The PostgreSQL documentation states that JSON data can be stored just fine in a text data type, but that a specific data type for JSON adds specific validation for JSON strings.  The documentation then adds that there are related support functions available.  Indeed there are JSON operators and functions that massage data between JSON strings and table rows and columns.  Suppose that you have a use case to exploit these functions, should you use them?  The simple answer for a Uniface developer is “of course not”.

Looking at those JSON support functions I would suggest that you can write Uniface functions / local proc modules to manipulate and transform data in similar ways.  Uniface Structs and the new 9.6.04 structToJson and jsonToStruct statements are particularly helpful for this.  So, provided that there is no extreme performance advantage in doing such manipulation on a DB server, it would not be a good idea to tie your application to a specific DB vendor, and lose that DBMS independence that Uniface gives you.  Bear in mind that there is no JSON data type in the current SQL Standard from 2011, and the major RDBMS vendors have not found a need to add such a non-standard extension.

Since we do have JSON manipulation tools, there is another consideration, based on our experiences with XML.  How do we validate the meaning of data transported by JSON?  With the xmlstream data type (and supporting proc statements) we have DTDs.  With our Structs transformations we have XML schema validation support.  With Uniface entities, we have the full support of the application model.

What is missing is a JSON Schema mechanism.  Thus I would suggest that if there is no supporting validation mechanism, there is no point in having a specific data type for JSON.

That situation may change in the future.  There are Internet Engineering Task Force (IETF) drafts available for a JSON Schema standard.  If you want to anticipate this as future standard, you can use this online tool to generate a JSON Schema:  http://www.jsonschema.net  from a sample JSON data stream.

At this time, to use this draft JSON Schema, you will need to write a validation module yourself.  However, you may be able to validate the data based on the Uniface Application Model.  After loading the Struct with the jsonToStruct statement, you may want to prepare the Struct for using the structToComponent statement.  Since 9.6.05+X501 the structToComponent supports a /firetriggers command option, which causes the Pre Save Occurrence and Post Save Occurrence triggers to be fired, thus allowing you to do further occurrence based validation or manipulation.  Of course the entities that you use for this purpose can be dummy entities created for this purpose, modelled or not.  This would avoid the need to reconnect with the database.

Hopefully we now have enough tools to deal with JSON data, without the need for a new data type.

Random Number Generator in Uniface

If you are not aware of it, Rik Lewis has a great blog about Uniface. I was quite interested in a recent post about the generation of random numbers. We don’t *officially* have this in Uniface. I don’t know why we don’t (probably something related to C++ across multiple platforms from the dark ages).

I’m interested to find out if this is something that we should put in the product (I’m assured it’s not too difficult), but I’m curious to know some use cases. The obvious one would be to generate primary keys, although there are other ways to do this.

But also things like how long would it need to be? 10, 20, 50 characters or should it be something like $random(10) which specifies 10 characters?

Comments welcome..