Hixie's Natural Log

2016-03-27 07:50 UTC Flutter: Developer experience

One of our goals with Flutter is to make developing with Flutter a pleasant experience for developers. As part of this, I've focused on the debugging experience.

Lots of our classes make ample use of asserts to help catch problems (either bugs in your applications, or, as it sometimes turns out, bugs in the framework itself). The meaning of these asserts aren't always very clear, though. Because of this, we've been changing some of them to exceptions with very elaborate messages.

For example, if you try to use a material widget without a "Material" object somewhere in its ancestor chain, instead of just asserting that there's no Material ancestor, we'll now output a paragraph-long message that explains the problem, gives you guidance for how to fix it, and tries to explain exactly where in the application the problem is.

I'm especially happy with the very detailed messages you get now when something is wrong with a BoxConstraints object or when a RenderBox fails to fit in its BoxConstraints. It now shows a message that really goes out of its way to track down the cause of the problem. I hope it helps someone!

You can find some more examples of this by searching for "FlutterError" in the repository. By the way, if you run into any asserts that aren't clear, please don't hesitate to file an issue. It'll help us prioritise which asserts to expand on next.

Another thing I've been working on recently to help the debugging experience is adding toString() implementations to pretty much every object in the framework. I want to make Flutter app developers feel like they can dump any random object from the framework to the console and fully expect to see useful information out, whether it's a core primitive like Point or Rect, or a high-level object like RenderTable.

For example, if you print an Animation object, you'll get output like:

AnimationController(▶ 0.000) ➩ Interval(0.0⋯0.9) ➩ Cubic(0.25, 0.10, 0.25, 1.00)

This shows that this is an animation object that's rooted at an AnimationController that is currently playing (â–¶) and whose value is currently 0.000 (it was probably just created), that the value then goes through (âž©) an Interval class, and that the output of that goes through (âž©) a curve, in this case a Cubic. The arguments for the Interval and the Cubic are also shown in parentheses (a lot of our toStrings use this style).

Again, as with the asserts, if you run into any objects that don't print something useful when you dump them, file a bug! I get a strange satisfaction from implementing these toString functions. Don't ask.

Of course, these debugging aids are of no use if the documentation is terrible. We did some small hackathons at the office recently to see what the "out of the box" experience is for people who've never used Flutter, and the biggest thing we learnt was that we really need to flesh out our online docs.

So, we've started really aggressively adding dartdocs to everything in the framework. Every time we commit any code, it updates our docs at http://docs.flutter.io/. We are also tracking how many members (methods, getters, setters, classes, typedefs, you name it) we have yet to document.

Right now we're at 2068 undocumented members, but that's down substantially from a few months ago.

We're trying really hard to make the documentation useful. For example, we have a rule that if the documentation is something that someone could have written if they knew nothing about Flutter except the names of the class and method in question, then it's not allowed to go in. Sometimes that makes it really hard to write the documentation, but I think it will pay off in the end!

At the moment we're adding to the documentation more or less at random (actually, more or less in the order that the analyzer lists the members that are lacking docs), so let me know in the comments if there are specific things that you'd like to see documented sooner rather than later, and I'll make sure those are done next!