www.codinghillbilly.com   kyle.baley.org  Subscribe / Contact
 
 
 
 
LATEST POSTS
Thursday, September 17, 2009

Quick productivity blorg today. Because if hillbillies are known for anything, it’s their efficacy. And their ability to use words they don’t quite know the meaning of but can fake in context. (I’m referring, of course, to “efficacy”. I know full well what a “blorg” is so I don’t need you telling me in the comments.)

Alt-F4 is not the most natural keystroke on the Kinesis keyboard. Or even on a regular keyboard. Yet I use it pretty often. Especially recently while testing out Lucene on my document repository. Word and PDF docs abound very quickly while I’m opening them and verifying results. So I was looking for a faster way of closing them quickly.

My chosen method: Press Ctrl three times in rapid succession to close the active window.

The implementation: AutoHotKey. Here is the script that does it:

~Ctrl::
CloseOnThird()
return

CloseOnThird() {

   Static Count
   key := RegExReplace(A_ThisHotKey,"[\*\~\$\#\+\!\^( UP)]")
   If ( A_ThisHotKey = A_PriorHotKey and A_TimeSincePriorHotkey < 400 )
        Count += Count < 3 ? 1 : 0
   Else Count = 1
   KeyWait %key%, DT0.4
   If (ErrorLevel and Count = 3)
      WinClose,A
}

The end result: at the end of a strenuous day, I can mash the Ctrl key over and over again until the computer shuts down. Tres satisfying.

Kyle the Ctrl’d

Saturday, April 25, 2009

I’m over a month in with my new keyboard and, as promised, here is the follow-up.

Typing speed has returned to more sporting level, as I had expected. The exercises included with the keyboard, while not Pulitzer Prize material, do help. I’d work on them on my host machine while waiting for my VM to boot up in the morning. Doing that, I was able to get through the ones I cared about in about a week.

I’m still not *quite* at the same typing speed but I’m close enough. It’s the old 80/20 rule. I’ll get up to 80% of my old speed after 20% of effort. The last 20% will probably take orders of magnitude longer. That said, the keyboard does exactly what it advertises, which is reduce strain. All (keyboard-related) pain in my right arm has ceased. Whether it’s psychosomatic or the new keyboard layout or the fact that the keyboard releases a rush of endorphines every time I press Ctrl-Alt-E, I don’t much care. The fact is, the pain is gone. That alone makes the keyboard worth it’s weight in whatever metal is selling these days. As a bonus, I also discovered that Robin Williams used one in the blockbuster hit, Flubber. If that’s not endorsement enough, well, you can’t save everybody.image

To be fair, there have been a whack of other little adjustments I’ve made that have contributed to my new pain-free typing experience. I described a few in the original post:

  • Using Executor
  • Remapping CapsLock and F1 to Esc (the former because it’s more convenient, the latter because the F1 key is the MOST ANNOYING KEY ON THE FACE OF THE PLANET!)
  • Using AutoHotKey to remap Left-Control + Right-Control to Alt-Tab and Left-Control + Right-Win to Shift-Alt-Tab

In addition to this, I’ve also done the following:

  • Changed the default keystroke to Executor to Right-Control + Backspace
  • Turn off the annoying double-click when you press CapsLock (aka Esc). This is a keyboard function and it was heavenly when I found out it could be disabled.
  • Remapped the left backslash key on the keyboard to Insert.
  • Mapped Win + F10, F11, F12 to Volume Mute, Volume Up and Volume Down respectively (with AutoHotKey)
  • Made heavier use of ViEmu and Vimperator

With regard to the third point, for whatever reason, the keyboard comes with two backslash keys. This is strange given how sparse they are about duplicating other common keys (alt, win, etc.) and simply not including others (Insert, for example). Whatever the case, I’ve used the built-in keyboard remapping capability to remap the left-hand backslash to Insert which has helped immensely for logging into VMs.

The last point is important. When I first tried both of these tools some months ago, I used them for a month and gave up, thinking I’d given them the good ol’ college try. Coming back to them, I was surprised how much I actually remembered. Which is good because it meant I could then learn some more keystrokes without having to also try to keep the original ones in my brain. The experiment was so successful that I added ViEmu for Word and ViEmu for SQL Server to my toolkit. All of them have helped me to avoid the arrow keys, PageUp, PageDown, Home and End, all of which are still not as intuitive as they ought to be. Oddly, I tried Vim itself for a few days and it was way too wacky for me. So I’m sticking with Notepad2 as my default text editor. I end up typing jjj and kkk a lot when I want to navigate but I can only take so much freakishly-obscure tools and hardware at once.

