Code Samples for the Windows Phone 8 Database webinar

Those are the code samples from my Webinar, if you are a regular reader of this blog and didn't come here from the webinar you should probably ignore this post.

The table class definition - Treasure.cs download.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data.Linq;
using System.Data.Linq.Mapping;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TreasureApp1.Data
{
    [Table]
    public class Treasure : INotifyPropertyChanged, INotifyPropertyChanging
    {
        private int _id;
        private string _type;
        private int _amount;
        private string _unit;

        [Column(IsPrimaryKey = true, IsDbGenerated = true, DbType = "INT NOT NULL Identity", CanBeNull = false, AutoSync = AutoSync.OnInsert)]
        public int Id
        {
            get { return _id; }
            set
            {
                if (_id != value)
                {
                    NotifyPropertyChanging("Id");
                    _id = value;
                    NotifyPropertyChanged("Id");
                }
            }
        }

        [Column]
        public string Type
        {
            get { return _type; }
            set
            {
                if (_type != value)
                {
                    NotifyPropertyChanging("Type");
                    _type = value;
                    NotifyPropertyChanged("Type");
                }
            }
        }

        [Column]
        public int Amount
        {
            get { return _amount; }
            set
            {
                if (_amount != value)
                {
                    NotifyPropertyChanging("Amount");
                    _amount = value;
                    NotifyPropertyChanged("Amount");
                }
            }
        }

        [Column]
        public string Unit
        {
            get { return _unit; }
            set
            {
                if (_unit != value)
                {
                    NotifyPropertyChanging("Unit");
                    _unit = value;
                    NotifyPropertyChanged("Unit");
                }
            }
        }

        [Column(IsVersion = true)]
        private Binary _version;

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        // Used to notify the page that a data context property changed
        private void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        #endregion

        #region INotifyPropertyChanging Members

        public event PropertyChangingEventHandler PropertyChanging;

        // Used to notify the data context that a data context property is about to change
        private void NotifyPropertyChanging(string propertyName)
        {
            if (PropertyChanging != null)
            {
                PropertyChanging(this, new PropertyChangingEventArgs(propertyName));
            }
        }

        #endregion

    }
}

The data context class TreasureContext.cs download.

using System;
using System.Collections.Generic;
using System.Data.Linq;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TreasureApp1.Data
{
    public class TreasureContext : DataContext
    {
        public static string ConnectionString = "Data Source=isostore:/Treasure.sdf";

        public TreasureContext(string conectionString)
            : base(conectionString)
        {
        }

        public Table Treasure;
    }
}

The CRUD operations CRUD.cs download.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TreasureApp1.Data
{
    class CRUD
    {
        public void Create()
        {
            using (var session = new TreasureContext(TreasureContext.ConnectionString))
            {
                var newObj = new Treasure()
                {
                    Type = "Gold",
                    Unit = "KG",
                    Amount = 50,
                };

                session.Treasure.InsertOnSubmit(newObj);

                session.SubmitChanges();
            }
        }

        public void Read1()
        {
            using (var session = new TreasureContext(TreasureContext.ConnectionString))
            {
                List list = (
                    from o in session.Treasure
                    where o.Type == "Gold"
                    select o
                    ).ToList();
            }
        }

        public void Read2()
        {
            using (var session = new TreasureContext(TreasureContext.ConnectionString))
            {
                List list = 
                    session.Treasure.
                    Where( o => o.Type == "Gold" ).
                    ToList();
            }
        }

        public void Update()
        {
            using (var session = new TreasureContext(TreasureContext.ConnectionString))
            {
                Treasure t = session.Treasure.Where(o => o.Type == "Gold").First();

                t.Amount = 500;

                session.SubmitChanges();
            }
        }

        public void Delete()
        {
            using (var session = new TreasureContext(TreasureContext.ConnectionString))
            {
                Treasure t = session.Treasure.Where(o => o.Type == "Gold").First();

                session.Treasure.DeleteOnSubmit(t);

                session.SubmitChanges();
            }

        }
    }
}

