Saturday, October 5, 2013

Delphi Experts and IDE Plugins I Love - Part 2: CNPack

In Part 1 of this series, I covered GExperts, and now I am moving on to what is arguably the most powerful, and most useful open-source expert plugin for Delphi.

It works with very old versions of Delphi (including Delphi 7 and Delphi 2007) which are still widely used out there, it adds some features to Delphi 7 and 2007 that became standard in later versions of Delphi, such as line numbering, and adds features like structure highlighting that are also available in one of the very high quality commercial IDE Expert tools like Castalia, which I'll be covering in a separate article.

I don't believe very many delphi Developers start out with any of the following goals:


  • I would like to write units that are over 50,000 lines in length.
  • I would like to write methods with Cyclomatic Complexities over 1000.
  • I would like to nest begin and end blocks more than 20 levels deep.
  • I would like to write units that have methods that are over 5000 lines long.
But if very few of us start out wanting to do the above, it is still kind of scary how many of us manage to unlock the above dubious achievements. And even if we do not manage to unlock them ourselves, some of us get to work on codebases where the previous people working on the system made things less tidy, less sane, and less easy to follow.  When you can't go in and rewrite every line in a 2 million line application, sometimes a tool can help you not to get lost in the forest.   This is one of the reasons why structure highlighting and context indicators are so useful in your editor.

Imagine you have some code like this, I'm going to construct an artificial example, because I can't really show you the commercial source code I work on, as it's proprietary and may contain trade secrets of my employer.

  object1 := TSomeObject.Create(param1,param2,param3);
  try
   try
    if  CustomerFlags.EnterpriseEdition then
    begin
         // 80 lines of code, including several WITH
         // blocks.
    end
    else if CustomerFlags.ProfessionalEdition then
    begin
        // 200 lines of code, more WITH statements.
    end
    else begin
       // 300 lines of code, yet more WITH statements.
    end;
  except 
  // exception  handling. 
  end;
 finally
    object1.Free;
 end;

If anyone comes up to me and says, "you shouldn't write large blocks of unreadable code that have many nested levels of begin, end, and you should definitely not be using WITH", I'd say, "fine, you're right, now go away,  I'm trying to teach you how to read messy Delphi code, not how to write good code".

If the amount of code inside the blocks is small enough that the code fits entirely on the screen, and the person doing the indentation made it line up, it's probably easy enough to visualize the above scopes.

However, because I dare not show you a 1500 meter tall bitmap here, I'll just show you a method that barely fits on the screen, and you can judge for yourself whether or not methods 100x and 1500x larger than this would also benefit from the following highlighting improvements, and lines connecting the begin and end statements:





As  you can see above, each set of scopes (the begin and end of the procedure, the finally that goes with the try, the begin and ends that go with the if statements) has a different color, and there are lines connecting the begin and end statements now.

If Delphi's code formatter supported reformatting single methods, I'd say, use it on each method,
as you modify it, because reformatting entire modules causes too much difficulty with version control systems.  But the combination of highlighting as above, and completely rigid formatting in the One True Delphi Indentation Style (shown above) will lead you into the Holy Land where Programmers, Customers, and Bosses all Dwell in Peace and Prosperity. 

Just to be contrary, I think I'll start using an Egyptian Braces style, a-la the K&R C book, every now and then.  Just to rile up certain people. You know who you are. Everybody loves a holy war. Anyways, onwards.

What else does CN Pack have?

Too much stuff, frankly. Here's where I show you how to turn everything off and then turn on the bits you like. Click CnPack > Options, then click Advanced, which opens a new window, with two tabs, go to the Advanced tab, and then click this button, to Deselect All Wizards. Then Restart Delphi.
Now you have a CNPack menu that is empty, and basically no features. Now you can add the features you want, one at a time, and learn them, and then add another. I find this a much easier way to learn the CNPack features than being thrown into a virtual labrean tar-pit of options.




Okay now let's turn some stuff on.

The stuff you probably want to turn on first is Source Highlight Enhancements, that's what does the pretty lines and colors for begin and end, that  I showed you above.  If that's all CNWizard did, it would be a great thing.  But wait, there's more.    Try out the Form Designer Enhancements. If you turn them on and then go into the form designer, you'll see new stuff and it will be easier to associate in your brain what feature does what, if you turn them on, try them out, and if you don't absolutely LOVE it, turn it off again, until you need them.

Here's what I have turned on, note how spare my selections are:



If you are overwhelmed with the decision set you face, try my settings.  You might find the Uses Units Cleaner a life saver, I know I do. It's basically magic. If you have a disgusting Uses Clause, that uses 100 units in the interface uses clause, and 100 units in the implementation uses clause, are you certain that all of those are necessary?  This expert will find and remove units that could be removed, speeding up compilation, decreasing the number of namespace pollution and making code-completion in the IDE more accurate, among other things.  Bad Uses-Clauses Hygiene is an epidemic, because most Delphi developers are scared to touch a Uses clause.  Most people just go in and add an item to it, and then hope for the best.  Understanding, grouping and organizing your dependencies, once CNPack has minimized them to the real minimal set that you need to build that unit, is a good step towards understanding the ball-of-mud that your application is becoming, and start turning it around to the point where it is a clean, and well architected piece of software.

