Dock.Fill should be used more often

Look at the picture below.

image

These are the Team System tests results I run today. Why the heck is more than half of the window empty (huge red rounded rectangle) ? Instead, the grid could perfectly fill the empty space and thus reducing the stress on my mouse wheel.

I have no idea why there is an empty space but [MS] developers are often keeping dialogs fixed and small (how much time it took to get resizable dialogs, such as Add References... one) and it seems the same happened to this unfortunate form (if you have a screen bigger than 15" that is). If you look at the bright side, at least grid's horizontal expansion is there.

Is this going to change in Visual Studio 2008? Judging from beta 2 - the testing UI has been redone to some extent and this grid doesn't appear anymore at all.

Spell checker for developers is a good thing

Here is an output from Intel's Matrix Storage Console when repairing a RAID array:

image

Yep, it says Verifing instead of Verifying. This is a common harmless error that happens in an application. While it is a harmless one it makes you feel uncomfortable though - if developers are producing such obvious errors they also might ... if there is a real error in RAID driver...ouch. Isn't there an easy solution for a developer to avoid such errors?

I have a solution for developers - spell checker add-in for Visual Studio (requires free DXCore engine - a part of CodeRush/Refactor! from [DevEx]). It adds spell checking capability right into your IDE and its free!

Read spell checker description and then download the latest version from here.

Command prompt utilities should have a readable help message

Today I had to display ILMerge's help information (btw, ILMerge does merge assemblies in a single assembly and it is a must have free utility produced by [MS] Research labs). This is the output I've got:

C:\Progs\Vodovodi\Vodovodi.Utilities\AddPrefix\bin\Release>"C:\Program Files\Mic rosoft\ILMerge\ILMerge.exe" Usage: ilmerge [/lib:directory]* [/log[:filename]] [/keyfile:filename [/delaysig n]] [/internalize[:filename]] [/t[arget]:(library|exe|winexe)] [/closed] [/ndebu g] [/ver:version] [/copyattrs [/allowMultiple]] [/xmldocs] [/attr:filename] [/ta rgetplatform:<version>[,<platformdir>] | /v1 | /v1.1 | /v2] [/useFullPublicKeyFo rReferences] [/wildcards] [/zeroPeKind] [/allowDup:type]* /out:filename <primary assembly> [<other assemblies>...]

Clear, isn't it? Absolutely not - it is an unreadable mess. It is very obvious that this fine tool was written by scientists who don't care about friendly messages. They should use at least new lines!

C:\Progs\Vodovodi\Vodovodi.Utilities\AddPrefix\bin\Release>"C:\Program Files\Mic rosoft\ILMerge\ILMerge.exe" Usage: ilmerge [/lib:directory]* [/log[:filename]] [/keyfile:filename [/delaysign]] [/internalize[:filename]] [/t[arget]:(library|exe|winexe)] [/closed] [/ndebug] [/ver:version] [/copyattrs [/allowMultiple]] [/xmldocs] [/attr:filename] [/targetplatform:<version>[,<platformdir>] | /v1 | /v1.1 | /v2] [/useFullPublicKeyForReferences] [/wildcards] [/zeroPeKind] [/allowDup:type]* /out:filename <primary assembly> [<other assemblies>...]

So, a simple \r\n does make a huge difference. And there are plenty of fine tools/applications with a great engine and with crappy UI out there. I won't even mention Dotfuscator at this point.

e-banking at its best

I saw this post over at David's blog and all that I have to say is that ... I am not surprised. e-banking applications aren't good over here in Slovenia. But this one from David's post tops the list by far. Here is the screenshot from his blog (I hope he don't mind that I've made a copy of it).

BA-CA error

So, you might say "heck, errors happen". Yes they do, but this one shows bank ignorance at its worst. Even though their representative Janez explains in a comment that the error and usage of Access(!) database are unrelated to core application itself he is bloody wrong. So, what can you see from this error:

  • They are using Access
  • They are using asp
  • They are using ODBC driver (who knows why..)
  • The code that connects to the database is in the file /obvestila/DBConn.asp and the connection itself is in the line 9
  • They never heard of never ever show internal error to the public

These are 5 lines of knowledge that should remain hidden. Specially in this kind of sensitive application. Do you wonder what other errors might reveal? But the real problem is not within this particular data displayed, it is the fact that they are showing data that shouldn't be seen from outside, ever. This leads me to thinking that their application is really badly written, or at least a part of it, and it might be highly vulnerable to malicious attacks. At least such message doesn't really give you a sense of security. I also wonder how scalable the application is when used by more than 5 concurrent users.

Anyway I am sure that application was written by the cheapest company...Kudos to everybody using this application for their courage.

UPDATE: The page with the error shown above is not the page from their e-banking but from their e-banking entry page. Their e-banking application is actually located on another web address and it seems like it is java application. So the two might be separated. But nevertheless all of the criticism above is still very valid.

C++ cryptics

I saw today this line of code in a newsgroup and couldn't resist to compare it to the same code written in C#.

array<System::Data::DataRow^>^ rows = myTable->Select("...");

Now, compare the managed C++ code above to the C# code below:

DataRow[] rows = myTable.Select("...");

I wonder which one is more clear and readable...

Anonymous method trivia

Can you guess how many times will this console application output the current date?

class Program { private static Tubo tubo = new Tubo(); static void Main(string[] args) { One(); tubo.RaiseTubek(); Console.WriteLine("Finished"); Console.ReadLine(); } private static void One() { tubo.Tubek += delegate { Console.WriteLine(DateTime.Now); }; tubo.RaiseTubek(); } } public class Tubo { public event EventHandler Tubek; public void RaiseTubek() { if (Tubek != null) Tubek(this, EventArgs.Empty); } }

Visual Studio Team System Testing tools and multithreading

If you've been doing testing with Visual Studio Team System (VSTS) you have probably noticed that each test might be run in different thread. And the same is valid for set up and clean up methods. This feature might be a good one generally but not if you are testing UI.

I worked a scenario where I start application's main form within ClassInitializeAttribute decorated MyClassInitialize method. Then I do various tests in sequence (I use ordered tests) and finally I close the application in ClassCleanupAttribute decoreated MyClassCleanup method.

Here is a how my code looks (simplified):

private MainFrm mainFrm; // Form derived class [ClassInitialize()] public static void MyClassInitialize(TestContext testContext) { mainFrm = new MainFrm(); mainFrm.Show(); } [ClassCleanup()] public static void MyClassCleanup() { mainFrm.Dispose(); mainFrm = null; } [TestMethod] public void SomeTest() { // do some test with mainFrm }

Since I am using an ordered test to executes tests in sequence I would expect that tests are run in the same thread. However this is not the case nor you can force VSTS to use a single thread. Why is it important anyway? Because all operations to the UI have to be done within the thread that created UI control. Any access from different thread should and probably would cause an exception at best. Ouch, that's sounds like a showstopper for UI testing (besides the fact that VSTS doesn't support UI testing). To tell you the truth I was really surprised that an option to run tests in a single thread is missing.

