How do you know your software works? And keeps working?

Which scenario do you like better?

You wake up in the morning. The sun shines brightly through your window, but for all you care it might as well be pouring with rain. The bug reports are stacked high and low on your desk. The minute you walk in someone from support will be on your back about clients X, Y and Z who have effectively been unable to use your software for days now, making it impossible for them to serve their clients. You hope the coffee machine is working. Otherwise you will have to go down to the floor housing sales and product management. They will jump at the chance to ask you how features A, B and C are coming along. Features they have been waiting on for months now. Is Gary back from holiday today? Darn. That means that you will have to explain why it took so long to fix the export to Excel thingie you thought would only take half a day. Gary is talking about hiring more developers to regain some speed. Nice and all, but where are you going to find the time to train them? The prospect of all this weighs you down, draining all the energy you regained while asleep and then some. You drag yourself out of bed and to work. Not because you enjoy it, but because you need money on the table to pay your bills.

You wake up in the morning. The sun shines brightly through your window. You squint a little clearing the sleepiness from your head. Today is going to be a good day. You are going to finish that cool new feature client C requested two weeks ago. It was an interesting challenge. You learned a lot in the process. It isn’t the last. Plenty more features in the pipeline that will be fun to build. Justin, the product manager, will be around this afternoon to discuss a couple more ideas. Sales have a few prospects that are requesting special features and Gene, the support manager, would like some extra reporting so he can detect hot spots before they become a problem. Oh and Bill is coming over for lunch. Lunches with Bill are the best. Bouncing around ideas and coming up with better ways to do stuff always gets both of you going. Would be interesting to take the new hire along. See how he responds. The prospect of a good day gets you out of bed with eager anticipation.

Me?

I am absolutely partial to the second scenario.

Yesterday I ran across a post on software quality.

It struck a chord with me. It articulates exactly what I feel.

I care deeply about software quality. Not to alleviate my innate fear of failure. Not out of perfectionism. Not to do things “right”.

I care deeply about software quality because it keeps my work fun and interesting.

I’d much rather be building new features than fixing bugs. I prefer to work without the pressure of “fixing” things as fast as possible because a client is screaming hell and bloody murder.

Building quality software is the only way I know how to make this happen and to keep it happening.

All other ways of building software may seem to have very big advantages, but those advantages only manifest in the short term.

Like delivering results quickly.

I like delivering results quickly just as much as anybody else.

Even if you need to take shortcuts to do that.

Shortcuts are fine only as long as you redo them properly immediately after delivery of the feature. If you don’t, those shortcuts come back to haunt you.

Unless you address them immediately and ruthlessly, every shortcut, whether in code, in tests or in documentation, makes new features a teensy bit harder, less reliable and more work to implement.

Which slows down delivery of new features.

And which can introduce subtle bugs that you will have to fix at a later stage when you are no longer familiar with the subject.

Fixing bugs also slows down delivery of new features.

Taking one shortcut may not seem like a big deal. The effect is limited. But unless you fix it, that tiny bit of extra work needs to be done every time you deal with that code. It cumulates quickly.

You think you can take that hit. It is in some part of your code that doesn’t get changed often, so the effect remains limited. No biggie.

However, there is more to accepting a shortcut than accepting the hit on effort required for future changes.

It sets a standard.

That shortcuts are somehow ok.

Soon you won’t have one shortcut but two, then three, five, nine and more.

The more shortcuts you take, the bigger the effect.

After some time of taking shortcuts, the speed at which new features are delivered really starts dropping.

Bug lists get longer. Implementing new features requires more and more knowledge that hasn’t been made explicit anywhere. New hires take a long time to get up to speed. Seniors are stretched beyond breaking point implementing new features only they have the experience with your code base to do properly and guiding less experienced colleagues.

Parts of your code will be in dire need of refactoring.

There will be parts of your code you don’t dare touch for fear of introducing bugs or inadvertently disabling features that you no longer even know exist but that your clients rely on.

The calls for a rewrite will start to be heard and grow in frequency and intensity.

The first scenario looms large overhead.

The only way I know how to avoid getting into that first scenario is relentless attention to and striving for quality software by everyone on the team. Just like Bob describes it in the last paragraph of his post

Posted in Software Development
Tags:

