Thursday, October 12, 2006

Brief guide to building a Delphi IDE AddIn

Someone in the Delphi IDE newsgroup asked the question, "Is there a guide anywhere about writing IDE addins"? After experiencing my own pain in building a small add-in (or is it plug-in?), I decided to make up a quick post. The answer to his question is a resounding "no." Well, you might consider this as something of a guide, but I had better luck getting started with these 2 docs:

The first thing to note is that I found that writing the add-in in .Net seemed to make it work for both Win32 and .Net Delphi projects.

When I started mine, I was really naive and thought there'd be some API with calls like GetStartNextMethod or something. You only get the buffer.

So here's the start - getting the source editor (sorry - snippets lost their formatting - too much work to put back in using blogger):

using Borland.Studio.ToolsAPI;

public class SourceViewer // base class
{
protected IOTASourceEditor fSourceEditor;
public IOTASourceEditor sourceEditor { get { return fSourceEditor; } }
public SourceViewer()
{
IOTAModuleServices moduleServices = BorlandIDE.ModuleServices;
if ( moduleServices == null )
{
fSourceEditor = null;
}
else
{
try
{
fSourceEditor = moduleServices.CurrentModule.CurrentEditor as IOTASourceEditor;
}
catch
{
fSourceEditor = null;
}
}
}
}


Then you use the source editor to get a reader to get the text of the buffer:

IOTAFileReader reader = fSourceEditor.CreateReader();

private string getRawSourceText( IOTAFileReader reader )
{
const int READ_CHUNK = 1600;

if (reader == null)
throw new Exception( "No file reader" );

StringBuilder sb = new StringBuilder();
System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
Byte[] source = reader.Read( READ_CHUNK, 0 );
while ( source.Length > 0 )
{
sb.Append( enc.GetString(source) );
source = reader.Read( READ_CHUNK, 0 );
}

return sb.ToString();
}



To get the IDE to integrate your AddIn, implement IOTAMenuWizard:

public class TestPlugIn: IOTAMenuWizard
{

public static void Register()
{
IOTAWizardService WizService = (IOTAWizardService)BorlandIDE.GetService( typeof( IOTAWizardService ) );
wizardID = WizService.AddWizard( new TestPlugIn() );
}
....

Then implement the other methods of IOTAMenuWizard such as execute and enabled. I wanted mine to be enabled when any source file is open (referencing the first class above):

return new SourceViewer().sourceEditor != null;

Once your assembly is ready to go, register it with the IDE (so the IDE will load it on startup):
  • Create a key under HKEY_CURRENT_USER\Software\Borland\BDS\4.0\Known IDE Assemblies.
  • Give the key a name (don't recall if the name matters / where it might show up, but I think it has to have a name).
  • Add the path to your assembly there.

Friday, October 06, 2006

Ridding (not riding) the Range

I added a suggestion to David's list of potential improvements that we all discussed in Minneapolis. He asked me to describe why it's a problem and what I think the solution is...

Why the Range global is a problem
  • It's like a master key that tightly couples all parts of the system. We will not be able to separate annuity from life w/o either eliminating it or duplicating it for both.
  • It's a global (or rather a collection of globals; same thing). Reference my blog post for reasons why this is bad.
  • It prevents the furtherance of OO development in the system.
I Object!
Objects are objects for a reason. They should encapsulate their data. The range object is a circumvention of OO. A given product will manipulate any number of range variables for varying functionality. So rather than being able to look at the product class methods and members to determine it's behaviour, you may have to guess what range variables it manipulates to do so. Variables should be owned by the proper object that manipulates them. Range variables are manipulated by any other object in the system. This leads to conditional code multiplied all over. So instead of this:

BaseObject.DoThis;

We have this:

If Rng.Something then
SpecificObject.DoSomething
else if Rng.TheOtherThing then
OtherSpecificObject.DoSomething;

If the individual objects properly encapsulated their data, we wouldn't have this problem.

Solution
I don't see any other way than to:
  • Forbid adding any new variables to the range object (with exceptions for exigent circumstances).
  • Start removing it's variables. For each:
    • Search the system for it's use.
    • Determine which object at which level in the heirarchy should encapsulate the data.
    • Move the variable to the appropriate object.
    • Adjust the code that references it.
  • Whenever sets are encountered, this should be seen as an indicator that a new object may be needed. Sets (and their brother case statements) should be rare in OO (1). Unlike an object, they encapsulate nothing. So if you look at a set in code, you learn nothing. In order to learn how the system manipulates the members of the set, you would have to search the system for all references to the set. When you do this search, you will no doubt encounter many case statements and for loops. If the business logic were instead object based, you would simply call BaseType.DoSomething and polymorphism would handle the conditional behaviour of the members of the set. Thus you don't end up with case statements and for loops that usually start out at a manageble size, but enevitably grow into something that is very difficult to maintain.
No doubt this will initially lead to some other objects becoming bloated, but this is a process. The bloated objects should, in turn, be distilled into more granular objects.

1) Refactoring, p. 34, 82

Tuesday, October 03, 2006

Good Javascript Reference

I was working on something for our new App Wizard Search today and came across this Javascript reference on the Mozilla developers' site.

http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference

If you go up a level or two there are all kinds of sections about various web development topics as well. It is all geared for Mozilla but with some consideration it would most likely be applicable across most browsers.

Friday, September 29, 2006

Regular Expression Tools

Since Kelly has been developing some regular expressions for modifying VB6 code in preparation for migration to VB.net (because he needs some things to end up differently in VB.net than the built in upgrade wizard would cause them to be), I had regex on the mind and decided to listen to this podcast about them.

If you've never used them before, regular expressions are basically just strings with special characters and placeholders for manipulating (not just finding) text. This is one I've used a few times to search through code. I need regex because I want to find all ocurrences where any index of SameArray is modified but the identifier within the brackets varies.

SomeArray\[\w+\]\s+:=
  • The text between the array index brackets can be anything. 'w' indicates anything that can be part of a language identifier.
  • The brackets themselves are escaped because they normally delimit character sets.
  • The '\s' indicates a space. There might be more than one space between the right bracket and the assignment.
  • The '+' indicates one or more of the preceeding token.

This is a simple expression that makes for a much better search. I didn't have it until now, but Regulazy is a graphical tool that is perfect for creating such expressions quickly. Regulazy creates .Net regular expressions, and something new I learned on the podcast is that there is no "standard" implementation for regex. The tool I use to search through files with the above expression is a simple utility done in Java, and this expression works for Java too. The basic tokens are the same (kind of a standard, I guess), but each implementation varies; for example, .Net allows you to name groups and refer to them in other areas of your expression. Perl allows you to use variables in the expression.

The podcast gave great resources for creating the expressions, but not for using them. I haven't come across many good utilities for searching files with regex expressions (although it wouldn't be much work to write one with the .Net System.Text.RegularExpressions namespace). Neither Notepad++ nor the grep search tool that comes with the GExperts suite that we use would run my expression (even though it uses only simple tokens that should be the same across all implementations).

Here's the thing about regex; they can be very powerful. A single expression can be used as a substitute for a class with tons of conditional code. But then, expressions like this are not very maintainable since they end up looking like a cartoon character's long outburst of profanity - that's the trade off. One thing that helps a bit is that you can insert comments in .Net expressions like yay: (?# Look Mom! There's comments in my expression! ).

Despite the complexity, some validation requirements are a no-brainer match (no pun intended) for regex - like validating email addresses. I wrote an email address validation routine/object once - not easy after reading through the actual RFC for email addresses. The .Net expression for this and other very common validations are available on MSDN. There are many more available on regexlib.com (along with an online expression tester). I'm sure the expression that Kelly developed, no simple expression that, would be a good addition to regexlib.com.

Even the regex guru guest of the podcast recommended that they should be used sparingly. If you do want to create one, use his regulazy tool. That will get simple ones created for you very easily. Then, if you need to create a sophisticated expression (replacements, named groups, ect.), use his Regulator tool. This app includes things like intellisense for expression creation. It will also interface with regexlib.com to help you find a pre-existing expression that may suit your needs. Both are free!

Another very useful resource that isn't regex, but is related is logparser.com. This site maintains utilities that allow SQL like querying of commonly used log files (like IIS or SQLServer).

