Saturday, June 20, 2015

XE8 Update 1 - Update Subscription

Update XE8 Update 1 was released and there is two different versions of the update one for Update Subscription and one without.

For several years now the company where I work as been on an Software & Maintenance for Rad Studio.  The key benefits that I really like are:

  • Support Incidents for when we run into a bug that we can not find a work around.   They work with us to find a solution the problem at hand.   Sometimes it's been a quick and easy problem for the support team and some time more difficult, ultimately we end up with something that works.     One time we ended up with special version of the compiler to solve our problems so we could stay working.    To be honest we don't have to contact support very often at all but it is nice to know it is there.
  • New version just arrive without having to deal with a purchasing nightmare, the budget stays relatively fixed so it's easy to plan the budget around the cost.
  • My entire team can participate in beta tests.
The Support and Maintenance program was recently was renamed to Update Subscription, and some of the terms have changed. Ultimately I believe these changes are good thing, but has some hurdles to get over, that some customers may not like.   Specifically that customer need to be on Update Subscription to the full set of bug fixes.  But some of the new terms allow for the following:
  • Ongoing maintenance for up to 2 yrs for major version and up to 3 concurrent major versions. This really means that our XE6 and XE8 should be getting some of the bug fixes from XE8 coming to it. This is really helpful as we can't keep our entire code base current.
  • Webinars and web content that is just for Update Subscription customers.   
We chose not to upgrade to XE8 as we have projects going on right now.  These projects can't afford a delay that would come with an major upgrade the development tools.   But under Update Subscription have value coming for XE6 and XE7 which we do use.    I look forward to those releases but do wish we had an idea when they may be coming.  

So in short I like the Update Subscription.   


Thursday, February 19, 2015

PPL - TTask Exception Management

Recently I wrote a blog post titled: "PPL - TTask an example in how not to use." The goal of that post was to help introduce some of the new thought processes that are required around multi-threaded programming.

To keep GUI code responsive, threads can be used to keep time consuming code out of the Main thread where the GUI code runs. For example a good usage for this is database access, and calling web services. But, what happens when the database access or web service call fails?   Using the same methodology as the prior blog post of doing it wrong first, this blog post now exists.

I have modified the code from the prior blog post, where we dropped a listbox and button on a form. The new code now raises an exception during the execution.
 
procedure TForm5.Button1Click(Sender: TObject);
begin
  Button1.Enabled := False;
  SlowProc;
end;

procedure TForm5.FormDestroy(Sender: TObject);
begin
  Task.Cancel;
end;

procedure TForm5.SlowProc;
begin
 Task := TTask.Create( procedure
                var
                   I : Integer;
                begin
                  for I := 0 to 9 do
                  begin
                     if TTask.CurrentTask.Status = TTaskStatus.Canceled then
                        exit;
                     Sleep(1000);
                     if I = 2 then
                        raise EProgrammerNotFound.Create('Something bad just happened');
                  end;
                  if TTask.CurrentTask.Status <> TTaskStatus.Canceled then
                  begin
                    TThread.Queue(TThread.CurrentThread,
                    procedure
                    begin
                      if Assigned(ListBox1) then
                      begin
                        Listbox1.Items.Add('10 Seconds');
                        Button1.Enabled := True;
                      end;
                    end);
                 end;
              end);
 Task.Start;
end;
When we run this code and press the button on the form the button is disabled and then nothing happens. The user gets no notification of the error. That is because the TTask has no way to notify the GUI of the exception. That is up to the developer. Never fail I know how exceptions work just wrap the code with a TRY EXCEPT block and raise it in the main thread.
 
procedure TForm5.SlowProc;
begin
 Task := TTask.Create( procedure
                var
                   I : Integer;
                begin
                  try
                    for I := 0 to 9 do
                    begin
                       if TTask.CurrentTask.Status = TTaskStatus.Canceled then
                          exit;
                       Sleep(1000);
                       if I = 2 then
                          raise EProgrammerNotFound.Create('Something bad just happened');
                    end;
                    if TTask.CurrentTask.Status <> TTaskStatus.Canceled then
                    begin
                      TThread.Queue(TThread.CurrentThread,
                      procedure
                      begin
                        if Assigned(ListBox1) then
                        begin
                          Listbox1.Items.Add('10 Seconds');
                          Button1.Enabled := True;
                        end;
                      end);
                   end;
                 except
                  on E : Exception do
                  begin
                      TThread.Queue(TThread.CurrentThread,
                      procedure
                      begin
                        raise E;
                      end);
                  end;
                 end;
              end);
 Task.Start;
