Write down some unwritten rules of Flutter development.
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index c859a4ba..077fce6 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -114,6 +114,11 @@
* `git pull-request` (if you are using [Hub](http://github.com/github/hub/)) or go to `https://github.com/<your_name_here>/sky_engine` and click the
"Compare & pull request" button
+Please peruse our [style guides](sky/specs/style-guide.md) and
+[design principles](sky/specs/design.md) before working on anything
+non-trivial. These guidelines are intended to keep the code consistent
+and avoid common pitfalls.
+
Please make sure all your checkins have detailed commit messages explaining the patch.
If you made multiple commits for a single pull request, either make sure each one has a detailed
message explaining that specific commit, or squash your commits into one single checkin with a
diff --git a/examples/widgets/README b/examples/widgets/README
new file mode 100644
index 0000000..54c151f
--- /dev/null
+++ b/examples/widgets/README
@@ -0,0 +1,12 @@
+Small examples of the Flutter widget framework
+==============================================
+
+To run these, open a terminal in this directory and use the following
+command:
+
+```bash
+pub global activate flutter
+flutter start --checked -t foo.dart
+```
+
+...where `foo.dart` is the file you want to run.
diff --git a/sky/specs/design.md b/sky/specs/design.md
index 6dfe745..be0688f 100644
--- a/sky/specs/design.md
+++ b/sky/specs/design.md
@@ -1,35 +1,106 @@
Design Principles
=================
+Flutter is written based on some core principles that were mostly
+intuited from past experiences with other platforms such as the Web
+and Android, some of which are summarised below.
+
+Lazy programming
+----------------
+
+Write what you need and no more, but when you write it, do it right.
+
+Avoid implementing features you don't need. You can't design a feature
+without knowing what the constraints are. Implementing features "for
+completeness" results in unused code that is expensive to maintain,
+learn about, document, test, etc.
+
+When you do implement a feature, implement it the right way. Avoid
+workarounds. Workarounds merely kick the problem further down the
+road, but at a higher cost: someone will have to relearn the problem,
+figure out the workaround and how to dismantle it (and all the places
+that now use it), _and_ implement the feature.
+
+Tests
+-----
+
+When you fix a bug, first write a test that fails, then fix the bug
+and verify the test passes.
+
+When you implement a new feature, write tests for it.
+
+Run the tests before checking code in. (Travis does this for you, so
+wait for Travis to give the green light before merging a PR.)
+
+API design
+----------
+
* There should be no objects that represent live state that reflects
some other state, since they are expensive to maintain. e.g. no
HTMLCollection.
-* Property getters should be efficient. If an operation is inefficient
- it should be a method instead. e.g. document.getForms(), not
+* Property getters should be efficient (e.g. just returning a cached
+ value, or an O(1) table lookup). If an operation is inefficient it
+ should be a method instead. e.g. document.getForms(), not
document.forms.
-* There should be no APIs that require synchronously computing layout
- (or other expensive operations).
+* There should be no APIs that require synchronously completing an
+ expensive operation (e.g. computing a full app layout outside of the
+ layout phase).
-* Any API that can be implemented in terms of another is a convenience
- API and should be implemented in a framework, not as part of the
- core. e.g., no document.forms.
+* We use a layered framework design, where each layer addresses a
+ narrowly scoped problem and is then used by the next layer to solve
+ a bigger problem. This is true both at a high level (widgets relies
+ on rendering relies on painting) and at the level of individual
+ classes and methods (e.g. in the rendering library, having one class
+ for clipping and one class for opacity rather than one class that
+ does both at the same time).
- - having APIs for performance reasons is fine (e.g. querySelector()
- could be implemented by crawling but it would be so much faster if
- it could use the runtime's ID hashtables that it's ok to support
- natively)
+ - Convenience APIs belong at the layer above the one they are
+ simplifying.
+
+ - Having dedicated APIs for performance reasons is fine. If one
+ specific operation, say clipping a rounded rectangle, is expensive
+ using the generic API but could be implemented more efficiently
+ using a dedicated API, then a dedicated API is fine.
* APIs that encourage bad practices should not exist. e.g., no
document.write(), innerHTML, insertAdjacentHTML(), etc.
-* If we expose some aspect of a mojo service (e.g. touch events) we
- should expose/wrap all of it (e.g. mousewheel) so that there's no
- cognitive cliff when interacting with that service
+ - String manipulation to generate data or code that will subsequently
+ be interpreted or parsed is a bad practice as it leads to code
+ injection vulnerabilities.
-* APIs should always spell acronyms like words (findId, not findID;
- XmlHttpRequest, not XMLHttpRequest)
+* If we expose some aspect of a mojo service, we should expose/wrap
+ all of it, so that there's no cognitive cliff when interacting with
+ that service (where you are fine using the exposed API up to a
+ point, but beyond that have to learn all about the underlying
+ service).
-* If we extend a method to have new arguments, they must be optional
- if there's any content using the existing method.
+Bugs
+----
+
+"Don't lick the cookie": Only assign a bug to yourself when you are
+actively working on it. If you're not working on it, leave it
+unassigned. Don't assign bugs to people unless you know they are going
+to work on it.
+
+File bugs for anything that you come across that needs doing. When you
+implement something but know it's not complete, file bugs for what you
+haven't done. That way, we can keep track of what still needs doing.
+
+Regressions
+-----------
+
+If a check-in has caused a regression on the trunk, roll back the
+check-in (even if it isn't yours) unless doing so would take longer
+than fixing the bug. When the trunk is broken, it slows down everyone
+else on the project.
+
+There is no shame in making mistakes.
+
+Questions
+---------
+
+It's always ok to ask questions. Our systems are large, nobody will be
+an expert in all the systems.
diff --git a/sky/specs/style-guide.md b/sky/specs/style-guide.md
index fa27b13..2016925 100644
--- a/sky/specs/style-guide.md
+++ b/sky/specs/style-guide.md
@@ -1,5 +1,5 @@
-Sky Style Guide
-===============
+Flutter Style Guide
+===================
In general, follow our [Design Principles](design.md) for all code.
@@ -8,6 +8,22 @@
maintaining it for years, can quickly determine what the code does. A
secondary goal is avoiding arguments when there are disagreements.
+All languages
+-------------
+
+Avoid checking in commented-out code. It will bitrot too fast to be
+useful, and will confuse people maintaining the code.
+
+Avoid checking in comments that ask questions (like "What should this
+be?"). Find the answers to the questions, or describe the confusion,
+including references to where you found answers. ("According to this
+specification, this should be 2.0, but according to that
+specification, it should be 3.0. We split the difference and went with
+2.5, because we didn't know what else to do.")
+
+
+
+
Dart
----
@@ -15,10 +31,12 @@
guide](https://www.dartlang.org/articles/style-guide/) for Dart code,
except where that would contradict this page.
-Always use the Dart Analyzer. Do not check in code that increases the
-output of the analyzer unless you've filed a bug with the Dart team.
+Always use the Dart Analyzer. Avoid checking in code that increases
+the output of the analyzer unless you've filed a bug with the Dart
+team. (Use "skyanalyzer" to run the analyzer on Flutter code.)
-Use assert()s liberally.
+Use assert()s liberally to describe the contracts that you expect your
+code to follow.
Types (i.e. classes, typedefs (function signature definitions) and
@@ -27,7 +45,21 @@
doubles and strings are prefixed with k. Prefer using a local const
or a static const in a relevant class than using a global constant.
-Don't name your libraries (no ```library``` keyword), unless it's a
+When naming callbacks, use `FooCallback` for the typedef, `onFoo` (or,
+if there's only one and the whole purpose of the class is this
+callback, `callback`) for the callback argument or property, and
+`handleFoo` for the method that is called.
+
+If you have a callback with arguments but you want to ignore the
+arguments, name them `_`, `__`, `___`, etc. If you name any of them,
+name all of them. Always be explicit with the types of variables in
+callbacks unless you are ignoring them (and have named them with
+underscores).
+
+If you have variables or methods that are only used in release mode,
+prefix their names with `debug` or `_debug`.
+
+Avoid naming your libraries (no ```library``` keyword), unless it's a
documented top-level library, like `painting.dart`. Name the files in
```lower_under_score.dart``` format.
@@ -76,20 +108,25 @@
same order (unless the order matters).
-All variables and arguments are typed; don't use "var", "dynamic", or
-"Object" in any case where you could figure out the actual type.
-Always specialise generic types where possible.
+All variables and arguments are typed; avoid "dynamic" or "Object" in
+any case where you could figure out the actual type. Always specialise
+generic types where possible. Explicitly type all array and map
+literals.
+
+Always avoid "var". Use "dynamic" if you are being explicit that the
+type is unknown. Use "Object" if you are being explicit that you want
+an object that implements == and hashCode.
+
+Avoid using "as". If you know the type is correct, use an assertion or
+assign to a more narrowly-typed variable (this avoids the type check
+in release mode; "as" is not compiled out in release mode). If you
+don't know whether the type is correct, check using "is" (this avoids
+the exception that "as" raises).
+
Aim for a line length of 80 characters, but go over if breaking the
line would make it less readable.
-Only use => when the result fits on a single line.
-
-When using ```{ }``` braces, put a space or a newline after the open
-brace and before the closing brace. (If the block is empty, the same
-space will suffice for both.) Use spaces if the whole block fits on
-one line, and newlines if you need to break it over multiple lines.
-
When breaking an argument list into multiple lines, indent the
arguments two characters from the previous line.
@@ -113,14 +150,22 @@
> print('Hello ${name.split(" ")[0]}');
> ```
+Only use => when the result fits on a single line.
+
+When using ```{ }``` braces, put a space or a newline after the open
+brace and before the closing brace. (If the block is empty, the same
+space will suffice for both.) Use spaces if the whole block fits on
+one line, and newlines if you need to break it over multiple lines.
+
Don't put the statement part of an "if" statement on the same line as
the expression, even if it is short. (Doing so makes it unobvious that
there is relevant code there. This is especially important for early
returns.)
If a flow control structure's statement is one line long, then don't
-use braces around it. (Keeping the code free of boilerplate or
-redundant punctuation keeps it concise and readable.)
+use braces around it, unless it's part of an "if" chain and any of the
+other blocks have more than one line. (Keeping the code free of
+boilerplate or redundant punctuation keeps it concise and readable.)
> For example,
> ```dart
@@ -138,6 +183,30 @@
> }
> ```
+> For example:
+> ```dart
+> if (a != null)
+> a()
+> else if (b != null)
+> b()
+> else
+> c()
+> ```
+> ...but:
+> ```dart
+> if (a != null) {
+> a()
+> } else if (b != null) {
+> b()
+> } else {
+> c()
+> d()
+> }
+> ```
+
+Use a switch if you are examining an enum (and avoid using "if" chains
+with enums), since the analyzer will warn you if you missed any of the
+values when you use a switch.
Use the most relevant constructor or method, when there are multiple
options.
@@ -156,11 +225,6 @@
saves a stack frame per iteration.
-When naming callbacks, use `FooCallback` for the typedef, `onFoo` (or,
-if there's only one and the whole purpose of the class is this
-callback, `callback`) for the callback argument or property, and
-`handleFoo` for the method that is called.
-
When defining mutable properties that mark a class dirty when set, use
the following pattern:
@@ -184,10 +248,6 @@
Start the method with any asserts you need to validate the value.
-If you have variables or methods that are only used in release mode,
-prefix their names with `debug` or `_debug`.
-
-
C++
---
@@ -197,3 +257,6 @@
Java
----
+
+Objective C
+-----------