How to get a ListView to display your values in columns

Can’t get a ListView to display the values from your database in columns properly?

You want to display information from your database. You would like it to be displayed in a list with columns. A ListView can do that.

Should be as easy as 1-2-3.

Just set up a query, loop through the records and add the field values to the ListView. Something like this:

    begin
      SQLQuery.SQL.Text := 'SELECT FirstName, LastName, Country FROM Famous_Actresses';
      SQLQuery.Open;
      while not SQLQuery.Eof do
      begin
        ListView.AddItem('First name: ' + SQLQuery['FirstName'], nil);
        ListView.AddItem('Last name: ' + SQLQuery['LastName'], nil);
        ListView.AddItem('Country: ' + SQLQuery['Country'], nil);
      end;
    end;

Right?

Wrong.

When you do it like this, it comes out as a long list of values all in a single column.

ListView displaying values as a list despite vsReport ViewStyle

That’s not what you want.

You want a nice orderly list in which every field has its own column. Just like how Windows Explorer displays files in its details view.

How Windows Explorer displays files in Details view style

Relax. You’re half way there.

Just two things left to do:
– Tell the ListView about the columns you want it to display.
– Add the values from your database to their specific columns.

Setting up columns for a ListView

You can add columns to a ListView in the visual form designer by double clicking the Columns property of the ListView and adding the columns you need. While easy to do, you now have tied that ListView to a specific set of columns. And I bet you that you will have plenty more lists to show in any application worth using.

When you know how to do those things in code, you give yourself the option of reusing a single form for many lists.

So, let’s do it in code:

    var
      Column: TListColumn;
    begin
      // Set up columns
      Column := ListView.Columns.Add;
      Column.Caption := 'First Name';
      Column.Alignment := taLeftJustify;
      Column.Width := -1;

      Column := ListView.Columns.Add;
      Column.Caption := 'Last Name';
      Column.Alignment := taLeftJustify;
      Column.Width := -1;

      Column := ListView.Columns.Add;
      Column.Caption := 'Country';
      Column.Alignment := taLeftJustify;
      Column.Width := 140;
    end;

Tips
– Set a column’s Width to -1 to make the column display its entire text.
– Set a column’s AutoSize to true to make it resize proportionally when the Width of the ListView changes.

Adding values to specific columns

Now that you have the columns set up, you are all set to make the ListView display your information as you want it. The only thing left to do is to add the values from your database in the way the ListView expects it for the vsReport ViewStyle.

You already got most of the code right in your first try. Just change the lines where you added items to the ListView to:

    var
      Item: TListItem;

      begin
        Item := ListView.Items.Add;
        Item.Caption := SQLQuery['FirstName'];
        Item.SubItems.Add(SQLQuery['LastName']);
        Item.SubItems.Add(SQLQuery['Country']);
      end;

And now you have a well behaved ListView that displays your database values in columns properly.

ListView with Proper Columns

Posted in Software Development
Tags: , , ,

Why does my panel display the wrong color?

You are working on your application and want to add some color to spruce it up a bit. Setting colors using Delphi’s Object Inspector is a breeze. That is, when you use the predefined colors from the color property’s drop-down list.

Object Inspector Color Drop-Down

Or when you use the color dialog that opens when you double click the Object Inspector’s edit for the color property.

Color Dialog

True, the dialog allows for a lot more colors than are available as predefined colors. But you find it cumbersome to use. It requires a double click to open the dialog and an extra click to open the “custom colors” part. It even isn’t smart enough to remember that you had the custom colors open the last time you used it. And it’s annoyingly fiddly to set the hue, saturation and brightness using the rectangle and slider. Using the edit boxes when you want more precise control over the color isn’t much better. In fact it is … cumbersome.

All you want to do is paste the color code for the nice orange that you found on the web into the color property’s edit box in the Object Inspector.

Nice Orange Color

And Delphi allows you to do just that. All you need to do is copy the color value, paste it into the edit box and replace the ‘#’ with a ‘$’ because Delphi expects a hex value there.

Typing Color Into Object Inspector

But when you do that …

You get a totally different result. Your nice orange color turns blue in the face.

Resulting Color

Gah!

