Archive for March, 2011

Mutable fields in Correspondence

Tuesday, March 29th, 2011

image Correspondence is a client-side NoSQL database that synchronizes with other clients through a shared server. If you’ve experimented with the bits, there is a breaking change in the latest changeset. A new build is coming soon, as well as a closed beta of the synchronization server.

Correspondence is built on the concept of historical modeling. This is a set of theory describing historical facts with partial order. The facts have predecessor/successor relationships that define both the order in which they can consistently be applied, and the mechanism for graph traversal.

One of the core tenets of historical modeling is that facts are immutable. This makes them easy to synchronize. Fields also determine the fact’s identity. Two facts having equal fields are actually the same fact.

In many applications, it is desirable to have mutable fields. In historical modeling, you have to use the Entity Property pattern to simulate mutability. This pattern builds on the strengths of historical modeling, allowing participants to unambiguously synchronize state changes. It also has the added benefit of detecting conflicts, and allowing users and applications to resolve them. Unfortunately, this pattern can be cumbersome to apply.

The mutable keyword

A Correspondence model is defined using a language called “Factual”. The upcoming release adds three keywords to the Factual modeling language. These three keywords break a fact into sections:

  • key - Required. Contains all key fields.
  • mutable - Optional. Contains all mutable fields.
  • query - Optional. Contains all queries and predicates.

The key and query sections contain members that have always been in the language. The mutable section adds new functionality.

Fields in the mutable section are mutable. The compiler generates the Entity Property pattern on your behalf. These fields are not part of the key, since they are not actually stored within the fact itself. They are stored in successor facts that track changes.

You write this:

fact Person {
key:
    unique;

mutable:
    string name;
}

The Factual compiler generates this:

fact Person {
key:
    unique;

query:
    PersonName* nameCandidates {
        PersonName n : n.person = this
            where n.isCurrent
    }
}

fact PersonName {
key:
    Person person;
    string value;
    PersonName* prior;

query:
    bool isCurrent {
        not exists PersonName next : next.prior = this
    }
}

Disputable properties

The Entity Property pattern detects conflicts and allows the application to resolve them. To aide the application in this task, Correspondence defines Disputable<T>. This template can be converted to and from the raw type T, but it also exposes two additional properties.

  • InConflict – A boolean that is true if a conflict has been detected.
  • Candidates – A collection of possible values.

Using Disputable<T>, the view model can apply an alternate style when a conflict has been detected, and allow the user to choose from among the candidates to resolve it.

public class PersonViewModel
{
    private Person _person;

    public PersonViewModel(Person person)
    {
        _person = person;
    }

    public string Name
    {
        get { return _person.Name; }
        set { _person.Name = value; }
    }

    public bool ShowConflictStyle
    {
        get { return _person.Name.InConflict; }
    }

    public IEnumerable<string> CandidateNamesItemsSource
    {
        get { return _person.Name.Candidates; }
    }

    public string CandidateNamesSelectedItem
    {
        get { return _person.Name; }
        set { _person.Name = value; }
    }
}

The Factual modeling language specification has been updated to reflect the new mutable keyword. If you’ve created Correspondence models in the past, you will be required to add key and query section headers once you upgrade. Then you will be able to take advantage of mutability.

User identity on Windows Phone 7

Friday, March 11th, 2011

When you can challenge another person to a Faceted Reversi game, you provide their name. So Reversi needs a way of authenticating the user so it can send them the correct games. I didn’t want the user to have to enter a password to play my game, so I relied upon the anonymous Live ID already available on the phone. I just have to associate your anonymous ID with your chosen screen name.

Windows Live provides identity

Once I’ve gotten the anonymous Live ID using the technique I previously blogged about, I create an Identity fact. An Identity is defined in the factual model as:

fact Identity {
    string anonymousId;

    Claim* claims {
        Claim c : c.identity = this
    }
}

The anonymoudId string is the only field in an Identity. That means that it comprises the entire key of that fact. No matter how many times I construct an Identity with that anonymoudId, it will be the same instance. The Identity instance is created and added to the Community.

_community = new Community(storageStrategy)
    .AddAsynchronousCommunicationStrategy(new POXAsynchronousCommunicationStrategy(configurationProvider))
    .Register<CorrespondenceModule>()
    .Subscribe(() => _identity.Claims);

string anid = UserExtendedProperties.GetValue("ANID") as string;
string anonymousUserId = String.IsNullOrEmpty(anid)
    ? "test:user12"
    : "liveid:" + ParseAnonymousId(anid);
_identity = _community.AddFact(new Identity(anonymousUserId));

The first time you run the app, it creates this Identity instance. Every subsequent run is simply loading it from isolated storage.

Notice that I’m subscribing to _identity.Claims before the _identity is even instantiated. The subscription is a lambda expression, so it will be executed later. So what are Claims?

A user claims a name

A Claim is the desire for a person to have a specific user name. It is defined in factual as:

fact Claim {
    publish Identity identity;
    User user;
    publish IdentityService identityService;

    ClaimResponse* responses {
        ClaimResponse r : r.claim = this
    }

    bool isPending {
        not exists ClaimResponse r : r.claim = this
    }
}

The Claim refers to the Identity from the phone, and the User that is being claimed. A User is:

fact User {
    string userName;

    Claim* claims {
        Claim c : c.user = this
    }
}

Just like Identity, User has only one field. This field is its key, so any User object that I create with userName = “michael” will be the same instance. This is what makes it possible to challenge another user: the User instance I create on my phone will be the same as the one that he creates on his phone.

A service approves and denies claims

So when the user selects a name, a Claim is created. This Claim is published to an IdentityService, which is defined as:

fact IdentityService {
    Claim* pendingClaims {
        Claim c : c.identityService = this
            where c.isPending
    }
}

Notice that IdentityService has no fields. Since fields define identity in Correspondence, there is nothing to distinguish one IdentityService from another. Every time I create a new IdentityService, I get back the same instance. It is a singleton.

There is a subscriber on my server looking for Claims published to the IdentityService. When it finds a Claim, it verifies that the user name is not taken by another Identity. It will then generate a ClaimResponse:

fact ClaimResponse {
    publish Claim claim;
    int approved;
}

This response is published to the Claim. Remember the lambda expression in the Community Subscribe method? The phone has subscribed to all Claims attached to the Identity. That means that the ClaimResponse will be pushed to the phone, and the user will know whether it was accepted or rejected.

This is an example of the Service pattern in Historical Modeling. With this pattern, I can allow people to choose their own name, but still rely upon Windows Live to authenticate them for me.

Flip pieces on the way out

Wednesday, March 9th, 2011

I recently released Faceted Reversi, the first Windows Phone 7 application based on the Correspondence framework. Let me take a few posts to tell you how it works, and how you can build your own Correspondence application.

Faceted Reversi is, of course, a Reversi game. Reversi pieces have two sides: black and white. Each color represents one player. When a player moves, he places a piece with his color up. He then flips all of the enemy pieces that were flanked by that move.

When we describe the rules, we say that the player flips the pieces as he makes a move. This is in fact not how the code is written. On a players turn, all the program does is record the move. Pieces are flipped on the way out.

GameBoard and GameState

The game logic is controlled by two classes: GameBoard and GameState. A GameBoard is an immutable object that records a fixed board position. A GameBoard can tell you:

  • which color is on each square
  • who’s move it is
  • how many pieces of each color are on the board
  • what moves are legal
  • what the board would look like after a legal move

Or saying the same thing in code:

public class GameBoard
{
    public static GameBoard OpeningPosition { get; }
    public int MoveIndex { get; }
    public PieceColor PieceAt(Square square);
    public PieceColor ToMove { get; }
    public int BlackCount { get; }
    public int WhiteCount { get; }
    public IEnumerable<Square> LegalMoves { get; }
    public GameBoard AfterMove(Square square);
}

GameState, on the other hand, is mutable. It records the current GameBoard and lets the user make a move.

The separation of immutable state from mutable state is significant. It makes it clear that the board position is dependent upon the sequence of moves. We represent that dependency using Update Controls. The current position is governed by a Dependent sentry that runs UpdateGameBoard when it becomes out-of-date.

public class GameState
{
    private Game _game;

    private GameBoard _gameBoard;
    private Dependent _depGameBoard;

    public GameState(Game game)
    {
        _game = game;

        _depGameBoard = new Dependent(UpdateGameBoard);
    }

    public PieceColor PieceAt(Square square)
    {
        GameBoard gameBoard = GetGameBoard();
        return gameBoard.PieceAt(square);
    }

    private GameBoard GetGameBoard()
    {
        _depGameBoard.OnGet();
        return _gameBoard;
    }

    private void UpdateGameBoard()
    {
        _gameBoard = GameBoard.OpeningPosition;
        if (_game != null)
        {
            List<Move> moves = _game.Moves.ToList();
            moves.Sort(new LocalMoveComparer());
            int expectedIndex = 0;
            foreach (Move move in moves)
            {
                if (move.Index != expectedIndex)
                    return;
                if (move.Player.Index == 0 && _gameBoard.ToMove != PieceColor.Black)
                    return;
                if (move.Player.Index == 1 && _gameBoard.ToMove != PieceColor.White)
                    return;

                Square square = Square.FromIndex(move.Square);
                if (!_gameBoard.LegalMoves.Contains(square))
                    return;

                _gameBoard = _gameBoard.AfterMove(square);
                ++expectedIndex;
            }
        }
    }
}

UpdateGameBoard runs through the list of moves in the game, sorted by move index. It validates each move against the current position. If an invalid or out-of-place move is found, it just gives up. The assumption is that moves were validated before they were added to the game, but we don’t want to crash the app or enter an invalid state if something goes wrong.

Record a move