The tab-order wizard is another one that I'll recommend you check out.  It's the best tab-ordering helper for Delphi forms I've seen. First it shows you the tab order visually while you are in the form designer at all times:



If you don't keep your application's tab order sane and how users would expect it, your users hate you. I'm telling you this straight.   Many Windows application users navigate their forms with the Tab key and like keyboard shortcuts, tabbing, and keyboard accessibility to work properly.  Tab ordering, a good set of keyboard hotkeys, and so on, are key to expert users loving your system.  Give them some love, test your application's tab ordering before you ship it, and when you have a grotesque mess of a form with 1500 controls, and you use the IDE Tab ordering dialog, it only shows you one level of your form at a time. In the example above, that's fine, but what if your form looked more like this:




At least the out of order problem is now visible. Now let's fix it:



A little warning message comes up, which you can ignore or read, and as all it does is normalize your tab orders, I really think it's pretty safe. But you are using Version Control right? If you don't like what any of the CNPack wizards does, just revert your code instead of committing, right? If you're not using version control, please go get Mercurial and learn it, and then come back, before you go any farther.   Thank me later.

Anyways, here it is, all done:


Wait you say, that's not how I would have ordered it.   Well, I did the above as an example so you can see what it does.   It starts at the top left most pixel of the screen, and orders the tabs from top to bottom, left to right.  Since the button on TabSheet2 is slightly ABOVE the other, it gets the first tab position inside that tab sheet.    So many you'll want to make sure you have all the alignments and positions on your form set properly first, and then try this wizard out.

You can even turn on "Auto Update Tab Orders" in the CNPack menu, but I think that's overkill, as you may want to manually update tab orders at some point, then review them, then save and check in your work.  A much saner workflow than leaving the whole thing on Automatic at all times.

GExperts has a very nice dialog that is better than the single-layer dialog in the base IDE, but I like CNPack's dialog-box-free way of working right in the form designer.  (You can use Delphi's WYSIWYG form designer as your tab order verification screen.)

Anyways there's more, but I think this is a long enough blog post. Next time, part 3, Model Maker Code Explorer, a commercial tool, and worth every penny, just like Delphi is a commercial product, and worth every penny.  If only Delphi was cheap like Borscht, like Code Explorer.  















12 comments:

  1. Delphi's source code formatting works with selected blocks - so you can just highlight a function and press CTRL+D - which would allow you to reformat individual methods, not entire units.

    ReplyDelete
  2. Hey that's fantastic! When did that get added? Now I'm going to use this a lot. (Select function, Ctrl+D)
    Warren

    ReplyDelete
  3. On the other hand, the formatter for GExperts allows you to protect blocks of code from being reformatted.

    As to CnPack, the subject of this chapter, I second the comments on the Uses Cleaner, which is invaluable when dealing with legacy code. The structural highlighting saved my sanity in a previous employment, where previous coders must have come from Warren's company. Also nice is the ability to export text as HTML/RTF for insertion in Word. (Yes, I do write docs.)

    ReplyDelete
  4. Replies
    1. @DonaldShimoda there is an experimental GExperts XE5 build since mid September http://delphi.org/2013/09/gexperts-for-xe5-experimental-build/

      Delete
  5. So build it yourself, Donald! :-) It's open source.

    Okay, so I built it for you. You can grab it here:

    https://docs.google.com/file/d/0B07SrKpE8ErmdDRsMmZVQy0xanc/edit?usp=sharing

    ReplyDelete
    Replies
    1. Thank YOU, it was very usefull for me!

      One question, do you know a way to change the editor tabs? I have so many open files and I wanted to have them visible. Looks like multitabs are not possible?

      Delete
  6. I am using CnPack and am seeing an odd behavior, but can't figure out how to turn it off. If I select a word in the source and press delete it deletes the character following the selection, not the selected word. And when I select a block of code it is the same. Even Paste will paste after the block of code rather the replacing the selected code. I don't like this, but have not found what is causing it.

    ReplyDelete
    Replies
    1. I have seeing it already. If that behavior happens in just some units and not in all units, it looks like an already known (by myself) Delphi issue. You will fix it only closing and reopening the related units. In some cases it will be neccessary close and reopen Delphi.

      Delete
    2. Very late to the party - but this is due to "Persistent Blocks" option in the editing. For some unknown reason this occasionally gets toggled on, even if the editor properties say it isn't. Too fix, go into the editor properties, and check then uncheck the option, then OK

      Delete
  7. Now CnPack IDE Wizards has Code Formatter Wizard for Pascal.

    The latest version is 1.0.8:
    http://www.cnpack.org

    ReplyDelete