One more note for .Net regex; if you are using the regex object to match repeatedly over alot of text, you can pass a param to the regex class that will cause the runtime to create an assembly (a class hard coded to meet your expression's specs) and run that assembly for speed. Cool, huh?

Wednesday, July 12, 2006

Small Methodology

Judging from the amount of posts recently, I think I'm writing this to myself. Oh well; dear diary...

In this post I'm extolling the virtues of smaller methods.

When I say small, how small do I really mean? Several times1, I've read no larger than what fits on a single screen although that's certainly debatable.
Code Complete2, the best code construction book ever, has a section titled "How Long Can a Routine Be?" It is surprisingly liberal, basically recommending smaller methods yet presenting some evidence that larger methods are not necessarily bad. It almost contradicts itself in another section, "Scope", wherein it recommends "breaking related statements into separate, smaller routines". The latter advice is given in the context of variable scope, so I suppose the lesson there is that length isn't as much a concern if there are few local variables involved. But... I don't ever recall reading anything advising larger methods. The archives of this site contain no end of examples of huge (edited) routines that caused no end of problems.

In any case, here are some pros for smaller methods:
  • Much easier during maintenance to find the area of code needing change (let's see I know I need to change something somewhere in PlayThatFunkyMusic, but it's 1000 lines long... where?). Note that you are in maintenance mode even when first developing the code.3
  • Code is so much more readable. Instead of trying to figure out if the next 10 lines are relevant to my problem, I read a MethodNameThatTellsMeWhatItDoes.
  • You end up with more efficient code since it's easier to see what you're doing. If you keep adding more and more to a method w/o breaking it out to additional methods, there's a good chance you'll do more than what's necessary. An example that surely came about in such fashion that I came across was a 600+ line method that had a nested 150 line if statement. The nested if checked the same thing as the outer if, but had an else. The compiler probably didn't give the unreachable code error because it was confused - or else I was confused. Either way it made for a very difficult debugging exercise.
  • Communication of intent. Smaller methods with descriptive names are prefferable even to comments. Intent is best communicated in structure and naming. From Martin Fowler, "A block of code with a comment that tells you what it is doing can be replaced by a method whose name is based on the comment. Even a single line is worth extracting if it needs explanation".4

And here are some cons:
  • Function call overhead. Not! Only in a case of a method/methods being called zillions of times would function call overhead (the cost of setting a spot in the register, adding to the stack, transferring execution to the new method, etc...) make a difference. Besides, we never know when the compiler inlines methods under the covers eliminating this perf cost altogether.
  • Developer has to navigate around among more methods to get to where he/she needs to be. There is some validity to this argument, but I think surely outweighed by the benefits and by the fact that there are ways (bookmarks, rapid finding [are you using GExperts?] and navigating among methods) to compensate for this.
In Extreme Programming Adventures in C#5, Ron Jeffries (basically the founder of the XP movement) advises, "The 'right' structure for a method that does more than one thing is called 'Composed Method.' Always create a method that is composed of nothing but method calls, all at the same level, rather than expanding any of the ideas out in line." His example refactors this:

public InputCommand(StringReader reader)
{
lines = new ArrayList();
String line = reader.ReadLine();
while (line != null && line != "*end")
{
lines.Add(line.TrimEnd());
line = reader.ReadLine();
}
CleanTheLines();
}

into this:

public InputCommand(StringReader reader)
{
ReadLines(reader);
CleanTheLines();
}

So each method that does multiple things makes calls to other methods. Once a method does one distinct thing, it no longer needs refinement. It's certainly my experience that such code is very easy to follow.

Oh, and remember - BDS (and Visual Studio 2005) make extracting methods pretty easy. Code on, brothers and sisters. Oh wait, I'm just writing this to myself...

Notes
1) Most recently in "Rules for Developing Safety Critical Code", IEEE Computer, June 2006; Code Complete also mentions this rule of thumb.
2) Code Complete is Avail on the Intranet even though a search for it shows no results.
3) Interview with Andy Hunt and Dave Thomas, "All Programming is Maintenance Programming".
4) Refactoring, Page 77.
5) Extreme Programming Adventures in C# is Avail on the Intranet. Reference Chapter 9 under section, "InputCommand Refactoring".

Friday, May 12, 2006

Intro to WinFX

Jenny and I attended a MS event about WinFX on the 12th. Hopefully, this post will serve as a mini intro for anyone else interested in Microsoft's upcoming technologies.

