tl;dr: I'm building a version of Minesweeper in Dart as an example of something straight-forward and fun. I hope to show how to build Dart apps and demonstrate why Dart is a great tool for building web experiences. Play it here. Check out the code on Github. Watch my blog for updates in the next few weeks.

Intro

I'm having a lot of fun with Dart. It's a great intersection of the things I love about other platforms.
  • The open source goodness of Ruby and Python.
  • The type goodness of C# and Java--which lights up a productive IDE development experience.
  • The run everywhere goodness of Javascript.
I've built a couple projects in Dart, but I wanted to build something for newbies.

Getting the Code

Dartsweeper uses my Dartlib library. I haven't quite migrated Dartlib to pub. If you want to play with the code, make sure you download (or git clone) both the code for Dartsweeper and Dartlib and put them in adjacent directories.
  • source_code
    • sweeper.dart
      • lib
      • html
      • readme.md (for sweeper)
      • ...
    • dartlib
      • bin
      • docs
      • readme.md (for dartlib)
      • ...
If you're using Dart Editor, which I recommend, open both directories to see all of the code.

Approach

Honestly, I'm a bit confused and tired of the whole MVVMVPMVC discussion.

Let me put my approach simply: Separation of Concern (SOC). Build small pieces that do a small set of things and connect them in clean ways. It enables easy unit testing. It enables flexible architecture. It avoids bike shedding about what's the V or the C or the VM or the P.

The other acronym I'll hang my hat on: TDD. Test-driven development is amazing generally, but especially for games. Games often have states that take a while to get to--like winning. Games that have random state--like Dartsweeper--can also suffer from obscure edge casses that one can only find by playing a lot.

It ends up being much easier to just point a unit test at a Game object and have it hammer through a large number of game states.

But I'm getting ahead of myself. Follow along in the lib directory in the repo.

lib/sweeper directory

Main logic of the game. Nothing UI-specific.

  • Field: The read-only, 2-D collection of squares. Booleans. True if it's a mine. Also exposes the adjacent count to make rendering numbers easy.
  • Game: The core logic. Tracks the state of the game. Allows revealing and flagging. Exposes the duration of the game.
  • GameState and SquareState: enum-like classes for recording the state of the game or individual squares
Take a look at the associated unit tests. Dart advertises itself as "batteries included". An example: the core libraries include a really nice unit test framework.

lib/html

The HTML version of the game.
  • GameView: Populates the provided DOM elements and wires up event handles.

html

Where you actual application exists.
  • sweeper_demo.dart: A tiny bit of code that imports the game logic and the html logic, finds the target elements in the page, and creates the GameView.
  • index.html: Defines the elements for the app. Aside from a couple of special script tags, it's just HTML, which is the point.
  • style.css: Just styles. Nothing special.

Experience

So far I haven't hit many big issues with the app. It's a joy to work in an IDE with a typed language.

I'm much less scared about refactoring code in Dart because I get warnings if I've forgotten to rename a variable or if I'm missing an argument to a method. Not only does the type system make initial development faster (with features like member completion), it makes code maintenance easier. This is a huge win.

Being able to debug Dart source directly (instead of generated javascript) also greatly improves productivity.

I have hit a couple of bumps, though.

Issues

Compiled Javascript size

It's huge. Far bigger than the source Dart code in my project. It's been the source of mockery on Hacker News, etc.

While it's a bit annoying now, I'm not worried. At the moment, compiler processes all of the imported libraries (even the code that's not used) and generates output that's not minified. Tools like the Closure Compiler have shown this a solved problem. The Dart team is worried about stability and correctness now, as they should. I'm patient.

Minor cross-browser issues

I was using MouseEvent.toElement, which is not supported in FireFox. I moved to MouseEvent.currentTarget and everything now works. This is a case where having the uncompressed javascript output was a good thing. It was debug the output to find the problem. 

Future

Canvas, sound, mobile. I already have a nice set of retained graphics libraries in Dartlib. I going to dive in with animations and the Web Audio API. I'll keep the existing HTML app in place, since it's such a straight-forward sample. Once I figure out a clean interaction model, I also hope to make Dartsweeper sing on phones and tables.

I'm excited to see how much I can light up this app with Dart.

Stay tuned.