So what happens when the player makes a move? Simple:

public partial class Player
{
    public void MakeMove(int index, int square)
    {
        Community.AddFact(new Move(this, index, square));
    }
}

All we do is record that move. This adds it to the Moves collection in the game, stores it in the local database, sends it to the other player, and makes GameBoard out-of-date. Let’s break that down.

Publish a move to other subscribers

The Move fact is declared in a language called “factual”, specifically designed for Correspondence.

fact Move {
    Player player;
    int index;
    int square;
}

Adding a fact to the Correspondence community stores it in the local database. It also sends the fact to the server, which forwards it to all interested subscribers. We can tell that the other player is interested because he subscribed to the Game.

_community = new Community(storageStrategy)
    .AddAsynchronousCommunicationStrategy(new POXAsynchronousCommunicationStrategy(configurationProvider))
    .Register<CorrespondenceModule>()
    .Subscribe(() => _identity.ApprovedUsers
        .SelectMany(user => user.ActivePlayers)
        .Select(player => player.Game)
    );

The linq query in the Subscribe call returns all of the Game facts that the player is currently involved in. When a player subscribes to a game, the server will send him all of the published facts. A Player fact is published to a game, as indicated by the “publish” keyword in the factual model.

fact Player {
    publish User user;
    publish Game game;
    int index;
}

A Move fact belongs to a Player, so it is pushed as well. This is how Correspondence knows to send the move to the other player.

Update the UI when a move arrives

So when the move reaches the other player, how does the game know to refresh the board? The Game fact queries for related moves, again in the factual model.

fact Game {
    unique;

    Move* moves {
        Move m : m.player.game = this
    }
}

This makes _game.Moves a live collection. Whenever a fact is added, whether on this phone or from another one, this collection changes. Update Controls recognizes that GameBoard depends upon this collection. So when it changes, GameBoard becomes out-of-date, and Update Controls notifies the view to redraw itself through data binding.

All Correspondence applications work this way. State changes cannot be side-effects of a user action. Instead, the program simply has to store the user action into the model. State changes occur on the way out, back toward the user interface. They are dependent upon the history of user actions.

It doesn’t matter if the move comes from the user interface, from the local database, or from another user. Flipping the pieces is not a side-effect of making a move. It is dependent upon the sequence of moves, regardless where they come from.

How not to sell a two-player game on Windows Phone 7

Thursday, March 3rd, 2011

Last week I launched Faceted Reversi, a two-player strategy game for Windows Phone 7. In this game, you play Reversi against other people who have also downloaded the application. It uses Correspondence to coordinate moves between the two phones. So far the adoption has been … slow.

image

Faceted Reversi has two ways to play:

  • pass the phone
  • remote

In pass-the-phone, you play against another person, but the two of you sit together and share a device. It just acts like a game board. In remote mode, you play against somebody else with their own device. Think “Words with Friends”. To begin a remote game, you either pick someone that you know or let the server choose a random player.

Faceted Reversi is priced at $1.99, and has a trial mode. In trial mode, you can play as many pass-the-phone games as you like. But you can only play one remote game. To unlock the ability to play more games, you have to pay.

There are a couple of problems with this revenue model. First, trial apps don’t appear in the Free section of the Marketplace. And second, the network is a catch-22.

Free vs Trial

Neither iOS nor Android has trial mode built into their applications. You have to buy it before you can try it. As a result, many developers published two versions of their apps: the free one and the paid one. Windows Phone implemented the trial feature to solve this problem. A developer can publish one application, yet still give the end user both experiences.

But Windows Phone also has a Free section in the Marketplace. This section includes applications that have a $0.00 price tag. It does not include applications with a trial mode. Many developers have found that people download apps from the Free section much more frequently than they do from the paid sections. As a result, developers have been abandoning the trial model and publishing two versions of the app.

Catch-22

The only reason to pay for Faceted Reversi is to play games against the network of people who have also paid for Faceted Reversi. The value of the application is proportional to the size of this network. When nobody has bought the app, nobody is in the network. And when nobody is in the network, nobody will buy the app. The only way to get people to buy the app is to seed the network.

Faceted Reversi Free

To solve these two problems, I am working on Faceted Reversi Free. This will be a completely separate app. It will be priced at $0.00, so it will appear in the Free section of the Marketplace. This should drive higher download numbers. I don’t think that a full order of magnitude increase (i.e. 40) is unreasonable to expect.

This version of the game will have only one feature: random player. You will be able to play against another player, but you won’t be able to say who. This will have the effect of seeding the network with a sea of random players … at least 40 of them!

This version will also serve ads. Before each game, it will display an ad while it waits for the server to select a random player. This should provided some revenue to keep the Correspondence server running, and incentivize people to buy the paid version.

In upcoming posts, I’ll describe how to build a two-player game with Correspondence. I’ll also keep you posted regarding the uptake of Faceted Reversi Free and whether my clever scheme succeeds.