WinFX is basically MS's new API for windows. It can be accessed via .Net 2.0 code and will come bundled as part of the next OS, Vista, as well as being available to install on WinXP and Server 2003.

There are 3 pillars of WinFX that all follow the somewhat famous architecture outlined by Jack Greenfield in his article, "Software Factories." Greenfield was formerly a bigwig at Rational, where everything had UML as it's foundation and was supposed to be the shiznit, but fizzled. Now his new ideas of using useful models to build real software (though there's more to the article) are becoming a reality. So the model is the code - just as you can design a form in our current tools and it is the actual form you run, so you can create models in a designer and it is the actual logic.

Another main point about the new paradigm of development is that imperative and declaritive code can be separated much more easily. So all the details of what you want to do (connect to this data store, use this protocol, make the interface look like this) are very easily separated from how (business logic). All the declarative code goes into markup (XML or XaML).

So the 3 pillars are:
  • Windows Presentation Foundation - The all new UI.
  • Windows Communication Foundation - Web Services (or services that may reside on the same machine) enabling a service oriented architecture at any level.
  • Windows Workflow Foundation - Modeling as described above.
Presentation Foundation (formerly Avalon)
The UI uses "XaML" to represent any damn thing you can imagine. The graphics engine supports regular bitmaps and vector graphics. There is a pure UI designer piece called "Expression" whose graphics manipulation capabilities I can't adequately describe. With XaML you can describe how you'd like a graphic to rotate, zoom (and vector graphics are crystal clear at any zoom factor), or whatever. The controls you create that display all these graphics can reference templates for consistency. Then the XaML is transferred to the developer. Here's a video of a real application utilizing the presentation foundation. One presenter mentioned that you will be able to run the same XaML on the desktop as is the browser, but this didn't seem to add up as there was a different Expression tool for web pages...

Communication Foundation (Formerly Indigo)
Connect to anything using any transport mechanism with the same type of interface. In a sample app, the presenter had connected to web services, but had also wrapped up communication with a regular human interfaced web page (querying availability of a product on a retailer's web site) for use in the same fashion. So you communicate with another WinFX local service the same way as a web service.

Workflow Foundation (Formerly I don't know what)
There used to be another piece to the WinFX pie called "WinFS," the "FS" for file system, I presume. This piece dealt with an entirely new way to manage files. Files had extensions (not in the name) that allowed for sophisticated organization and retrieval. I'm not sure how much of that stayed in WinFX; as far as I can tell workflow foundation only deals with what I discussed above about being able to visually design your application's logic.
You drop activities down on a design canvas and wire them together as a sequential diagram, a state machine (basically event driven), or as a rules driven machine. You can even simply set a breakpoint on your activities and then step into them if they have additional code behind them. I think this will really encourage code re-use and third party vendors are already making lots of useful "activities". So one of the out-of-box ones (I think) would be send an email message. Drop down that activity, set some of it's properties and let 'er rip. Activities can contain other activities, so you could even have a main activity be one that is the main gateway to persistence (save to data store). Then each time execution enters that activity, it may flow into different sub-activities. Another cool activity example is Amazon's purchase item activity.

Tuesday, May 09, 2006

Refactoring to eliminate duplication

As with a previous post, this may be obvious, but I think merits elucidation and discussion.
There are many cases where some code cries out, "refactor me!", but there never seems to be sufficient time. In the opinion of most leaders in the software community, however, we should make time; our efforts will always pay off.

So here's something commonly seen:

case PartyAnimal.Age of
 2..12:
 begin
  PutRightLegIn;
  PutRightLegOut;
  DoHokeyPokey;
  ShakeAbout;
 end;
 13..19:
 begin
  PutRightLegIn;
  PutRightLegOut;
  DoMacarena;
  ShakeAbout;
 end;
 20..25: //etcetera

We have some obvious repetition here that should be extracted into a method (wouldn't it be really cool if we had an IDE that would do this for us? It does, you say? Please teach me how; BDS gives me an error every time; VS2005 never did).

To emphasize why it should be extracted into a method:
  • When (note - not if) PutRightLegIn needs to change in every case, the change can be made in one place.
  • It makes for less code in the listing (and in the .exe). Less code to do the same thing is always a good thing. (1)
  • To quote Martin Fowler, "the essence of good design is ensuring that the code says everything once and only once." And better design makes for more efficient maintenance. (2)
  • It follows the DRY principle: Every piece of knowledge in the development of something should have a single representation. (3) The piece of knowledge in this case is RightLegIn, RightLegOut, X, ShakeAbout.

So, of course, our refactored case statement (after adding our new method, DoPartyDanceWith) looks like:

case PartyAnimal.Age of
 2..12:  DoPartyDanceWith( HokeyPokey );
 13..19: DoPartyDanceWith( Macarena );
 20..25: //etcetera


I'm hoping the next time each of us has to modify something that looks like this, there will be a greater itch to refactor, then modify.

Notes:
1) The Art of Unix Programming (and a zillion other places)
2) Refactoring
3) The Pragmatic Programmer (and many other places)