Relax. The solution is simple. Colors on the web are specified as hexadecimal RGB values. Unfortunately Delphi’s TColor type assumes a different order. It interprets the hexadecimal value as if it were specified as BGR.

If you want:

  • red you need to specify $000000FF
  • green you need to specify $0000FF00
  • blue you need to specify $00FF0000

So, to get your nice orange, simple reorder the hexadecimal value you pulled from the web, turning

$00F16E00

into

$00006EF1

Et voilà, there is your nice orange on your panel.

Correct Color

Posted in Software Development
Tags: , , ,

How to store enums without losing your coding freedom

Enums are nice!

You have found out about enumeration types and you clearly see the advantages they hold over plain, tired, old integers. They are specific, self documenting, type safe – you can’t pass one type of enum when another is expected. Oh yes, you love enums. And enum sets. No more flags and bit operations for you.

But …

They are not supported directly by databases. Or INI files. Or Json. Or XML. Or any other type of storage for that matter.

Enums as integers

You know you can store their integer value equivalents. It isn’t exactly hard.

To get the integer equivalent of any enum type, simply use the `Ord` function:

type
  TMyEnum = (meOne, meTwo, meThree);
var
  MyEnum: TMyEnum;
  MyInteger: Integer;
begin
  MyEnum := meTwo;
  MyInteger := Ord(MyEnum);
end;

And the other way around is just as simple:

begin
  MyInteger := 2;
  MyEnum := TMyEnum(MyInteger);
end;

Easy enough, but storing enums using their integer equivalents has a couple of humongous drawbacks:

  • The values you store in your database lose all their meaning. Would you know, off hand, what `5` means for some `TAccountType` enum?
    While you might be able to memorize the integer equivalents of a couple of enums, doing so for all enums in your code… Eeks. Personally, I prefer to use my brain power for something more interesting.
  • You lose almost all freedom to change your enum declarations. Yes, you can change the names of your enum members and you can add new members at the end. But removing obsolete members, adding new members somewhere in the middle, reordering members so the order makes more functional sense… Big no-no’s! If you did anything like that you would effectively be changing the meaning of integer values that have been stored using the previous declaration.

Storing enums as their integer equivalents is not such a bright idea then. The walls of Jericho may not come tumbling down on you, but you could very well face support staffers beating down your door equipped with tar and feathers because they’d be dealing with disgruntled users after they upgraded to a new version because that changed the meaning of whatever they stored using the previous version of your software. Ouch…

So, what to do?

Enums with specific ordinal values

In all but the earliest couple of Delphi versions, you can give specific enum members specific ordinal values:

type
  TMyEnum2 = (meFive = 4, meSix, meSeven);

Seems nice?

Yeah. Until … you are some changes down the road and your enum declaration becomes a big mess, or … until you read the fine print that says that when you do so, you lose Run-time type identification on that enum.

Run-time type identification

What? Run-time type identification? What is that? Why do I care?

Run-time type identification, more commonly referred to as Run-time type information and RTTI for short, is what allows you to do stuff like:

Log(Format('AccountType has a value of [%s], which is invalid in this context.', 
  [GetEnumName(TypeInfo(TAccountType), Ord(AccountType))]));

and see a message like this in your logs:

AccountType has a value of [atBusinessOwner], which is invalid in this context.

instead of:

AccountType has a value of [7], which is invalid in this context.

Without it, all you can do is cast to an enum’s underlying basic type: byte, word, integer, …

Enums as strings

Storing enums as strings makes your data much more friendly for human eyes.

And … you regain your coding freedoms.

The freedom to order your enum members as you see fit, is pretty obvious. You are now storing names after all, and restoring values by reading names is not dependent on the position of that name in the declaration.

With that automatically comes the freedom to add new members anywhere in the declaration that makes the most sense functionally. New members can’t after all be stored yet, and reading existing names isn’t dependent on their position in the declaration.

The freedom to remove obsolete members is slightly trickier. You need a way to handle the fact that the now obsolete names still exist in stored data. For enum sets you could simply ignore them. For enums you need a sensible fallback value.

The freedom to rename members is the trickiest of the bunch, but is perfectly feasible. Any rename after all can be seen as a combination of deletion and addition. And thus can be dealt with by using the member with the new name as the fallback value for the old one.

