A site devoted to discussing techniques that promote quality and ethical practices in software development.

Thursday, May 26, 2011

Apple users, welcome to the real world!

If you have not be told Apple has virus, you should read this excellent piece of report on "Mac Defender" malware. As a realist, I have always laughed when Apple users naively believing the sales hype that it does not virus!

I have been following this Mac Defender for a long time, way before the popular media outlets picked up the story. When I first heard of this, I realized that apple users' age of innocence had just been shattered. My warning to my friends and view on the vulnerability of these unrealistically complacent apple users would be like pack of drunken sheep to the wolf. Surprisingly this same sentiment is echoed by Molly Wood in CNet. As a developer, software bounds to have vulnerability as it is crafted by human. Besides, Apple OS is just a Unix and Unix/Linux is always known to be malware/virus.

I believe it will become a lot worse before it gets some form of relief because these attackers have sharpened its modi operandi in the Windows world and that Windows users are conditioned to become more alert about Virus/Trojan/Malware. To these attackers, Apple users are trusting lot!

I am not surprised to learn of the recommended "unhelpful" customer service directive of Apple as reported. Molly has outlined several notable exemplars of Apple's unhelpfulness. The "silence-then-solution pattern" will definitely put their users at great risk through Apple's generosity of giving attackers a wide windows of attack opportunity. Does Apple care? I doubt it. The old "Poison DNS attack" and Apple's slowness in addressing this is just another shiny example of a company cares more about a facade than what's behind and its users well beings.

Monday, May 16, 2011

Complete build process of Matlab component for .Net with meaningful version number

The previous post describes a recipe for injecting meaningful version number into NE Builder produced .Net assembly.

The normal NE Builder generated assembly using non-embedded CTF archive requires the use of a /linkres option to describe in its manifest an external linkage to a CTF file. Unfortunately, this option is not available to Visual Studio C# project and as a result, it is not possible to create a class library project in Visual Studio to automate this process; batch process is still required.

Incidentally, some one in the forum was puzzled by the automatic copying of the CTF file when one referenced a NE Builder generated assembly. This action is caused by the use of /linkres option.

In view of the need to use a batch file or command line operation to build the .Net assembly, it is therefore advantage to automate all the build steps without the need to invoke the Matlab IDE to generate the external CTF archive, the C# and companion files. Below are the steps to construct this batch file:

1. Create a command to invoke the Matlab component compiler (mcc.exe) to generate the CTF archive, the C# and companion files using the -F switch with your Matlab prj file. To see this switch usage, invoke MCC -? on a command prompt.

This switch takes all the setting from the PRJ file and is a convenient way to centralize all the specifications in one place that is also available to Matlab IDE, which is a convenient visual tool to set those specifications.

2. Execute the CSC.EXE, the C# compiler, with the response file constructed as described in the previous post.

This batch program generates all the files afresh without the need to rely on part IDE build and part command line build to complete the process; this technique ensures all files are in sync and that it can be incorporated into any automatic build process.

Wednesday, May 11, 2011

Caveat in NUnit testing Matlab NE Builder produced assembly

Matlab NE Builder produced assembly when loaded needs to extract the compiled scripts into a cache area which is normally in the executable directory.

When such an assembly is being tested in NUnit, with Shadow Copying enabled (the default setting), can generate a file path that exceeds the maximum length of file path name of Windows.

When this happens, it can generate an exception saying that it cannot create an instance of MCR. Check the Text output tab of NUnit console for any message saying something like this:
Failed to remove
 Verify file ownership and access permissions.
Where is a very long path name.

If you still want to use Shadow Copying support in NUnit, go to NUnit's console's settings dialog and specify a short directory as a Shadow Copy Cache, which is usually your "%Temp%\nunit20\ShadowCopyCache". Alternately turn off the Shadow Copy can help to alleviate this problem.

Recipe to add assembly version to Matlab NE Builder produced assembly

Matlab NE Builder, once called .Net Builder, is a tool from Matlab to package the Matlab script (the .m files) into a .Net assembly making the functions specified in Matlab available to .Net application.

This tool unfortunately provides token .Net infrastructure support. It can produce a strongly named assembly but it does not have facility to allow user to specify the assembly version data, a vital piece of information to support strict version binding policy.