Both ViEmu and Vimperator are as configurable as Vim, which may mean something to you if you know that Vim is very highly configurable. So I’ve added the following configurations to ViEmu for all versions:

  • noremap <Space> <C-d>
  • noremap <BS> <C-u>

I’m not 100% sure what noremap does compared to map or nnoremap. Just know that adding the above two lines to _viemurc and _viemuwrc makes things happen. In this case, pressing Space will move text down half a page and pressing Backspace will move it back up again. This may seem odd to you but considering where these two keys are on a Kinesis, it’s very aesthetically-pleasing actually.

For Vimperator, I essentially stole the configuration from someone else. The highlights of it are:

  • set complete=l
  • au LocationChange .* js modes.passAllKeys = /(www\.google\.com\/reader)|(rememberthemilk\.com)/.test(buffer.URL)
  • com gui :set guioptions+=mTb
  • com nogui :set guioptions-=mTb

This is what these commands do:

  • Enable auto-completion when you open a url (either with :open or :tabopen)
  • create a command called :gui which enables all the toolbars. The :nogui command hides them again.
  • disable Vimperator for Google Reader and RememberTheMilk (i.e. automatically switch to pass-through mode for these sites)

For the last one, I had, at one point, also disabled Vimperator for GMail because it collided with many of the GMail shortcuts. The latest version of Vimperator is much saner with GMail so I’ve enabled it again. Still get an error when deleting mail with # and I can’t press Y to archive but it’s much better than before.

There is still one major pain point: The location of some rather common characters in C#. Namely: []{}<>. These are all located in the same corner and I’m still tripping over myself as I type them. I’m working on a macro that will allow me to type out “left curly brace” and have it substitute { in its place.

Kyle the Laconic

Friday, March 13, 2009

I could just update my existing post from a couple of days ago but I have another point to make afterward.

Firstly, there is a minor release of ViEmu available as of yesterday. What I found most notable was near the end where Jon says he will be working on the ReSharper issue mentioned in my last post as well as an updated keyboard configuration dialogue. Both will be welcome additions and I’ll be grabbing that release hot off the presses.

Here’s where I think I missed the boat a little. I thought I’d blogged on ViEmu before so I didn’t dwell so much on my opinion of the software. Last June-ish, I decided to give the various vi/vim tools a try because they’d been getting some press. I gave a good college try to ViEmu for VS, SQL Server, and Word. I also had Vimperator for browsing. I tried all of them for at least a month and after that time, I still wasn’t as productive as I was without them.

Recently, as I mentioned, I’ve had a more vested interest in reducing my dependency on the crack we all call “mouse”. So Vimperator and ViEmu came back into the fold. I was pretty surprised at how much I had remembered from last time. This helped a lot because it meant the learning curve was that much lower. Whereas the last time, I had to get used to the navigation before I could learn the more involved intricacies of the products, this time, I had the navigation and search features buried in the back of my head somewhere.

Where I’m going with all this is I think ViEmu for Visual Studio is a good buy for developers, a point that didn’t come across in my last post. I don’t know that I do enough in Word and SQL Server to justify those but that’s me. Maybe you’re in SQL land more often. But I spend enough time in Visual Studio that it makes sense to investigate ways to improve the experience. I mean, how long does a carpenter hammer in nails before he gets a nail gun?

There’s a heck of a learning curve as with all things vi. (This kind of goes against my philosophy of “If something is hard to learn, it’s not worth learning” but I’ve made an exception in this case. See also: NHibernate). There are still minor hiccups, not least of which is my tendency to press j and k in Live Writer. And I was expecting this huge rush of superiority to descend upon me when I started to “get” it but I guess I’m still not quite at the “holier-than-thou” stage of the process. Looking forward to that because I do so respect those people that are so dismissive of others for not liking the same tools they do.