Wednesday, May 03, 2006

get_ and set_

By default, if you have a property named MyProp, Delphi assumes methods named GetMyProp and SetMyProp. Per a Delphi 2005 book I have read, Delphi.NET actually compiles this code creating new methods get_MyProp and set_MyProp which in turn call the original methods. We could eliminate this extra layer if we just use get_ and set_ for the original names. This would have at least a minor improvement in performance. So, should we set a standard of get_ and set_ for future property specifier names?

PS: if the specifiers simply refer to an element such as FMyProp, Delphi still creates get_ and set_methods that then access FMyProp.

Read only class attribute

Say I have a class that has some attribute that is basically read only. Each child of the class has a fixed value for this attribute for all instances of that child class. Three possible ways to implement this are:

1. Add an element named MyAttribute. In the constructor, set the value of MyAttribute.

2. Add a function named MyAttribute that is overwritten in each child class.

3. Add an element named FMyAttribute and then add a MyField property with a read specifier of FMyField. In the constructor, set the value of FMyAttribute.

4. Add a Get method named GetMyAttribute and then add a MyField property with a read specifier of GetMyField. In each class, override GetMyAttribute.

I assume option 1 is the least desirable since it doesn't enforce read-only and basically does not fit in with the standards we are striving for. Option 4 is seems to be the most robust, but is overkill. Any opinions.

Tuesday, May 02, 2006

GAIM: Lotus SameTime client replacement

When ING blocked the external IM ports I for one found the Lotus client lacking in features compared to the clients that we had been using. Well the other day on my Mac I noticed that the client I was using had an option for SameTime. This made me ask why we couldn't use a different client at work as well. So I did some looking and found several clients that said they had SameTime support. The client I had previously been using, Trillian, did mention SameTime support but only in their "Pro" version. Another client that said they support SameTime was GAIM. I have been using this client on my Linux box at home for a few years now and have been happy with it. It is free, open source software. There is a Windows port of this program and the rest of this post details my experience so far with it.

If you want to try GAIM for SameTime you first need to download the client using the link at the top of this page. Once downloaded go ahead and install the program. I used the default install options.

Next you will need the GAIM plugin for the SameTime protocol. This plugin is Meanwhile. It can be downloaded from this page. (Updated) Be sure to pick the Windows version. It should be the file with "win" in the name. Once downloaded you can run the install. It should place the plugin into the appropriate folder.

Next open GAIM. It will present you with a login dialog and most likely open the Accounts window. I believe you need to go into Tools->Preferences and select the Meanwhile plugin in the plugins section before adding an account. Forgive me but I don't remember the exact steps for this but I believe it was intuitive.

Once the plugin is active you should be able to use the accounts dialog to add a new account. Select Meanwhile in the type dropdown list. Enter your username and password. Your password should be the same one used for logging into Exchange. For the servername I cut and pasted out of the Lotus client settings. Here's a screenshot of my account settings.

You should now be ready to connect and start IM'ing. For me my buddy list appeared the second I successfully connected. Since it is stored on the server you can make changes here or in the Lotus client and both see the changes. The only area that I've had trouble figuring out in GAIM is adding new buddies. To do this I switch to the Lotus client, add the buddy, then go back to using GAIM.

From here you can go in and customize your settings in Tools->Preferences. I've turned on several of the plugins to improve the behavior as well as logging, conversation history, etc. Here's a screenshot of my pimped out IM client.