The database creation code for the app initialization (partial code) don't forget to add using Microsoft.Phone.Data.Linq; download

            using (var session = new TreasureContext(TreasureContext.ConnectionString))
            {
                if (!session.DatabaseExists())
                {
                    session.CreateDatabase();
                    var updater = session.CreateDatabaseSchemaUpdater();
                    updater.DatabaseSchemaVersion = 1;
                    updater.Execute();
                }
                else
                {
                    var updater = session.CreateDatabaseSchemaUpdater();
                    if (updater.DatabaseSchemaVersion == 0)
                    {
                        updater.DatabaseSchemaVersion = 1;
                        updater.AddColumn("Unit");
                        updater.Execute();
                    }
                }
            }

OzCode – the best debugging tool for .net (really)

Disclaimer:I do some work as a subcontractor of the company behind OzCode and I’ll probably become an investor in OzCode, in other words, I'm so impressed with this tool that I'm going to put a significant (for me) chunk of my own hard earned cash behind it.

OzCode is an extension for Visual Studio that adds all sort of debugging aids:

It includes simple stuff like a better exception widow that makes it trivially easy to drill down to the exception base cause.

Unbelievably useful stuff like search in in-memory data structures and the ability to easily see the contents of collections of objects that don’t has a reasonable ToString.

And totally magical features like “simplify” that can break apart complex expressions to show you exactly why that monster expression isn’t returning what you expect it to.

If you develop software for .net do yourself a favor and go download OzCode, debugging will never be the same again.

Plans for 2014

The last post was about what happened in 2013, now let’s talk about the plans for 2014:

yaTimer Time Tracking Software

yaTimer is still my flagship product and will continue to be in very active development.

Hopefully the great big update – version 3.0 – will finally be released this year.

Giraffe Upload Photo Backup Software

I will continue to support and fix bugs in Giraffe Upload but I don’t expect any major upgrades in 2014.

I really like Giraffe Upload and use it myself but I have to admit that it is unlikely to be a big success, it works, it has customers and I’m happy with it as it is but it is unlikely to pay the bills.

The Nbd-Tech web site and blog

I’m recovering from my little “burn-out” (you can read all about it in the previous post), I’m starting to get my energy level and creativity back to what their were before and hopefully soon I’ll start writing regularly for this blog again.

This web site and blog really look old-fashioned and need some new graphic design, I plan to get this site redesigned soon.

Also, this blog runs on SubText, a really nice blogging engine that is, unfortunately, a dead project, none of the core contributors worked on it for a long time and it’s unlikely to be updated in the future, this year I’ll, regretfully, migrate away from SubText into something else, probably the ubiquitous wordpress.

The Useful Photo Tips Blog

The useful photo tips blog will remain on the “back burner” for a while, I do want to stat posting there again but I have so much to do that realistically it will be a while before I have time to blog about my hobby again.

A new project

I’m always working on the next big thing and I plan a new product in the project management field, I’m going to announce it soon when its web site is ready.

What's your plans for 2014?

What happened in 2013?

Every year I write a post summarizing what I did in the last year and my plans for the next year, I’m not going to break this tradition now.

The short story – I worked in the data security field (specifically, on-line fraud prevention), this was super intensive and left me completely burned out, I stopped working in this field and I’m not going to do anything like that again.

I’ve been out of the security field for a few month but haven't completely recovered from my “burn-out” yet – but I’m getting better quickly.

So, how did my various products did in 2013 and how it comperes to my plans as I published them in January 2013.

yaTimer Time Tracking Software

yaTimer moved to a subscription only model (as planned) but this turned out to be a mistake and I started selling yaTimer as a one-time payment again a few days ago.

The product formally known as “yaTimer Central” was integrated into yaTimer (again, as planned) and is now available together with yaTimer as “yaTimer Desktop + Cloud”.

The big yaTimer version 3 that was planned for 2013 didn’t happen, also, I never did start charging for upgrades.

Giraffe Upload Photo Backup Software

Giraffe Upload got some bug fixes and better diagnostics during the year but there were no major changes.

This Blog, The Useful Photo Tips Blog

I was too burned out to write – but I am getting better and hope to start blogging regularly again soon.

I’ve also recently released two open source projects:

Hope I have some readers left after this quite year, please leave a comment and tell me how your year was.

yaTimer one-time payment is back

Switching to a subscription-only model was a mistake, people hate subscriptions and prefer the one-time payment model.