In any case, you’ll also find the author is very receptive to questions and suggestions on both the site and, more recently, on Twitter. And speaking of Twitter, you’ll find no group more helpful than ViEmu and ReSharper users. Give it a try by asking “What’s your favorite tip for <insert either one>?”. (Since you asked, it’s one I just discovered: Unbind Esc from Edit.SelectionCancel. Many thanks to Aaron Jensen and Joey Beninghove for that one.)

This public service announcement inspired by the author’s knowledge of how &*%$ HARD it is to build decent add-ins for Visual Studio.

Kyle the

Monday, June 02, 2008

I bet you didn't know hillbillies believe in kismet. Well, we do, mostly because it typically works in our favour. The minute things start going wrong, well, that's just plain someone else's fault and typically requires at least one lawsuit.

But today, kismet. That's the only reason I can think of why someone would post a SimpleStateMachine project on CodePlex not three days after I started working on this very problem.

<-- snip -->

I've just cut out an Imperial tonne of back story that upon re-reading was boring as all git out, though wittily told. I'm going to skip to the implementation.

Which still requires some knowledge of the worfklow I'm trying to implement.

image

This image encapsulates quite a few false starts, most notably in the places where it "branches" off (the beige boxes). My first implementation was a flow where a job could be in three states at once. For example, a job could be "To Be Invoiced", "Awaiting Hydro Approval" and "Awaiting Regulatory Approval" all at the same time. Not a traditional definition of a State Machine but one that I could start coding against nonetheless.

Then comes the SimpleStateMachine that was oh so enticing but also a little less liberal with the rules of a state machine. So I moved, after much deliberation, to the above diagram in which the branches represent the launching of separate workflows. Thus, in a sense, a job *can* be in more than one state at once, but not in a given workflow. Now I could try out the SimpleStateMachine and still appeal to my sense of ancestral ambiguity.

The code is surprisingly easy to follow, not least of which is because of the unit tests and demo application, both of which paint a pretty good picture of how the application can be used. When you need to step through it, you'll find things clearly separated out so it's pretty easy to figure out what's going on.

I'm including the entirety of my main workflow below partially because I like testing out the scrollbars of your RSS reader but mostly so you can see how simple it is. I'm told it's in Boo format but it's my first exposure to the language so I haven't verified. All I know is that it works.

workflow "Basic Job"

state_identifier_target @JobStatus
event_identifier_target @JobEvent

on_enter_state      @PersistState, "on_enter_state"

_event @SetUp
_event @DraftingCompleted
_event @DraftingRejected
_event @DraftingApproved
_event @Invoiced
_event @Paid
_event @Uncollected
_event @Cancel

state @Ordered:
  when @SetUp                >> @InDrafting
  when @Cancel               >> @Cancelled
	
state @InDrafting:
  when @DraftingCompleted     >> @ToBeChecked
  when @Cancel                >> @Cancelled

state @ToBeChecked:
  when @DraftingRejected      >> @InDrafting
  when @DraftingApproved      >> @ToBeInvoiced
  when @Cancel                >> @Cancelled
	
state @ToBeInvoiced:
  when @Invoiced              >> @AwaitingPayment
  when @Cancel                >> @Cancelled
	
state @AwaitingPayment:
  when @Paid                  >> @Closed
  when @Uncollected           >> @BadDebt

state @Closed

state @BadDebt

state @Cancelled

This is *almost* something I could assign to a business user to create. Not that I would. But they could certainly read it and figure it out with minimal coaching.

You'll notice the on_enter_state task at the top. This means that the PersistState task (which is a custom task I've written to write the job status to the database) will execute each time we enter a state.

This concept also applies to individual states. For example, this workflow doesn't totally match the diagram. I've omitted the part where it launches two other workflows. The way I plan to implement them is to modify the @ToBeInvoiced task as follows:

state @ToBeInvoiced:
  when @Invoiced              >> @AwaitingPayment
  when @Cancel                >> @Cancelled
  on_enter_state @LaunchHydroWorkflow, "on_enter_state(ToBeInvoiced)"
  on_enter_state @LaunchApprovalWorkflow, "on_enter_state(ToBeInvoiced)"

That is, I will create custom tasks to launch the two other workflows after we enter the ToBeInvoiced state.