Most significantly, inadvertently changing the meaning of stored data because someone rearranged an enum declaration that he shouldn’t have … well, it is no longer an issue. And that is a huge advantage as it makes your software a lot less brittle.

How to …

Best news is, all of this isn’t very hard to achieve.

The `TypInfo` unit contains the `GetEnumName` and `GetEnumValue` functions which do the work for “single” enums:

// ToString
AccountTypeAsString := GetEnumName(TypeInfo(TAccountType), Ord(AccountType));

// FromString
AccountTypeAsInteger := GetEnumValue(TypeInfo(TAccountType), AccountTypeAsString);
if AccountTypeAsInteger >= 0 then
    AccountType := TAccountType(AccountTypeAsInteger);

This still involves quite a bit of type casting. And you need the same kind of statements for every enum in your code, so you will find yourself creating copy-pasta just to avoid having to retype them again and again.

Type casting and creating copy-pasta are two things you should avoid. The combination should have you trembling at the knees.

Preserving type safety

Hiding the casting ugliness behind a couple of functions would be a lot better. A function like:

function AccountTypeToString(const aAccountType: TAccountType): string;
begin
  Result := GetEnumName(TypeInfo(TAccountType), Ord(aAccountType));
end;

function AccountTypeFromString(const aAccountTypeString: string; 
  const aDefault: TAccountType): TAccountType;
var
  AccountTypeInteger: Integer;
begin
  AccountTypeInteger := GetEnumValue(TypeInfo(TAccountType), aAccountTypeString);
  // Value < 0 indicates the string is not a known TAccountType member name.
  if AccountTypeInteger < 0 then
    Result := aDefault
  else
    Result := TAccountType(AccountTypeInteger);
  end;

allows the rest of your code to remain perfectly type specific and type safe:

begin
   MyLogString := AccountTypeToString(AccountType);
   AccountType := AccountTypeFromString(SomeString, atBasic);
end;

You would however need to create `…FromString` and `…ToString` functions for every enum and enum set in your code. (Unless you can use generics, see further down.)

No fun, I’ll readily admit. But something I have done a lot and think you should do a lot too, because it is a small sacrifice to gain the benefits of less copy-pasta and more expressive and readable code. After all:

AccountTypeToString(AccountType);

reads a lot better than

GetEnumName(TypeInfo(TAccountType), Ord(AccountType));

Generics with extended RTTI

If you are on a Delphi version that supports generics as well as the extended RTTI (D2010+), you are in luck. You can forget about type casting and forget about creating all manner of conversion function pairs. You get completely type safe conversions with just two methods in a “static” (*) class:

(*) If anybody knows the proper “Delphi” way to refer to a class that only contains `class` methods, I am interested.

type
  TEnum<T> = class(TObject)
  public
    // Use reintroduce to prevent compiler complaint about hiding virtual method from 
    // TObject. Breaking polymorphism like this is no problem here, because we don't 
    // need polymorphism for this class.
    class function ToString(const aEnumValue: T): string; reintroduce;
    class function FromString(const aEnumString: string; const aDefault: T): T;
  end;
  
  class function TEnum<T>.ToString(const aEnumValue: T): string;
begin
  Assert(PTypeInfo(TypeInfo(T)).Kind = tkEnumeration, 
    'Type parameter must be an enumeration');

  Result := GetEnumName(TypeInfo(T), TValue.From<T>(aEnumValue).AsOrdinal);
end;

class function TEnum<T>.FromString(const aEnumString: string; const aDefault: T): T;
var
  OrdValue: Integer;
begin
  Assert(PTypeInfo(TypeInfo(T)).Kind = tkEnumeration, 
    'Type parameter must be an enumeration');

  OrdValue := GetEnumValue(TypeInfo(T), aEnumString);
  if OrdValue < 0 then
    Result := aDefault
  else
    Result := TValue.FromOrdinal(TypeInfo(T), OrdValue).AsType<T>;
end;

You use it like:

type
  TAccountType = (atBasic, atDual, atBusiness);
  TMonsterType = (mtGravatar, mtWavatar, mtMysteryMan, mtRetro, mtIdenticon);

procedure RunExample;
var
  AccountType: TAccountType;
  MonsterType: TMonsterType;
  StringValue: string;