end;

The application is run the application and get some ugly error like this one. "Exception TForm5.SlowProc$2$ActRec.$0$Body$3$ActRec in module Project4.exe at 00208756."

The reason we don't get the correct errors is that the variable of E that is created during the during the TRY EXCEPT block is freed by the time the main thread gets around to raising the exception.

So we try changing this segment of the code from this:
 
TThread.Queue(TThread.CurrentThread,
    procedure
    begin
       raise E;
    end);
to
     
TThread.Synchronize(TThread.CurrentThread,
                      procedure
                      begin
                        raise E;
                      end);
Because the Synchronize will halt the current thread and wait for the main thread to execute the the synchronized code. But we run the code and we are back to nothing happening again, but why?

This is because Synchronize captures the exception and re-raises the exception in the originating thread.

AcquireExceptionObject function to the rescue.

Calling AcquireExceptionObject allows you increment the Exception Object reference count so that it's not destroyed at the end of the TRY EXCEPT Block.   Then we can call TThread.Queue and raise the exception in the main thread.
 
procedure TForm5.SlowProc;
begin
 Task := TTask.Create( procedure
                var
                   I : Integer;
                   CapturedException : Exception;
                begin
                  try
                    for I := 0 to 9 do
                    begin
                       if TTask.CurrentTask.Status = TTaskStatus.Canceled then
                          exit;
                       Sleep(1000);
                       if I = 2 then
                          raise EProgrammerNotFound.Create('Something bad just happened');
                    end;
                    if TTask.CurrentTask.Status <> TTaskStatus.Canceled then
                    begin
                      TThread.Queue(TThread.CurrentThread,
                      procedure
                      begin
                        if Assigned(ListBox1) then
                        begin
                          Listbox1.Items.Add('10 Seconds');
                          Button1.Enabled := True;
                        end;
                      end);
                   end;
                 except
                     CapturedException := AcquireExceptionObject;
                     TThread.Queue(TThread.CurrentThread,
                     procedure
                     begin
                       if Assigned(Button1) then 
                          Button1.Enabled := true;
                       raise CapturedException;
                     end);
                  end;
              end);
 Task.Start;
end;
Now when something bad happens in our task the GUI is notified.  Problem solved! But it's not the whole story, there are other ways to manage exceptions with TTasks, and depending on the nature of your code you this option may be better.

You can remove the TRY EXCEPT Block. When a TTask is executed your user code is already wrapped in a TRY EXCEPT block, and it captures the exception for you already.

If I have a reference to the Task I can call Task.Wait(TimeoutValue), which will wait for the time out for the task to complete and return true if it completed.  If it has stopped executing due to an exception an EAggregateException will be raised in the thread that called Task.Wait() if that is the main thread then the user would be notified of the problem.

TTask has the ability to have N number of child tasks. Because of this exceptions that are raised in a TTask are aggregated together in an EAggregateException object. The EAggregateException is defined with the following public interface.
 
  EAggregateException = class(Exception)
  public type
    TExceptionEnumerator = class
    public
      function MoveNext: Boolean; inline;
      property Current: Exception read GetCurrent;
    end;
  public
    constructor Create(const AExceptionArray: array of Exception); overload;
    constructor Create(const AMessage: string; const AExceptionArray: array of Exception); overload;
    destructor Destroy; override;

    function GetEnumerator: TExceptionEnumerator; inline;
    procedure Handle(AExceptionHandlerEvent: TExceptionHandlerEvent); overload;
    procedure Handle(const AExceptionHandlerProc: TExceptionHandlerProc); overload;
    function ToString: string; override;
    property Count: Integer read GetCount;
    property InnerExceptions[Index: Integer]: Exception read GetInnerException; default;
  end;