So check out the library if you are working with workflows (and props to Ayende for pointing me to the library to begin with). As an added bonus, the author is amazingly quick in responding to issues. In the time it took me to type this up, he added the ability to use an IoC container with your custom tasks and a more efficient way of searching for custom tasks. Both in response to questions I asked on the discussion list.

Next post will likely be on the actual implementation of this workflow. Suffice it to say that the project lives up to the premise on the home page:

"The motiviation for creating this library was a dissatisfaction with the complexity and weight of Windows Workflow Foundation for creating, maintaining, testing and versioning of what should have been simple state machine workflows in our applications."

Kyle the Flowed

Saturday, May 31, 2008

Couple o' quick productivity tips.

The first I posted on Twitter yesterday. That is, in Visual Studio, you can map Ctrl-Alt-F4 so that it closes all open document windows. It's a noticeable time saver for me because I often get to the stage where I'm holding down Ctrl-F4 for about ten seconds waiting for it to close everything up.

Instructions:

  • In Visual Studio, go to Tool | Options
  • Under Environment select Keyboard
  • In Show commands containing, enter Window.CloseAllDocuments. You should get a single entry in the listbox below it
  • Put the cursor in Press shortcut keys and press Ctrl-Alt-F4.
  • Click OK

You can use whatever combination you like but check to see if it's used by something else. I originally wanted Ctrl-Shift-F4 but ReSharper was using it for "Close recent tool". Haven't determined what that means yet.

Next tip. When I get zip files, ninety-nine percent of the time, I do the same thing with them: Extract to <foldername>. That requires right-clicking on the file, navigating to the 7-Zip folder in the context menu, and selecting the appropriate option. I'm using 7-Zip as my archiver of choice primarily because it's free, fast, and hasn't gone the Paintshop Pro route of bloatedness like WinZip has.

(NOTE: You can configure 7-Zip's context menu to get rid of things you don't use, like Zip and E-mail. You can also make the menu non-cascading. The options are a little buried in the application but you'll find them.)

7-Zip has a command-line version, as I suspect most archivers do. So after a browse through the documentation, I created a batch file as follows:

@echo off
set zipPath=%~dpn1
"C:\Program Files\7-Zip\7z.exe" x "%1" -o%zipPath% -y
pause

I've completely forgotten what the value after "set zipPath=" means but it was on the interwebs here somewhere. Sorry folks, the Hillbilly can't be expected to remember everything he did last month. Like if he showered or not.

The next step here is to link this batch file to .zip files. I went the low-tech way by right-clicking a zip file, and selecting Choose Program... from the Open With context menu:

image

Select your newly-minted batch file and now zip files are extracted to <foldername> with a single click (or with an Enter for the keyboarders).

Notice that the zip file has a "pause" in the last line. That's precautionary and can be removed if you like. I added it so I could see if there were any errors during the process.

That is all.

Kyle the Productive

Thursday, February 07, 2008

During my presentations at South Florida Code Camp, some people asked on the tools I was using. I went off on a bit of a tangent on tools in general and cut myself off when it occurred to me, "this is bloggable".

The theme of that tangent was thus: Don't be afraid of commercial tools. The analogy I made was that carpenters, plumbers, electricians, even hookers all buy there own tools to...ummm....reduce friction. The good ones buy tools that fit their needs, regardless of whether it's top of the line or a fourth generation hand-me-down with a crank on the side.

At the time I talked about this, I was demonstrating VisualSVN. Which is $50. Translated, that comes out to anywhere between twenty minutes to two hours of billable time, depending on your negotiation skillz. It paid for itself probably around month two. And even if you don't buy that logic, I've bought far less useful stuff for $50 which I will leave to your imagination.

You knew of course that I'd bring up ReSharper. I won't beat you over the head with the amount of time it's saved me but suffice it to say, it's another favorable purchase on the cost/benefit scale. I didn't get a chance to see Mark Miller's presentation on Code Rush and I haven't tried the product myself but my opinion is, try 'em both and pick one that works for you. Or maybe you try each, put them through their paces, and find that neither adds to your productivity. But try them. And buy them if they are useful.

In short, don't avoid something just because it costs money. Yes, you can put up two files in Notepad side by side and compare them visually. But isn't your time worth the thirty dollars to get it done that much quicker with BeyondCompare?

This post brought to you by the creators of SmartFTP and UltraMon.

Kyle the Pimp

Monday, December 24, 2007

Welcome back, revolutionaries! We've had a small reprieve from the fight to let our early anarchy settle in and---....y'know what. The revolutionary jargon is getting too hard to write and the refactorings more involved so I'll just throw out a "The revolution will be blogged!" and go back to bein' a hillbilly, iffen it's all the same to you.

Today I'm throwing myself at the data access layer and the database. The data access layer is an easy target just because it exists and we've long since switched to NHibernate for our data access in other applications. So the refactoring there will entail ripping it out mostly. Along with most of the stored procedures which haven't inspired me with a lot of confidence ever since I found three of them that refer to tables that don't exist.

One of the pain points I've encountered in dealing with this particular database is the different schemas it uses. For those of you not familiar with the concept (as I wasn't until about a week ago), most databases will use the default schema, which is usually dbo, probably for database owner but don't quote a humble hillbilly. In this case, almost all the tables were created under a different schema. For example, the users table belongs to a Admin schema and the FieldList table belongs to a Dictionary schema.