begin
    // ToString

    AccountType := atDual;
    WriteLn(Format('AccountType atDual to string: %s', 
      [TEnum<TAccountType>.ToString(AccountType)]));

    MonsterType := mtWavatar;
    WriteLn(Format('MonsterType mtWavatar to string: %s', 
      [TEnum<TMonsterType>.ToString(MonsterType)]));

    // FromString with a known value

    StringValue := 'atBusiness';
    AccountType := TEnum<TAccountType>.FromString(StringValue, atDual);
    WriteLn(Format(
      'AccountType from string "atBusiness" with atDual as default: %d (%s)', 
      [Ord(AccountType), TEnum<TAccountType>.ToString(AccountType)]));

    StringValue := 'mtMysteryMan';
    MonsterType := TEnum<TMonsterType>.FromString(StringValue, mtIdenticon);
    WriteLn(Format(
      'MonsterType from string "mtMysteryMan" with mtIdenticon as default: %d (%s)', 
      [Ord(MonsterType), TEnum<TMonsterType>.ToString(MonsterType)]));

    // FromString with an unknown value

    StringValue := 'Unknown';
    AccountType := TEnum<TAccountType>.FromString(StringValue, atDual);
    WriteLn(Format(
      'AccountType from string "Unknown" with atDual as default: %d (%s)', 
      [Ord(AccountType), TEnum<TAccountType>.ToString(AccountType)]));

    StringValue := 'Unknown';
    MonsterType := TEnum<TMonsterType>.FromString(StringValue, mtIdenticon);
    WriteLn(Format(
      'MonsterType from string "Unknown" with mtIdenticon as default: %d (%s)', 
      [Ord(MonsterType), TEnum<TMonsterType>.ToString(MonsterType)]));

Which produces the following output:

AccountType atDual to string: atDual
MonsterType mtWavatar to string: mtWavatar
AccountType from string "atBusiness" with atDual as default: 2 (atBusiness)
MonsterType from string "mtMysteryMan" with mtIdenticon as default: 2 (mtMysteryMan)
AccountType from string "Unknown" with atDual as default: 1 (atDual)
MonsterType from string "Unknown" with mtIdenticon as default: 4 (mtIdenticon)

As I said this is completely type safe code without any casting (apart from what TValue may do internally). The compiler will sling errors at you when you do something like this:

MonsterType := TEnum<TMonsterType>.FromString(StringValue, atDual);

or this:

AccountType := TEnum<TMonsterType>.FromString(StringValue, mtMysteryMan);

Because the compiler knows that atDual is not a member of TMonsterType and that FromString does not return a TAccountType.

Me like!

Posted in Software Development
Tags: , , , ,

How to make your forms behave consistently without repeating yourself

You are in the Delphi IDE and need to make a new form. It looks like another form you already have, but not quite. You could copy and tweak it. That’s the quick way to get the result you need. That’s the way most of your predecessors have gone about creating new forms. You know, because every time you change something in one form, a seemingly endless stream of “this one too” requests starts flowing your way. And you suspect, or actually you know, that there will be another request for a similar form quite soon.

Wouldn’t it be great if you could change them all in one place and be done with it?

Well you can.

Delphi supports visual form inheritance. That’s not just inheriting from another form’s class, but also inheriting from its layout, its controls and the way they have been wired together, including the ability to “override” individual settings and adding controls just for the descendant form you are working on.

For new forms visual form inheritance is just a matter of adding a new form to your project through [File | New | Other], navigating to [Inheritable items] and selecting the form that you want to use as the ancestor for your new form.

“All well and dandy, but what about existing forms?”, you ask.

That’s slightly more complicated, but only slightly.

  1. You start by adding a new form that will become your application’s “master form”. Do this in the normal way you would add a form: [File | New | Form - Delphi]. Let’s name this form [BaseForm] and save it as [BaseForm_Form.pas].
  2. Add any stuff that you want all your application’s forms to share, controls, other components such as image lists, event handlers, whatever you like.
  3. Open one of your existing forms and show its .pas file. (Hint: use PF12.)
  4. Add BaseForm to the uses clause.
  5. Change TForm3 = class(TForm) to TForm3 = class(TBaseForm). Of course here TBaseForm is the class name of the BaseForm form you just created and TForm3 stands for the class name of your form.
  6. Go back to the visual representation of your form. (Hint: use PF12.) You won’t see any of the stuff you added to your BaseForm yet.
  7. Right click anywhere on the form’s surface and click [View as Text].
  8. Notice the first word in the textual representation of your form. It is object.
  9. Change that from object to inherited so the first line becomes inherited Form3: TForm3.
  10. Right click anywhere in the form’s textual representation and click [View as Form].