Every assembly produced by NE Builder, regardless strongly name or not, has the version As a result it is not very useful. According to Matlab forum, Matlab does not have any way to deal with this issue. This blog post provides a recipe of allowing user to add assembly version or any other pieces of information to the NE Builder produced assembly. It does not use any undocumented or hack to produce the result; it simply uses the same standard .Net build specifications the NE Builder Deployment tool uses.

  1. From the Deployment tool (read NE Builder) build the assembly and making sure that you clear the "Embedded the CTF Archive". This is because when you use embedded CTF archive, the builder deletes the CTF file after building the assembly. We need this file in the subsequent steps and hence not embedding lets us access this file. Furthermore, it is easier if you make the source and output directory the same.
  2. Save the build steps to a build log and open it with a text editor.
  3. Look out for the line containing the CSC.exe as we will use that to produce the response file for the C# compiler.
  4. Copy the text after CSC.exe into a text file. You can insert line break to make it more readable.
  5. Add AssemblyInfo.cs to the response file. This file contains the assembly information you wish to include into the assembly.
  6. Save the text file into a file with customary .rsp extension into the same directory as the source.
  7. Create the AssemblyInfo.cs file if not exist and specify your assembly version and other information.
  8. Run the CSC with this response file to produce your assembly which will contain the required assembly version.
Step 2-6 are only required as a once off exercise and if you add or remove .m file from your package, edit the response file accordingly.

This recipe then allows one to produce a versionable strong name .Net assembly that carries the Matlab script.

Tuesday, May 10, 2011

No use to defend an indefensibly bad user-interface

I was shown a web application designed to manage project and progress report, a la MS Project minus the Gantt Chart and time lines. I am not a user of any project management software and hence this post is not about its capability, though my shallow knowledge of this topics tells me that it is rather incomplete.

As a software developer with low tolerance of terrible user-interface that only the creator loves, this package has an example that really enrages me into highlighting it here. Consider the following screen capture showing the 'Select All' check box circled in red:

A shaped-eye reader will instinctively spotted something amiss in this diagram; the 'Select All' check box is checked but the other check boxes in that column aren't. Well according to the developer, this is a feature. Let me describe how this 'Select All' check boxes works in this application.

Normally it was not checked and the user can check the relevant row by using the check box which operates in the standard manner.

The minute you click on the 'Select All' check box, it selects all the check boxes in that column. Nothing strange about that and it is the same behavior as in Google's GMail or Hotmail, just to name a few.

However, the user-interface becomes non-intuitive and distorted when you try to de-select all the check boxes by clicking on the 'Select All' check box, which by now has a check mark on it, an operation that comes naturally for all users. In this crazy illogical scheme, the developer literally creates a different class of check box but with the same look and few as the standard ones. A true bastardization of the check box.

When one clicks on the 'Select All' check box the second time, instead of extinguishing the check mark and de-selecting all the check boxes in that column as everyone (bar the developer) expects, this check box maintains the check mark - a kind of one shot check box but not exactly. If you click it in vain attempt to de-select all, it in fact selects all check boxes for you. There is no way to de-select all and the 'Select All' check box is not disabled or grayed out. Because there is no way to uncheck all the check boxes in one operation, experimentation with this 'Select All' check box brings frustration and curses.

The standard check box has a binary state - click it to check and click it to uncheck - and that is the behavior any user expects when one sees a check box and not a distorted one as highlighted.

The developer maintains that it is not a bug but a feature just like so many when cornered into this indefensible situation. I think the developer is wise to read this book and constantly reminding himself that "Your user is not you". In clear vain attempt to defend the indefensibly wrong user-interface, the developer offers this way to extinguish the 'Select All' check mark, which is an other brilliant example of his failure to understand "Your user is not you":
  • Uncheck each check box in the column manually
  • Then press the update
  • The round trip back from the server will clear the 'Select All' check box.
I am surprise that he did not suggest to log out of the application and relog in as that would have done the same job more quickly saving you manually unchecking each check box. Interesting no other users think that this is a brilliant design! My advice: listen to your users as you software is as useful as seen through your users' eyes. Your user is not you or there are more users than developers.

The correction of this distorted user-interface is technically very simple but psychologically difficult as the developer has to admit that it is a bug first; they already have JavaScript code to check each check boxes in the column and it is just a simple process to run the code through to uncheck them. In fact, they expand more efforts in creating this only-creator-loves distorted user interface.

 This software also has another time wastage feature, which clearly has not gone through any user design mock up such as "Paper Prototyping" by Carolyn Snyder.

There is a page where the user has to indicate the progress of each milestone and at which date. The date must be entered by using 3 combo boxes - one for day, month and year as shown here:

This means to enter a date, one needs a minimum of 6 mouse clicks. If the date can be entered via a edit box with an calendar icon to invoke it if necessary, the user could enter the date much more quickly.

But this will require more developer's input validation effort. Since it is already using client side JavaScript, it is not such a big deal with the most difficult task for determining the client's locale.

When you have a dozen or so dates to enter, every saving is a real bonus and the developer should consider redesigning. The current design is really for the benefit of the developer - saving code. In fact, they still need to validate the input. What if someone select 31/04 or 30/02?

Blog Archive