To create the table under a different schema:

CREATE SCHEMA [Admin]
CREATE TABLE [Admin].[tbUsers]
(
[UserID] [int] NOT NULL IDENTITY(1, 1),
[NetworkUserName] [varchar] (255) NULL,
[RoleID] [int] NOT NULL,
[PreferredPlaidColour] [varchar] (50) NULL
)

After this, you'll need to qualify the table in any queries you make to it:

SELECT * FROM [Admin].[tbUsers]

I'm certain there are advantages to using schemas. Security comes to mind as I'm betting you can apply security rules to a schema to grant/limit access to it. And they probably appeal to DBAs that like to keep things pseudo-organized.

For our case, it was overkill and a surprisingly potent distraction when we had to query the database. This was the only application that used them and it wasn't exactly a high-profile, high-security type application. It's used by one app, ours, and you either have access to the app or you don't. And they weren't even used consistently. There were two tables using the default dbo schema, at least one of which shouldn't have been.

So after talking with some developers who worked on the previous version and confirming that they weren't being used in a meaningful way, we set about removing them. Which is much easier than one might think:

ALTER SCHEMA dbo
TRANSFER Admin.tbUsers

I do have to send a shout-out to DataDude, which you may know by it's official name (and I'm going by memory so it may be off a bit): Microsoft Visual Studio Team

Did you know?

You can't compare tables in DataDude if one or both tables in the comparison has no primary key

Partner Coding System for Professional Licensed Database Practioners and Ornothologists, the Spongebob Squarepants Edition.

This nifty little VS add-in/utility/whole entire version of the product has been a tremendous help during this refactoring. It has a Schema Compare feature that I used to generate the initial scripts to create the database and a Data Compare feature I used to generate test data for our QA environment.

But a nice feature I wasn't expecting: after I changed our CREATE TABLE scripts to use the new default schema, Visual Studio immediately popped up a pile of clickable warnings indicating stored procedures, foreign key scripts, etc, that were no longer valid because the name of the table had changed. Not quite as clean as a ReSharper Rename, mind you, but better than hunting through scripts manually and inevitably missing some.

It was also DataDude that discovered the three stored procedures referencing non-existent tables.

The net result: a database more in tune with its sister databases and one that inspires far less cursing from developers who are prone to typing in SQL statements without the schema.

Kyle the Databound

Saturday, December 15, 2007

Fear not, brethren and...uhhh....sistren. The resistance is still alive. But the revolutionary jargon will get in the way here so I'm reverting to a more traditional means of expression.

Among the things we've implemented as part of our project clean-up is the aptly-named ClassTester. It's a neat little tool that takes some of the pain out of routine testing of constructors and properties by, for example, setting a property then checking to make sure you get the same value back from the getter. Here's some sample syntax for testing the properties of an object:

    ClassTester tester = new ClassTester(new myObject());
tester.TestProperties();

Now, hillbillies are not what you might call amenable to writing boilerplate code for every single class in their domain. Leads to some problems you can only imagine in your nightmares. So in an attempt to avoid duplication, I decided instead to walk through all the classes in the assembly:

       [Test]