So I start considering switching to NUnit (and TestDriven.net perhaps) since my tests weren't that many so far. The switch would cause me more work and more administration and I wasn't that happy to take NUnit path. Then I found the solution, which is really very simple. You have to execute all operations on UI thread and Control.Invoke method does exactly that. Here is modified code:

private MainFrm mainFrm; [ClassInitialize()] public static void MyClassInitialize(TestContext testContext) { // this method remains same - this thread creates UI mainFrm = new MainFrm(); mainFrm.Show(); } [ClassCleanup()] public static void MyClassCleanup() { // if thread is not one that created the form then excute an // Invoke call to switch thread if (mainFrm.InvokeRequired) mainFrm.Invoke(new MethodInvoker(MyClassCleanup)); else { mainFrm.Dispose(); mainFrm = null; } } [TestMethod] public void SwitchToFootball() { // if thread is not one that created the form then excute an // Invoke call to switch thread // Do the same if clause for any test that has to interact with UI classes // (indirectly or directly) if (mainFrm.InvokeRequired) mainFrm.Invoke(new MethodInvoker(SwitchToFootball)); else SwitchTo(BetCategoryCode.Football); }

Basically, before each test execution you have to make sure it executes in correct thread (the one that created UI objects). You do that by first checking whether the current thread has to be switched by checking Control.InvokeRequired property (both this property and Invoke method are thread safe). If this property is true you have to switch threads by invoking Control.Invoke method with a delegate to the method to execute (which is the same in this case) otherwise no switch is required. And you don't even have to create different delegate types since a test method has to be a parameterless method and thus System.Windows.Forms.MethodInvoker delegate is good for all methods.

And that's it. Happy UI testing.

Think twice before giving your personal data to either Yahoo or MSN

According to today news MSN and Yahoo agreed to help Chinese government in censorship and fight versus "politically sensitive" bloggers. The help consists in giving all of blogger's private data to the government on its request. Just like that. Now, if those big companies are so willing to give data away to Chinese government, do you think that they have a problem giving same kind of data to any "democratic" government - even more so, if somebody mentions terrorism threat. Not to mention that MSN and Yahoo are huge companies. Smaller companies are probably even worse in this regard. Heck, even European Union is sending a lot of private data to US when an European citizen flies over there. Privacy? What' that? We should sacrify all of our privacy for bigger goals, right? NO! Perhaps John Connor was right in the Terminator 3 movie - he lived practically outside the system.

So, think twice and one more time before you give any personal data to any company.

Make XtraVerticalGrid fast as a bullet

Recently I've discovered that XtraVerticalGrid, a nice vertical grid from [DevEx], has some serious problems with speed when doing batch updates. Usually you should enclose batch updates within BeginUpdate/EndUpdate method calls. This usually prevents processing/redrawing within the control when one does many updates to underlying datasource at once. The neat effect of BeginUpdate/EndUpdate results in dramatic speed improvements.

However, XtraVerticalGrid doesn't implement batch BeginUpdate/EndUpdate very well and still massively processes the changes even though developer doesn't want to. Basically an operation that should take a fraction of second took more than 3s, which is an annoyance to the user, due to this problem.

Here is the workaround

Derive a class, i.e. RhVerticalGrid from VGridControl and add this piece of code:

public class RhVerticalGrid: VGridControl { private int lockUpdateCount; #region BeginUpdate public override void BeginUpdate() { lockUpdateCount++; base.BeginUpdate(); } #endregion #region EndUpdate public override void EndUpdate() { lockUpdateCount--; Debug.Assert(lockUpdateCount >= 0); base.EndUpdate(); } #endregion #region CancelUpdate public override void CancelUpdate() { lockUpdateCount--; Debug.Assert(lockUpdateCount >= 0); base.CancelUpdate(); } #endregion protected override void OnDataManager_ListChanged(object sender, ListChangedEventArgs e) { if (lockUpdateCount == 0) base.OnDataManager_ListChanged(sender, e); } public override void InvalidateRecord(int recordIndex) { if (lockUpdateCount == 0) base.InvalidateRecord(recordIndex); } }

That's it. My execution speed dropped down from >3s to almost instantaneous execution. Begin|End|CancellUpdate methods just increment/decrement lock counter (when lockUpdateCount == 0 the updates are allowed, otherwise not). The main improvements are within OnDataManager_ListChanged and InvalidateRecod methods where I propagate the processing only if updates are allowed. That's it - use the derived grid control instead of the original. Simple as that. And make sure your batch updates are enclosed with Begin|EndUpdate methods!

How does one find such culprits?

If you are scratching your head with the question "how does one find the culprit of such slowdowns"? The answer lies in performance profiling. To find this one I've used my favorite AQTime profiler (much more than just a performance profiler) and quickly found the culprit. I should also mention that this isn't the first time that AQTime helped me to find both memory and performance problems. Yep, a performance and memory profiler is a must have tool for serious developer, even better if this is AQTime. Anyway, here is clear picture (from AQTime graph view) of the culprit in action:

image

BTW, here is the link to the bug report on the [DevEx] support center I made today.

LLBLGen Pro got even better

Frans released a new major version of his [LGP] ORM. Basically, a top notch ORM product got even better. Make sure you check the what's new list - and if you are looking for an (better) ORM, don't hesitate to give it a try, you won't regret it.

The only feature I miss is LINQ support which is supposed to appear in the next version. Actually, including LINQ support isn't that useful right now as Visual Studio 2008 aka Orcas isn't supposed to ship until very late 2007/beginning of 2008. Frans is actually wise to wait a little bit more with LINQ and instead concentrate on actual improvements which help developers right now. That said I am really waiting to see LINQ for [LGP] when VS 2008 gets released. I suspect LINQ will make [LGP] (and any other ORM product out there) code much much more readable that it is now (limited by current .net languages).

Keep up the excellent work, Frans.