Monday, March 22, 2010

Windows Phone 7 - A party pack of sweets for developers

They are playing advertisements for Pascall's Party Pack on TV at the moment. The tag line is "All sweets you love, and one you can't stand." That pretty much sums up Windows Phone 7 for developers. Lots of goodness with a few things that may leave a bad taste in your mouth.

Despite the name, Windows Phone 7 Series is not a successor to Windows Mobile 6.x. Instead the name is a marketing nod towards Windows 7. Although both WP7 and WM6 are based on Windows CE, there is no resemblance at a higher level. From a user point of view, WP7 is closer to the iPhone than to WM6. A more accurate name would be Windows Phone 1.

After far too much time reading, watching and playing, here are my thoughts on WP7 as relates to development:

Tasty:
  • Development is done in c# and Silverlight/XNA. While native code would be nice, C# is easier to get into than Objective C. I haven't used either Silverlight or XNA previously but they look a lot more promising than the XP era Windows Forms used by Windows Mobile.
  • The tools are much better than those for the iPhone, and free
  • Push notifications look at lot easier to do than on the iPhone
  • Apparently xbox live integration is really good (I wouldn't know)
  • There are metric shitloads of tutorials, walk throughs and documentation (Twitter apps are the new hello world)
  • Games programming looks really, really nice

Meh:
  • The tools don't work well in virtual machines. You can make it work in a Win 7 32bit VM but it will run like a dog. The tools don't work at all in Win 7 x64. If you don't want to install onto your main system, you can try booting from a virtual hard drive.

Yuck:
  • No database support (apparently it's not necessary coz you have xml and the cloud). SQL Server CE is built into the rom, but no access is provided.
  • No multitasking (push notifications only)
  • No access to the file system. Application files all go into Isolated Storage in the app folder.
  • No "sideloading" of applications. Apps can only be installed from the Marketplace, or by Visual Studio
  • No built in file synchronisation (it's this cloud thing again).
  • No Silverlight support in Windows Mobile 6.x (but there is Silverlight for Symbian wtf) and no Win forms support in WP7. I.e. even if your win mobile app was written in c# it needs to be rewritten for WP7.
  • Limited APIs (no access to contacts, no sockets, ...)
  • No native code - no c, c++, pascal etc (and thus no firefox :()

I haven't felt this conflicted since the vfr 1200. Some nice things balanced by some not so nice.

As mentioned, so this is essentially version 1. Some of the issues are planned to be fixed after the initial release (copy/paste, database access).

Links

Microsoft
Windows Phone 7 tools
Code samples
Developer network
Mix10 videos (check out the keynote)
UI Guide

Silverlight
Get started in Silverlight
Get started with Silverlight in WM7

Example apps
Twitter client
Another twitter client (Scott Gu)
Labyrinth
Sqlite database

Blogs
Artificial Ignorance
10rem
Mobile development

Saturday, February 13, 2010

Solving a mid-life crisis with a Solid State Drive

My development laptop is now 18 months old, which makes it older than me in computer years. As part of a mid-life refresh, I replaced the boot drive, (250gb 7200rpm) with an Intel X25M 160gb ssd.

The result of this is that things are much snappier. How much snappier? I timed a few things of importance to me, booting my laptop and virtual machines, starting delphi and rebuilding a medium sized project (600,000 loc).

Overall, using an ssd cut the times by an average of 39%. Not too bad an improvement. To put it another way, my "getting started" time (boot laptop, boot vm, start delphi) went from 6:05 to 3:37.




Edit:
The Delphi 2007 install is screwed up somewhere. It certainly never used to take 3 minutes to start up:( but sometime last year it started getting really slow. I don't use that install or vm much so I haven't bothered trying to sort it out.

Thursday, January 14, 2010

[.net] Using sql server full text searching with Mindscape's LightSpeed

Advance warning: This post is only of use to people using Lightspeed or suffering from insomnia.

The problem
For my current c# project, I am using Mindscape's Lightspeed O/R framework. Lightspeed is a mighty fine product that makes object persistence a breeze. I would kill to have this in delphi.

However the only full text searching that LightSpeed supports out of the box is Lucene.net. Sql Server full text searching is not provided and no-one else seems to have created it.

The good news is that Lightspeed has a pluggable search engine framework so it is possible to add a new search engine. The bad news is that it's not overly well documented and there aren't many examples. The good news is that their online support is pretty good.

The resolution
Mindscape have a blog post outlining the process of adding a new search engine. However there are a number of traps for young players that aren't covered there, or indeed anywhere. The following should shed some light on the process.

Creating a new search engine requires implimenting ISearchEngine
  public interface ISearchEngine
{
IList<SearchResult> Search(string query, params string[] scopes);
void Add(IndexKey indexKey, string data);
void Update(IndexKey indexKey, string data);
void Remove(IndexKey indexKey);
void Optimize();
void Clear();
LightSpeedContext Context { get; set; }
void BeginBulkAdd();
void EndBulkAdd();
}
For sql server, and for most databases with inbuilt FTS, most of these methods can just be left as empty method bodies. All that needs to be implemented is Context (stores lightspeed configuration info such as the database connection string) and Search.

All that is needed to implement Context is:
    public LightSpeedContext Context { get; set; }

The fun comes in implementing Search:).

Example class
LightSpeed takes a class and maps it to a database table. In my case, the class is CmsModels.Entities.AccClaim. It is stored in the table AccData and has an integer primary key called ClaimId.

To perform a search, say finding all of my claims, I need to run the following query:
    select *
from FreeTextTable(AccData, *, 'Sean Cross Prevshort')
order by RANK desc
returning something like
    KEY       RANK
175671 27
175673 23
175646 15
175657 7
Key is the pk field (ClaimId) and Rank is how well the record matched the query.

Implimenting search
The Search method takes a query ("Sean Cross Hastings") and an array of type names (["CmsModels.Entities.AccClaim", ...]). It returns a list of SearchResult objects. SearchResult has the following constructor:

    public SearchResult(
string key,
string scope,
string entityId,
float score
)

In short, we take the query and the class name, construct a query, run it and use the results to create a list of SearchResult objects. Easy, in theory.

The devilish details
A Getting the table name
Given an object name, Lightspeed has a number of ways of determining the table name. Which option is chosen depends on the model and class settings.
The possibilities are
  1. Table name = class name (eg AccClaim)
  2. Table name = pluralised class name (eg AccClaims)
  3. Table name is explicitly set in class attributes (eg [Table("AccData", IdColumnName="ClaimID")])
  4. Table name is set programmaticly using a user defined naming strategy object (eg TBL_ACCCLAIM)
AFAIAA It is not possible to cover all these cases without access to LightSpeed internals. I have suggested that they provide a GetMyBloodyTableName method but that hasn't happened yet.

I have opted to only support cases 1 and 3 as this covers most of my classes, and it's easy. Any table name that falls into a different case can still be searched by specifying the table name explicitly.

To get the table name, I look for a TableAttribute and use it. If I can't find one, I use the type name.
    string tableName = "";
Type t = Type.GetType(scope);
object[] tableAttrib = t.GetCustomAttributes(typeof(TableAttribute), false);
if (tableAttrib.Length > 0)
{
tableName = ((TableAttribute)tableAttrib[0]).Name;
}
else
{
tableName = t.Name.ToUpper();
}
B Running the query
LightSpeed doesn't support running random sql so it's back to ado.net. The Context object can be used to create a SqlCommand object so it's pretty straightforward:

    IDbCommand command = Context.DataProviderObjectFactory.CreateCommand();           
Context.CreateUnitOfWork().PrepareCommand(command)
command.CommandText = string.Format("select * from FreeTextTable([{0}], *, @query) order by RANK desc", tableName);
((SqlCommand)command).Parameters.AddWithValue("@query", query);
IDataReader reader = command.ExecuteReader();

while (reader.Read())
{
...
}
C Creating the SearchResult objects
The SearchResult constructor is as follows:
    public SearchResult(
string key,
string scope,
string entityId,
float score
)
scope is the full class name passed into the Search method (eg "CmsModels.Entities.AccClaim")
entityId is the pk returned from the query in the Key field (eg 175671)
score is the rank returned from the query in the Rank field (eg 27)

key is the problem child. It is not properly explained anywhere in the documentation. I only found out how it is created by creating a dummy Add method, putting a breakpoint in there and examining the values passed in. It is a string in the format "{type name}]{entityId}" (eg "[AccClaim]175671").

So creating the results is
    while (reader.Read())
{
string entityId = reader[0].ToString();
int rank = reader.GetInt32(1);
string srKey = string.Format("[{0}]{1}", t.Name, entityId);
var sr = new SearchResult(srKey, scope, entityId, rank);
result.Add(sr);
}
Use the source Luke
The full source code is here. This is "works on my machine" quality code, so use with care. In particular:
  1. It doesn't handle pluralisation or naming strategies
  2. I cast directly to SqlCommand without testing it. Works for me but..
  3. It's not solidly tested. I only use it for one table so it may do funny things with other table structures.
  4. While running the code for the first time, the office power failed and the entire building went dark. I'm not saying it's related, but if it happens to you, you are on your own.
Things for MindScape to do
Provide a GetMyBloodyTableName and GetMyBloodyKey helper methods. Pretty please.

Wednesday, December 9, 2009

Solving Excel's "DBCC TRACEON" error with brute force and ignorance

We use excel reports extensively for reporting. They are fast to create and everyone can read and manipulate them. However there are the occasional gotchas. In the past, I have had to muck about with macros to fix connection string errors.

We upgraded to sql server 2008 on the weekend. Following that, nearly every data aware spreadsheet started giving "User 'public' does not have permission to run DBCC TRACEON" errors.

The problem, and a resolution is described here. Older versions of Excel/MS query identified themselves by including APP=Microsoft® Query;" in the connection string. MS also hard coded a check for "Microsoft® Query" in sql server which then runs DBCC TRACEON for no apparent reason.

Under sql server 2000, this in fine, but under sql server 2008, this fails as DBCC requires admin permissions.

The correct approach is change the connection string as described in the linked posts. Previously I have done this with macros. However this time I had 200+ spreadsheets to change :(.

I used a free search and replace utility (ReplaceText) to replace all instances of "APP=Microsoft® Query;" with "APP=Microsoft® WTFIT;". 2 important things here, the search and the replacement text are the same size, and the strings include "App=". Failing to do either will give you a corrupt file.

Problem solved in about an hour. It's not a pretty solution but it's better than spending a week at it.

Monday, November 16, 2009

Why I am moving from delphi to .net

This post is somewhat of a conterpoint to Why we didn’t convert to .Net. And perhaps we never will… I would have writen a post earlier, but I have spent most of the last week writing a tender proposal. The tender was for a claims management application with 70 users scattered across the country. My proposal was for a web application, using asp.net mvc and writen in c#.

My main objection to the WoW post is not his (or her) conclusion, but the subtext that .net has nothing to offer. Delphi programmers (or at least the vocal ones hanging out in non-technical) seem to have a strong view on what "real' programming is, and .net fails on several points (not native code, garbage collected, large installation footprint) for these guys. My view is that "real" programming is solving problems, and using the best tools for the job. In some cases that is delphi, but increasingly for me it is c#.

I haven't suddenly jumped ship, I reevaluated our (Catalyst's) needs earlier this year. Two things came out of that; most of our futher development will be in web apps, and .net is a better fit for us.

My and Catalyst's needs are not univeral. I don't pretend that my reason for moving apply to everybody. None the less, here are my reasons for moving:

Performance:
When it comes to performance, my most important benchmark is developer time. As a (mostly) solo developer, I don't have enough time to do all the things that I want. Anything that improves my productivity is good. I find c# faster to develop in.

From an runtime speed, it's hard to find good benchmarks. My feeling is that Delphi is faster, but not enough to make a noticable difference in my kind of apps. .net is let down by the winforms implimentation which (the last time I used it) had painfully slow drawing. The rest of it is plenty fast enough.

Language features:
Garbage collection and Linq. You ever love them or hate them. I love them. Delphi has mostly caught up with the other big ticket items but not these.

The standard library is another .net plus. It may have an enormous footprint but it's certainly extensive.

Staffing:
I work in a small city. Finding delphi developers here is nearly impossible. I only know of dev company using delphi and, for historical reasons, I can't use them.
.net developers is a different story. I could throw a stone out the window and hit one (seriously, they're just across the road).

Finally
I am not abandoning delphi completely, I have a number of delphi apps to maintain so I will be using it for a while yet. .net is not a silve bullet either. For web apps I find .net better, but for desktop apps it's pretty much even.

Tuesday, September 22, 2009

D2010 suppport in tiOPF

tiOPF is a Object Persistence Framework. That is, it is a framework based around saving your objects to, and loading them from, databases and/or flat files.

Delphi 2010 support has now been added to the latest repository version.

No release has been made as of yet, so you need to to retrieve it from the subversion repository. See here for instructions.

Notes
  • Running unit tests requires copying the xdom.pas unit from Delphi 2009as this is no longer supplied
  • There are a large number of failures with BDE paradox tests. I haven't investigated this yetas no-one uses paradox any more
  • tiVirtualTree and related components have been removed from the gui controls as they don't work under D2009/D2010.
  • Unicode is still not supported :(

Links

Tuesday, September 15, 2009

C# for the iPhone: Monotouch released

Novell's MonoTouch product has been released. MonoTouch is mono for the iPhone.
This allows compiling .net applications to native code and deploying to the iPhone.

There are akready 200 apps in the app store using Mono via Unity so the underlying technology is fairly well tested. MonoTouch adds Cocoa support and integration into MonoDevelop.

MonoTouch has 2 main issues for some users, the $399US price point, and the logo.
The price has disappointed a number of beta testers and the logo is the second worst I have seen recently (worst is the Toastmasters goatse).