1       public void Test_general_constructors_and_properties()
2       {
3           Assembly assembly = Assembly.GetAssembly(typeof (Still));
4           Type[] types = assembly.GetTypes();
5           foreach (Type type in types)
6           {
7               if ( type.IsClass 
8                    && !type.IsAbstract 
9                    && type.Namespace == "Suvius.Applications.HoochDeriver.Domain" ))
10              {
11                  ClassTester.TestConstructors(type, false);
12                  object item = assembly.CreateInstance(type.FullName);
13                  ClassTester tester = new ClassTester(item);
14
15                  tester.TestProperties();
16              }
17          }
18      }

Some points of interest:

  • I could use any domain object in line 3. I'm interested only in getting the assembly that houses all the domain objects
  • Line 8: The ClassTester doesn't much like abstract classes
  • Line 9: This line may seem redundant but it is necessary because of the way I run my builds (which, credit where it's due, I pilfered from JP Boodhoo). Namely, in the build file, we compile all .cs files into a single assembly and run the tests against it. Which means line 3, will retrieve the assembly containing (almost) every class in the application. Compare this with compiling in the IDE where all domain classes are in one assembly by themselves. So running this test from the IDE, where it will compile the assemblies separately, we don't need the check for the namespace. Running it in the build file however, we do.

There are in fact two separate tests here, one for constructors and one for properties. If you want to argue that these should be separate tests, I'll agree. If you want to argue against that, I'll agree too. That's how much I care about it.

Anyway, this code is nice in theory. At present, the tester handles only very routine cases. If there are any validation rules, you'll get validation errors. For example, if you have a Percent property where you throw an exception if the value is not 'twixt 0 and 100, the ClassTester will throw this exception most of the time because it generates a random number to set the properties and doesn't know about your little rules. The ClassTester does allow you to ignore individual properties though, which is useful when testing classes individually.

The second problem with looping through every class is that not every class can be tested, even with no validation rules. In our case, we had some classes that were inheriting from CollectionBase (did I mention it was ported over from .NET 1.1?) and the ClassTester failed on all of these because of the Capacity property (which I didn't know existed).

The end result is that we had to include a list of classes to ignore from the domain and make sure they were tested separately through more conventional methods. Whether or not this is worth it depends on how many classes you need to ignore. In our case, it was only the collection classes which have since been removed anyway because of the generic collections in .NET 2.0.

And to prove it was all worthwhile, the ClassTester found and located no less than three bugs in our getters and setters, each one a variation on this theme:

    public decimal AmountOfHopsToAdd
    {
        get
        {
            if (DandelionBase != null)
            {
                // Return some complicated formulaic value based on DandelionBase
            }
            else return 0.0M;
        }
        set { _amountOfHopsToAdd = value; }
    }

In this specific case, the setter is all but useless since _amountOfHopsToAdd is never actually used anywhere. The other examples gave similar fodder for pondering and our code is shinier and happier for it.

Kyle the Testable

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

Copyright © 2010 Kyle Baley. All rights reserved.
 
CATEGORIES
.NET General (18) alt.net (4) altnetconf (9) ASP.NET AJAX (40) ASP.NET MVC (29) Bahamas (1) Bahanet (9) BDD (1) Brownfield (18) Career (9) Castle (1) Code coverage (1) Coding Style (6) Communication (1) Community (18) Conscientious Coding (34) Continuous Integration (11) dasBlog (12) Development (16) DevTeach (4) Domain (2) Environment (4) Estimating (1) Featured (14) Flamingo (10) Games (1) Google App Engine (2) GWT (5) Hardware (6) Java (1) Javascript (7) Linq (2) Livelink (6) Lucene.NET (2) MbUnit (1) Metrics (1) Miscellaneous (24) Mocking (4) NAnt (4) NHibernate (12) NInject (1) Office (3) Office Development (6) Open Rasta (1) Patterns (5) Presenting (13) Professional Development (15) Refactoring (10) ReSharper (11) REST (2) S#arp Architecture (5) Security (3) Software (11) Sundry (18) TDD (19) Tools (21) User Interface (5) Utilities (8) Visual Studio (8) VSTO (1) Web development (12) Windows (3) Working Remotely (16) Workplace (3) Writing (4)
 
LATEST POSTS
 
POPULAR POSTS
 
 
ARCHIVE