I've been using this client for a couple days now with no noticable problems. If all else fails we have the Lotus client to fall back on. Happy IM'ing!

Thursday, April 27, 2006

Against Globalization

No, this isn't a political rant. I'm discussing global variables; in our case the collection of globals in Rng, Inp, and Outp.

Let me preface the discussion by saying that I understand that there is a good reason the globals exist (they go way back).

The following happened on Monday and illustrates one of the problems with globals:
I was making last minute changes to a product. I was setting an Rng variable in the product, but by the time the output code ran, that boolean always had a reverse value. I searched the code for all places that changed that global, but didn't find any that I wasn't already aware of. To temporarily solve the problem I implemented a hack.

Cindy later explained to me why the global seemed to be changing, but no matter; the root problem is globals themselves.

I'm sure you're all aware of all or part of the following, but I wanted to put together a good list of reasons why globals are bad with few exceptions:
  • They make the code less modular; in fact they make it anti-modular - everything is tied to the globals.
  • When globals are used, it's exponentially more difficult to determine what to change. When all variables are in their own (smaller) object, you can find what needs to change much more quickly.
  • Using globals leads to duplicated and unused variables (of which Cindy and I have found several just since I've been here).
  • Better memory footprint: more objects, but fewer in memory at any given time.
  • Much easier debugging. Even when you have a simple "dummy" member variable with an accessor at least you can set a breakpoint on the accessor and easily track down all callers.
  • This from a portion of the coding standards that Rob referenced in a previous post (and another reason to always have accessors even if they're just dummy accessors): "If you avoid exposing fields directly to the developer, classes can be versioned more easily because a field cannot be changed to a property while maintaining binary compatibility. Consider providing get and set property accessors for fields instead of making them public. The presence of executable code in get and set property accessors allows later improvements, such as creation of an object on demand, upon usage of the property, or upon a property change notification."
  • They make test driven development (even though we may never actually adopt this) virtually impossible because you can't test objects individually; they all need globals that are manipulated by other parts of the main app.
  • For more, see Code Complete | Chapter 13 | 13.3: Global Data.
So, bottom line; I think we should begin avoiding them going forward if we want the app to evolve more easily.

In the specific case outlined above, I should have added a member variable to the product class and accessed it from the output code (even though it's a little funky to access the product object at that point).

Wednesday, April 26, 2006

Don't ever ask me to buy another book again!

I was just in a meetng were the ING Learning Centre has partnered with Skill Soft to provide ING employees with an electronic book library. It is called Books 24X7. It is amazing.

I was taking a quick look at it and we already have access to the latest Delphi 2006 and Delphi 2005 books that were written. From what I can tell certain books you can download and other are viewable through browser only.

I think this is very exciting. There was even a category for algorithms which I know Steve and Dennis will have a hay day with.
Here is asome additional informaiton about Books 24/7:

- ACCESSING Books24x7: Access to Books24x7 is through the icon on the Other Resources tab of the ILC. If you do not see the Other Resources tab, look for the Books24x7 Referenceware course in the Knowledge Tools section of your ILC homepage. If you had a previous subscription to Books24x7 and accessed their site directly, you will now need to go through the ILC to access it. Direct access to the Books24x7 site is no longer available.

- HELP AND SUPPORT: There is an extensive help system in the Books24x7 site available from the Help tab at the top of the screen. If you require technical support, please contact your ILC Administrator for your business area (click on the ILC Contact button on the logon page or homepage of the ILC).

- NEW BOOK NOTIFICATIONS: You will receive periodic email notifications from Books24x7 about interesting new books available through the service. If you want to access those new titles, enter Books24x7 through the ILC and search on those titles within the Books24x7 site.

- DOWNLOADING BOOKS: Not all books are available for download or audio access. If you find a book that has these options, refer to the Help guide within Books24x7 for instructions.

- CHANGING YOUR SETTINGS: Personal settings (except ID, name and email), can be changed using the Settings tab at the top of the screen in Books24x7. If your personal information changes (e.g., name, email address, etc.) you will need to make sure it gets changed in the ILC for it to reflect in Books24x7.

SlickRun

Since Rob sent us a list of useful freeware, I couldn't resist posting about one of the utilities on the list that I cannot live without; SlickRun

I can't live without it mostly because I despise that evil little monstrosity next to my keyboard most people refer to as the "mouse". But that doesn't mean you have to hate the hand manipulation device of doom to benefit from SlickRun. It makes launching common tasks way more efficient.

Here's what it is:
  • A place to centralize and manage all of the apps you commonly run.
  • A scratchpad for temporary pasting text.
  • A quick calculator.
The command launcher is something you use to create and launch shortcuts. So to open VSS I hit -> Window Key + A, "s", enter. As soon as I type "s" it completes my keyword for VSS ("sourcesafe") and hitting enter launches the app. Any time I open something more than twice, I add it to SlickRun and make opening it the next time faster (while laughing at my mouse). Any command you can enter at the run prompt works as well.

But there's more. You can add dynamic parameters to your commands. So one of my commands is "compare". When I run that command it prompts me for 2 file paths. I browse to and right click (using the right click key of course) on 2 files I want to compare and put their paths on the clipboard (using FileTargets, another handy utility), paste them into the prompt and it launches a file compare utility passing the paths to it which immediately shows me whether the files match.

The "jot" scratchpad comes up with a keystroke and always auto saves. So I invoke it, paste in some text and hit escape; it'll be there the next time I invoke it.

The same little window that you type your commands into serves as a calculator. I like to use it in favor of the windows calculator most of the time because I can easily enter several numbers with lots of parentheses. You can see each step of the calc all at once.

Coding Standards

Well, since the Web Illustrations project came together so fast we never really took the time to hammer out any good coding standards for our new .NET code, as well as HTML, scripts, etc. Now that the dust is settling a bit I'm going back and trying to clean up and comment some of my code. We now have Delphi.NET, C#, JavaScript, HTML, CSS, and XML files just to name a few. We do have documentation on Win32 Delphi coding standards, albeit a bit old.

For our C# code we should follow the Microsoft recommendations. It can be found on MSDN at:

Design Guidelines for Class Library Developers

Would it also make sense for our Delphi.NET code to follow this standard as well? Or should it follow closer to the Win32 Delphi standards we currently use? Perhaps Rich or Steve could speak as to what they've been doing in the .NET code sections.

I did some looking but could not find an authoritative JavaScript coding standard. There were several mentions to a document on the Netscape developers site but it appears to be gone. The Mozilla project doesn't seem to have anything similar. It appears to me that most sites (including Microsoft) appear to use Camel Case for most of their JavaScript variables and methods. I've tried to follow suit.

HTML, CSS and XML standards are sort of a whole other animal and perhaps would be worthy of a thread all their own if anyone is interested.

So I pose it to the group, what are your thoughts/feelings/recommendations on new and improved standards? Perhaps some of the new people have experience from their previous lives?

Wednesday, April 19, 2006

Intro to OneNote

For those who don't know what it is, OneNote is a new app in the MS Office suite (so we all have a license). I decided to try it out from day one here at ING.

My motivation is this: I (like most people) frequently take notes with paper and pencil. For years, I've been in the habit of maintaining to-do lists with little boxes next to each item. But this is inefficient:
  • I type much faster than I write.
  • It's easier to type while talking on the phone.
  • I can take notes on computer in more places using a laptop.
  • All my notes are in one place - on my machine.
OneNote is a tool for managing lots of notes.

At first it didn't seem too much different from a plain old word processor. But here are some important differences:
  • You never have to create or save files. Rather, you set a directory as your designated OneNote directory (and back it up of course) and OneNote manages the files (including auto-saving).
  • You can tag items paragraphs/sentences/bullets with "note flags". You tag items with stars, question marks, rememeber for later, or check boxes. Then you can search all your notes for a given note flag.
  • You can also simply draw something on your page freehand or easily take snapshots of some portion of your screen.
  • The organization for notes is section - page - subpage. Within a page/subpage you create paragraphs/bullet lists/whatever. Each of these items is automatically grouped into a draggable object thingy that makes it very easiy to cut and paste or drag and drop logically grouped info.
So here's a visual. I have a section titled "Trackers", and each page is titled with a tracker ID.














Under my "Meetings" section I have pages titled for each type of recurring meeting. I haven't yet used subpages.

Anyway, I'm really liking it. There are other features of course; these are just the basics. Maybe you will find it useful too!