With this interface a developer can loop through each individual exceptions, or call .ToString which places all the exception messages into a single string.

Hopefully this give a few more bits of insight into exception management with threads and TTask.


Friday, February 13, 2015

Legacy Code: What goes into a unit

I found this blog post in my drafts folder from August of 2013.  I think I was going to add code examples but never had the time.    I guess it's better late than never, even if I don't have code examples.

As a child I watched Sesame Street, and remember the "One of These Things" song.

"One of these things is not like the others,
One of these things just doesn't belong,
Can you tell which thing is not like the others
By the time I finish my song?"



When spending time in legacy and recent code you are going to find code that mimics that song.

When developing code it is best separate out distinct functionality into different units.

Our system contains 80+ console applications.  Each runs on a unique schedule.  Such as Nightly, Monthly, Quarterly, and Annually.

In our GUI application we have a factory that creates some of our screens.   The factory then knows about those screens.   Using this unit in one of our console applications is not needed.

One day someone on my team noticed several of our console applications had dramatically increased in size.    Looking at the code it was because several method were added to an existing unit that required access to the factory, although none of the console applications actually needed that code.  We had to move that new method to where it belonged.    

When working with an existing piece of code, and you are adding functionality you need to ask does it belong.    One clue to help is if you need to change the uses clause you must be aware of what you are linking not only to your unit but all the other units that use your unit.   When designing new code care should be put into keeping the visual interface out of the underlying business rules.     Functionality should be grouped it a way that when using unit X you are not linking code for units A, B, and C that will never be used.