This isn’t exactly a surprise, but I really needed the stability that reoccurring payments bring with them and I figured that without the one-time option most people will just get the subscription – I was wrong, most people showed their dislike for subscriptions by not buying.

So, the yaTimer one-time payment option is back.

For $59 you can get a yaTimer license that never expires – but it only includes 6 months of free upgrades (the subscription include all upgrade for the lifetime of the subscription).

I still need the stability that subscriptions bring – that is why you can expect my future products to be web-based – where monthly subscription are the accepted norm, I personally truly like local applications but, that’s life.

The problem with javascript

It’s very easy to do simple things with JavaScript (like change this div when that link is clicked) especially with libraries like jQuery to help you, this is why in a lot of companies front end web development is handled by the most junior and unskilled developers in the company.

JavaScript is actually a very capable dynamic language that borrows heavily from functional programing, add to this advanced JavaScript frameworks (like Angular) and you got yourself a very advanced and modern environment that uses all that dynamic and functional power.

And with today’s “single page web apps” we write big complex programs directly in JavaScript and want (or even have) to use the power of the language and the environment, those are no the previous generation of web apps where everything happened on the server and JavaScript was used to add a little bit of interactivity – this is real software development that happens mainly in JavaScript.

And this is where things go wrong, that junior developer strait out of school that only studied basic Java (if you’re lucky) doesn’t know anything about dynamic or functional languages and without some serious mentoring their head will explode when they try to grasp “simple” JavaScript concepts like passing inline anonymous functions around.

This is were we are today, frontend web development is often considered simple, unimportant and is generally done by untrained and unqualified junior developers – at the same time that frontend is expected to be both extremely complicated in functionality and look beautiful (and simple).

This leaves us with two options – continue to push this work into the hands of the mass of unqualified so-called developers in the hope they’ll mange to teach themselves a pretty substantial amount of advanced concepts and bring in a “highly paid consultant” when this fails (please do continue to do this, sometimes I’m the highly paid consultant) or – treat frontend web development like the advanced difficult field it is and actually pay to bring in the qualified developers to begin with.

ok, rant over, what do you think?

How to design an API

APIs are interfaces that let code written by other developers interact with your software – and interface code has to be designed for whoever is doing the interfacing.

When you (or someone else) designs a user interface that interface has to fit the user’s worldview, it has to work like the user expects it to work and it has to make things easy for the user – user interface that is designed to show how clever you are or the be as pure and theoretically correct as possible is hard for the outside user to understand, difficult to use and, in one word, sucks.

There’s nothing controversial about the last paragraph, I’m sure you had to use GUIs that are almost completely unusable (yet, probably make perfect sense to whoever created them).

When you (or someone else) designs an API that interface has to fit the other system’s developer’s worldview, it has to work like that developer expects it to work and it has to make things easy for the developer – API that is designed to show how clever you are or the be as pure and theoretically correct as possible is hard for the outside developer to understand, difficult to use and, in one word, sucks.

In other words, I don’t care how true your API is to the spirit of HTTP, I don’t care how object oriented it is – all I care is that it’s easy to use.

Here are some guidelines that will make your API easier to use (those are HTTP specific because, let’s face it, most APIS today are built on HTTP):

Be consistent in naming

If the endpoint for getting gallery details is GalleryGet than the endpoint to get image details should be ImageGet, not image_get and not GetImage.

Also, if you call a collection of images “gallery” always use the word “gallery”, don’t call it gallery in one place, album in another and folder in a third place.

Same go for parameter names, if the id of an image is called “imageId” then always call it “imageId” and not “idOfImage” or just “id”.

Use HTTP POST

There are just two HTTP verbs that are supported by every HTTP client library in existence (including badly written ones I must use on some project for some bad reasons) – GET and POST, I don’t care if you really think PUT or DELETE are better for some endpoints I have GET and POST.

For anything that accepts a complex data structure or a large amount of data you have no choice but to use POST.

For anything that changes the system or even remotely security related you should use POST because it makes cross site scripting attacks slightly harder.

For everything else also use POST so I don’t have to look up what request to make every single time I call your service.

Don’t get cute with HTTP status codes

For example, a failed login should not use code 404 (for user not found)

If the endpoint I’m calling doesn’t exist use status code 404, if the server is on fire (literally or metaphorically) you can use 500, otherwise use status code 200, also for errors.