And hey presto! Your form shows the stuff that is on your BaseForm. Now all you need to do is clean up the form so its own controls do not cover any of the BaseForm’s stuff and add an inherited; call to all the event handlers that are implemented both in [BaseForm] and your form that is now inheriting from it.

Posted in Software Development
Tags:

Is unit testing literal values pointless?

Well, yes. And no.

You shouldn’t be using literal values anyway. You should be using constants. And when you use constants everywhere, there is absolutely no point in testing whether a constant actually has the literal value assigned to it. No sense in testing the compiler. After all, if you can’t trust your compiler to get this basic stuff right, why are you using it?

And yet…

Some literals are more important than others. If you change these literals, your whole application could break down. Not literally, it won’t crash, but it will no longer function as expected. Despite you being very diligent in your use of constants in lieu of literals. And you won’t find out about it until hours, days, weeks, maybe even months later.

You find out about it when a client is screaming hell and bloody murder because your software stopped doing what it was supposed to do months back. Right after that important update. And now their computer crashed and they find out that they don’t have any data in their backups of your software. How can that be? Nobody has touched the backup functionality for ages …

Turns out that when adding some new functionality somebody inadvertently and unintentionally changed

const
  API_BACKUP = 'backup';

into

const
  API_BACKUP = 'baekup';

Of course this should be covered by integration tests. But integration tests usually take a lot longer than unit tests. When dealing with large code bases often are not part of the developer’s submit checks. And that is hoping that automated integration and regression tests are in place. Quite often integration tests and regression tests are not done by developers if at all… Serving coffee to developers in shops where regression testing is not part of the build or even the release process would leave me bankrupt. I wouldn’t even like to serve coffee to developers in shops where (automated) integration testing is done, but selectively based on the functionality or the units that were touched by a change. Heck, even today someone asked about how to limit the test set because it took so long to run…

Quite apart from the question of integration and regression tests, there is the little matter of the effort involved in addressing the problem once it surfaces. Catching these kinds of “blips” as early as possible helps reduce developer effort. Far easier to solve a failing unit test that pinpoints the cause of the failure than having to figure out why some integration test fell over the next day, or even later or not at all…

So what can you yourself do to prevent the horror scenario described above?

Test a literal against a literal? How pointless can you get?

Ah yes. We don’t want to be pointless.

Still, in the case of literal values that can come from the outside and affect what your software does or how it does it, there absolutely is a point to it. These tests only seem pointless because of their implementation of testing a literal value against the same literal value or – better – testing a constant against its literal value. The point is not in exercising the compiler or the unit test framework, but in guarding against inadvertent and unintentional changes.

Posted in Software Development
Tags: ,

Hello world!

Definition of "on a string"

A developer by trade, an eternal student by heart, I am now turning to teaching.

Or rather: I am now turning to sharing and hoping that someone might learn something from it so I can lay claim to being a teacher in the future.

On the one hand I intend to share what I have learned in almost three decades of software development. On the other hand I will be telling stories of entering fields that are largely unfamiliar to me.

Over the last couple of years I have grown more and more interested in designing software in a technology-agnostic way. It’s how I learned to program way back in the eighties: with flow charts and the design patterns of batch and online transaction processing of the time. I have found that thinking about a software implementation of a requirement without immediately getting down into the details of coding it helps a lot in getting clean solutions. That doesn’t mean a lot of design and design documents up-front. Heck no. I am as allergic to those as most. It can mean drawing informal diagrams with lines and boxes. If only because visualizing something helps understanding it and helps talking with your colleagues about it.

And then there are such things as the development process and designing User Interfaces that create a good User Experience.

I am, or rather have been and sometimes still are, active on three StackExchange sites: StackOverflowProgrammers and UX.

 

Posted in Uncategorized

Like this?

Subscribe and get more posts like this delivered straight into your inbox.
* = required field