But now comes the problem with legacy code.  You are not adding new code, your modifying the spaghetti mess that was left for you by someone else.    What should you do?
  1. Attempt to understand the existing code... Sometimes this is the most difficult part.
  2. If the code can be separated into two different units without changing the actual implementation details then it's far less risky to separate the units.   Then all your doing is adding the new unit to the uses clause of the units that used that code where needed.   Beware if your code uses RTTI this can still break things, depending on how the RTTI was used, specifically since the unit name could have been used as text either in code or an external file.
  3. If separation of code can not occur without changing implementation details greater well then you need decide if it's worth it.    Unlike the Matrix movie you get to find out how deep the rabbit hole goes before you take the red or blue pill.  The deeper hole, the bigger the problem. Key factors I use in determining if it's worth changing the design to separate the implementation.
    • How many places is the unit used...
      • How many places is the unit used, directly. (i.e. in the uses clause of another unit)
      • How many places is the unit used, indirectly. (i.e. In another class you inherit from a class that was in the prior unit, then you need to find out how many places the new unit is used. This search will continue on recursively until the unit is no longer indirectly used.
    • This allows you to answer some of these questions...
      • How critical is this piece of code to my application?
      • How much of the application will have to be retested if I change this code?
      • What benefits do I get from changing this code?
    • Sometimes going through this exercise I have determined what I thought was a  small problem has turned into a very large problem.    
Clear separation of concerns is critical to long term maintainability of a program.





Thursday, February 12, 2015

PPL - TTask an example in how not to use.

Delphi XE7 contains a new Parallel Programming Library, which is really powerful and easy to start using.   But it can be something that can be done wrong, and not realize it until it's much later.

Lets take the following fictional example.

There is form with a single button and a list box.   When the button is pressed a long process occurs, when the process is complete it needs to add an item to the list box.

This could be done without Multi-threading.
 
procedure TForm5.Button1Click(Sender: TObject);
begin
  Button1.Enabled := False;
  SlowProc;
  Button1.Enabled := True;
end;

procedure TForm5.SlowProc;
begin
  Sleep(10000); // simulate long process
  Listbox1.Items.Add('10 Seconds');
end;
During testing it is determined that the user needs to be able to re-size the application while the long process is running.

But never fail XE7 has been released with TPL and TTask to the rescue.

The first iteration SlowProc is changed to use a task.
 
procedure TForm5.SlowProc;
var
 Task : ITask;
begin
 Task := TTask.Create( procedure
                begin
                  Sleep(10000); // simulate long process
                  Listbox1.Items.Add('10 Seconds');
                end);
 Task.Start;
end;
Run the application and it appears to work.   Then further testing reveals a couple of problems.
The first being that button can now be pressed multiple times.   The second is that if the form is closed form right after pressing the button an few seconds later and access violation occurs.   
  • The reason the button can be pressed multiple times is that the enabled is set back to true after the task is started and not 
  • The cause of the access violation is that the code is still executing after the form has been freed.
The second iteration the code is now changed:
 
procedure TForm5.Button1Click(Sender: TObject);
begin
  Button1.Enabled := False;
  SlowProc;
end;

procedure TForm5.SlowProc;
var
 Task : ITask;
begin
 Task := TTask.Create( procedure
                begin
                  Sleep(10000);
                  if Assigned(ListBox1) then
                  begin
                    Listbox1.Items.Add('10 Seconds');
                    Button1.Enabled := True;
                  end;
                end);
 Task.Start;
end;
This now appears to work.  But, now there can be an up to 10 second delay before the application stops running after the form closes.  Now this is fictional example that has just a single sleep() call.   This can occur with real world items as well, but often there are several steps in the method, so I am going to simulate multiple steps, with a loop 0..9 with a call to sleep(1000);
 
procedure TForm5.SlowProc;
var
 Task : ITask;
begin
 Task := TTask.Create( procedure
                var
                   I : Integer;
                begin
                  for I := 0 to 9 do
                     Sleep(1000);
                  if Assigned(ListBox1) then
                  begin
                    Listbox1.Items.Add('10 Seconds');
                    Button1.Enabled := True;
                  end;
                end);
 Task.Start;
end;
Now the fictional example show multiple steps.    But it does not solve the problem with the application running for up to 10 seconds after the main form is closed.     When the form is begin closed the Task needs to be notified so it can stop running. This can be be done with the ITask.Cancel method.
To resolve this a third iteration is produced.

Task : ITask;  has been moved from SlowProc, and is now a member of the form.
 
procedure TForm5.Button1Click(Sender: TObject);
begin
  Button1.Enabled := False;
  SlowProc;
end;

procedure TForm5.FormDestroy(Sender: TObject);
begin
  Task.Cancel;
end;

procedure TForm5.SlowProc;
begin
 Task := TTask.Create( procedure
                var
                   I : Integer;
                begin
                  for I := 0 to 9 do
                  begin
                     if TTask.CurrentTask.Status = TTaskStatus.Canceled then
                        exit;
                     Sleep(1000);
                  end;
                  if Assigned(ListBox1) then
                  begin
                    Listbox1.Items.Add('10 Seconds');
                    Button1.Enabled := True;
                  end;
                end);
 Task.Start;
end;
This all appears to work and is released.   Sometime later in real world strange behaviors and errors are reported on this screen.    After research it is learned that the GUI is not thread safe, so we use a TThread.Queue, to the GUI code to run in the main thread.
Now onto the forth iterations of the code
 
procedure TForm5.SlowProc;
begin
 Task := TTask.Create( procedure
                var
                   I : Integer;
                begin
                  for I := 0 to 9 do
                  begin
                     if TTask.CurrentTask.Status = TTaskStatus.Canceled then
                        exit;
                     Sleep(1000);
                  end;
                  if TTask.CurrentTask.Status <> TTaskStatus.Canceled then
                  begin
                    TThread.Queue(TThread.CurrentThread,
                    procedure
                    begin
                      if Assigned(ListBox1) then
                      begin
                        Listbox1.Items.Add('10 Seconds');
                        Button1.Enabled := True;
                      end;
                    end);
                 end;
              end);
 Task.Start;
end;
Now we have an finally application that should work without error.     Granted this a fictional example, but it shows just some of the pitfalls that can come with multi-threading.  Each is relatively easy to deal with.   

Tuesday, October 28, 2014

Introduction to GIT

This week at CodeRage 9 I will be presenting.  "Introduction to Distributed Version Control"

My session covers the basics of how a Distributed Version Control System works.   I focus is on GIT but it applies to Mercurial - Hg.

Here is a link to the slides I used for the first 10 minutes of the presentation.

I used 3 clients in the Demo.


I highly recommend learning the command line tools,   there are two great demos for GIT available that I reference in the presentation.


What I don't cover heavily in the introduction is branching.  Understanding this allows you to really leverage the power of Distributed Version Control.  Atlassian has a great tutorial on GIT but the best part of this document is how it compares the various workflows you could use with GIT.

If your coming from SVN and moving to GIT I created this cheat sheet to remember the common commands.

Another thing I wanted to cover but did not have time was options when it comes to hosting your git repositories that I have used.

Public and Private Repositories outside your firewall:

  • GitHub
    Great visibility for open source projects.
    Priced per Private Repository, with unlimited users.
    Public Repositories are free.
  • BitBucket
    Good Visibility for open source projects
    Priced per user, with unlimited repositories.  5 and under users are Free.
    Public Repository with unlimited users are free.
I have found that I create several small repositories,  and the pricing for BitBucket works well for that.      So I tend to put my private repositories on BitBucket and my Public Repositories on GitHub.

There are several products that are designed for behind the firewall.  I have only used the free Bonobo Git Server.    Really want to switch to Stash, but I have to wait right now due to budget limits.









Friday, September 12, 2014

VCL or FireMonkey - XE7

In a previous blog post I mentioned we are starting a rewrite of an existing application using Delphi XE7 .     One of the comments was raised if we are going to use VCL or Firemonkey.

It was decision we took quite seriously.    Using Delphi  we spent a few days developing Firemonkey sample applications and compared them to what we could do in VCL.    Firemonkey is quite nice.   It has some really nice way of presenting data.  However, ultimately we have decided on writing our application using the VCL.  

Primary reasons we to considered using VCL
  • Existing libraries that can be reused.
  • We have written 30+ Custom Controls, that we can reuse.
  • Still maintained and enhanced.
Reasons we considered Firemonkey
  • Can create some really pretty applications, animations, etc... that are more time consuming to create under VCL.
  • Gets most of the new features in the Delphi libraries.
  • Gives a potential to go cross platform   However, we have no requirements for this.
Reasons we choose the VCL over Firemonkey.
  • We have no need to go cross platform with this application
  • VCL applications look like the belong on windows, Firemonkey applications look like that are made to work on Windows.
  • Firemonkey is a fast moving target, and Delphi upgrades may be more difficult if we skip versions.   
  • VCL is still getting improvements (But since it's mature it's not as difficult to adapt)  but it's easier to upgrade between Delphi versions.
  • Existing code libraries can be reused.
  • Cost we don't have to buy or develop controls we already have.
  • Specific VCL controls - (Where we could not find a equivalent in Firemonkey)
    • TImageScrollBox in the Envision Library  (Really nice way to view images)
    • TRichViewEdit from the TRichView Library (Any RTF editor may work)
    • TTrayIcon support 
    • TWebBrowser - HTML Viewing Component for desktop, we see it there for mobile.
The good news is that XE7 supports both and I have a decision to make.    I know some have said get rid of one or the other.    I personally like having the choice, they each meet a different set of needs.   

That being said part of my hope is that some of the reasons we chose VCL or Firemonkey are removed are removed in future releases.  I also really want supported interactions that allow us to mix Firemonkey and VCL Code, such as a TFrame in VCL or Firemonkey being able to be embedded into VCL or Firemonkey form.      

Regardless of the the framework choice,  XE7 appears to be a good choice for development and has compelling reasons to use over XE6.



Thursday, September 4, 2014

Product/Component Vendors and XE7 Support

Here are the most prominent 3rd Party components(That don't ship in the Rad Studio/Delphi products) that we use.   We may or may not use these in the application we will be rewriting in Delphi XE7 as we have make lots of decisions first such as VCL or Firemonkey.

2 Days after XE7 was released and some people are are on top of there game.
THANK YOU!

The following already support XE7

Patiently waiting on Support for XE7 

I really like what TMS did for upgrading to XE6 and now they have done the same for XE7.