Just about any http client treats success (200) and failure (anything else) differently, errors can raise exceptions or just cause a different code path to execute (the code path that handles things like no network connection, it’s not the code that should handle simple logic errors), don’t make my job harder, use status code 200 and return the error details in the HTTP content.

Don’t make me spread my logic all over the place because you know the complete list of HTTP status codes.

Note: obviously, it’s ok to return 401 as part of an authentication handshake, 304 if you use e-tags or other status codes that are explicitly required by the protocols you use – just don’t use HTTP status code for business logic errors.

The response should always have the same format

All service endpoints, in all success and failure modes should return data in the same format – and that format should be JSON, HTTP forms encoding or plain XML.

There are parsers and formatter for those 3 formats for just about every programing environment in existence.

Also, the response should always have some flag indicating success or failure at the same place – I want to be able to tell success from failure with generic code if needed (just put something like success:true or <status>fail</status> in there).

Note that this implies no empty response, if you don’t have any data to return just return the success flag, it makes it easier to see what happened in logs and debugging sessions.

And, for failures you should have an error code of some sort – and that brings us to…

No generic error please

I don’t really care if your error code is a number or a string – and accompanying it with a human radable error message is really nice.

But the important thing is to make the error specific and actionable:

“system error” means nothing, when a customer gets an error described as “system error”, “general error” or some other meaningless phrase I don’t have a clue where to start troubleshooting this.

“parameter error” is better, at least it points in a direction, “parameter error: invalid value for parameter id” is much better.

And the best error message is one that tells me what I did wrong and how to correct it, for example “parameter error, invalid value for parameter id, the id you passed is of a non-editable widget, please call EnableEditing before this call”, notice how that last error can be resolved in a minute while “general error” probably means hours of trying to find what the #%#! Went wrong

Or, the short version

Don’t make me waste time looking up unimportant details, make sure the API plays nice will all technology stacks (because you don’t know what crappy library I’ll have to work with) and set things up so they help we when things go wrong.

Testing new method for (almost) fully automatic time tracking

I’m currently testing a new automatic way to track my time when I’m doing consulting.

Currently it’s a very barebones proof-of-concept (I only partially built the “engine” and it’s automatically tracking time into a text file), I’m thinking of developing it into an actual prototype other people could use and eventually a full product.

Anybody interested?

yaTimer Central Update Complete

I’ve just finished updating yaTimer Central, everything should work now just like before – except that to access the system you now go to http://www.yatimer.com and not to you own subdomain (if you go the the old address the system should redirect you automatically).

If there’s any problems please tell me immediately via e-mail or using the contact page.

Thank you

yaTimer Central Update

Sometime over the weekend I’m going to update yaTimer Central, this is going to be a major update that fixes many of the design mistakes I made when I first started to build it.

There will be some downtime but I’m going to try to keep the downtime to a minimum, also, it’s possible you will try to use yaTimer Central and get an error saying your account has expired or has been canceled, if this happens than it’s because the new version manages accounts in a different location and your account just hasn’t moved to the new location yet.

As part of the update all the old reports you have created will be deleted, please download any report you want to save before Friday – but you don’t have to worry, all your data will move over to the new version and you will be able to regenerate those reports if needed.

This is the first part of project that will upgrade the technology behind yaTimer Central in order to make it easier to add more features, the main changes of this upgrade are:

  • yaTimer Central is no longer a separate product, it’s just part of yaTimer now.
  • The entire subdomain craziness is out, your web control panel will be accessible from www.yaTimer.com using the “Sign In” link at the top right corner.
  • All the subscription plans are no longer available, it’s now sold as part of yaTimer, it’s $9.99 per user per month (including the yaTimer software) for the small business edition with all the feature of the professional plan or $99.99 per user per month for the new enterprise features.
  • If you currently has a personal plan you will get all the features of the small business edition for no extra cost, if you currently have any subscription that is cheaper than the new pricing you keep the old price.
  • The signup process have been vastly improved, it’s now 3 fields instead of 10.
  • And, the major change that I hope nobody will notice, the account and user management will be replaced with one that will be easier for me to manage and support.

I’ll post here just before I start the upgrade and when the upgrade will be over.