Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

async await codelab #1659

Merged
merged 51 commits into from
Aug 7, 2019
Merged

async await codelab #1659

merged 51 commits into from
Aug 7, 2019

Conversation

legalcodes
Copy link
Contributor

@legalcodes legalcodes commented Jun 4, 2019

Staged:
https://jt-ww-1.firebaseapp.com/codelabs/async-await

Remaining tasks: (last updated 7/19)

  • Incorporate changes from Round 2 UX studies
  • observe test user completing the codelab
  • Incorporate changes needed after observing tester
  • Submit for final review

@googlebot googlebot added the cla: yes Contributor has signed the Contributor License Agreement label Jun 4, 2019
@RedBrogdon
Copy link
Collaborator

Feel free to ping me if I can be of use when you're building the gists for this.

Copy link
Collaborator

@sfshaza2 sfshaza2 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a great start!

src/_guides/language/async-await.md Outdated Show resolved Hide resolved
src/_guides/language/async-await.md Outdated Show resolved Hide resolved
src/_guides/language/async-await.md Outdated Show resolved Hide resolved
src/_guides/language/async-await.md Outdated Show resolved Hide resolved
src/_guides/language/async-await.md Outdated Show resolved Hide resolved
src/_guides/language/async-await.md Outdated Show resolved Hide resolved
src/_guides/language/async-await.md Outdated Show resolved Hide resolved
src/_guides/language/async-await.md Outdated Show resolved Hide resolved
src/_guides/language/async-await.md Outdated Show resolved Hide resolved
src/_guides/language/async-await.md Outdated Show resolved Hide resolved
  - add futures codelab to sidenav
  - add futures codelab to /codelabs page
  - update 'url' global to dart.dev
  - move futures codelab to /codelabs/async-await (formerly incorrectly placed in /language)
  - sundry content corrections in futures codelab
@kwalrath
Copy link
Contributor

kwalrath commented Jun 6, 2019

Cool stuff! But of course, I have feedback.

Some general feedback: I was surprised that there was only one embedded DartPad. I expect a lot more (inter)activity in a codelab. This feels more like a tutorial. (Maybe we can't make a codelab out of this; that's fine, a tutorial is good too.)

Whether it's a tutorial or codelab, even if we don't have exercises, we should prefer letting people execute code, as opposed to just telling them what happens when the code executes.

Some more specific feedback:

  • We need to be careful about terminology. For example:
    • We shouldn't say that futures return values. Instead, they complete with values (or errors).
    • "Future objects" == "futures". We shouldn't use the term "future object".
  • We need to be careful about how we use "async" and "asynchrony". I've been using async function to mean a function that has the async keyword before its body. As opposed to an asynchronous function, which might or might not have the async keyword. (It's perhaps too fine a point... but we do need to differentiate somehow, since the behavior of async-await is very different from the behavior of functions that use the Future API instead.) And then there's asynchrony (not async) or asynchronous code/programming/whatever, which I use to mean the subject in general.
  • When I printed the codelab, the font was very small. I think this is due to the embedded DartPad. We should do something to make DartPads not be so wide in the printed version. I think it's a problem we need to solve for mobile, too.
  • I found the instructions (and in particular the parts) to be confusing.
  • Let's avoid sentence fragments.
  • There are two titles on the page, and then a section head (Introduction) right beneath the title. Delete the section head and fix the titles.
  • We should be clear about the prerequisites (especially if this is a codelab; less of an issue if this is a tutorial). E.g., do they need experience writing/reading Dart code?
  • The timeline under the "What is a future" section is hard to read. Use a table or a figure?
  • I was surprised by the "Quick Review". That seemed like something you might have at the end of the whole article. But if we have it here, we should have it at the end of every major section.
  • Why isn't the code under "Execution flow with async and await" in a DartPad? We could save space and make it interactive!

I didn't want to make line-by-line comments, since it sounds like the content still isn't set. (Is that right?)

@legalcodes
Copy link
Contributor Author

legalcodes commented Jun 6, 2019

I was surprised that there was only one embedded DartPad.
There will be (at least) 3 total, the Errors section and the Putting it All Together section will both have embedded DartPads.

Incorporating your ideas from comments below, there may be as many as 5 total. Thanks!

@legalcodes
Copy link
Contributor Author

we should prefer letting people execute code, as opposed to just telling them what happens when the code executes.

This is a really good point -- there may be some easy opportunities to replace some of the examples with an embedded DartPad. Will update you on this.

@legalcodes
Copy link
Contributor Author

We should be clear about the prerequisites (especially if this is a codelab; less of an issue if this is a tutorial). E.g., do they need experience writing/reading Dart code?

The current draft lists only one pre-req (some experience writing asynchronous code) because if you've done that, you really can get through the codelab. Let me know if you think otherwise.

@legalcodes
Copy link
Contributor Author

Why isn't the code under "Execution flow with async and await" in a DartPad? We could save space and make it interactive!

Similar to above, I think this is a great idea. Will incorporate this.

@legalcodes
Copy link
Contributor Author

I found the instructions (and in particular the parts) to be confusing.

OK, good to know. The parts are there so that errors from test code output can reference them and give the user a clearer sense of which parts are failing.

@galeyang
Copy link
Contributor

galeyang commented Jun 6, 2019

I was surprised that there was only one embedded DartPad.
There will be 3 total, the Errors section and the Putting it All Together section will both have embedded DartPads.

I actually included at least 5 embedded DartPads in the study. Considering that I didn't include all sections in the study, I would expect to have probably 8 embeds in your full version. Feel free to ping me offline as needed.

We should be clear about the prerequisites (especially if this is a codelab; less of an issue if this is a tutorial). E.g., do they need experience writing/reading Dart code?

The current draft lists only one pre-req (some experience writing asynchronous code) because if you've done that, you really can get through the codelab. Let me know if you think otherwise.

Some pre-reqs I learned from a recent UX study

  1. Have programming experience in another language
  2. Know little Dart basic syntax
  3. Have some experience writing asynchronous code in another language

For the point 2, in UX study, I invited developers with "zero Dart experience" but know other programming languages. Before jumping into this codelab, I provided a cheat sheet that introduces basic syntax used in this codelab. I can share you the cheat sheet I created. Maybe we can offer similar things to new users so that it's easier to get started (without getting lost in a tour of language doc).

(Re: K) When I printed the codelab, the font was very small. I think this is due to the embedded DartPad. We should do something to make DartPads not be so wide in the printed version. I think it's a problem we need to solve for mobile, too.

The font size on mobile looks fine to me but the experience can be better. For printed version, I guess current Dartpad2 is not optimized for printing. It looks very confusing now.

(Re: K) I was surprised by the "Quick Review". That seemed like something you might have at the end of the whole article. But if we have it here, we should have it at the end of every major section.

+1 to this.

@kwalrath
Copy link
Contributor

kwalrath commented Jun 6, 2019

We should be clear about the prerequisites (especially if this is a codelab; less of an issue if this is a tutorial). E.g., do they need experience writing/reading Dart code?

The current draft lists only one pre-req (some experience writing asynchronous code) because if you've done that, you really can get through the codelab. Let me know if you think otherwise.

If they don't need Dart experience, we should say that.


<iframe frameborder="no" height="525" src="https://dartpad2-ux.firebaseapp.com/experimental/embed-new?id=f751b692502c4ee43d932f745860b056" width="100%"></iframe>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use production links for Dartpad2 instead of the UX experimental site.
https://dartpad.dartlang.org/experimental/embed-new.html?id=f751b692502c4ee43d932f745860b056

@kwalrath
Copy link
Contributor

kwalrath commented Jun 7, 2019

For the point 2, in UX study, I invited developers with "zero Dart experience" but know other programming languages. Before jumping into this codelab, I provided a cheat sheet that introduces basic syntax used in this codelab. I can share you the cheat sheet I created. Maybe we can offer similar things to new users so that it's easier to get started (without getting lost in a tour of language doc).

We have a cheatsheet on the site, but I haven't linked to it, because I didn't feel like it was ready yet (details at #1625 (comment)) . Maybe we can merge it and your cheatsheet?

Here's the semi-published cheatsheet: https://dart.dev/guides/language/cheatsheet

(Rereading your comment, I see that my cheatsheet should probably be a superset of yours, @galeyang.)

@legalcodes
Copy link
Contributor Author

Sounds good, I'll use the pre-reqs that Gale drew from the studies (including needing at least a little bit of dart experience). I'll also take a closer look at the various cheatsheet options we've proposed.

@@ -176,23 +177,27 @@ when using `async` and `await`:
* __The `await` keyword works only in `async` functions.__
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reverse the order of these two lines? In the following part, you first talk about async and then await.

If the function has a declared return type, then update the type to be `Future<T>`,
where `T` is the type of the value that the function returns.
If the function doesn't explicitly return a value, then the return type is `Future<void>`:

{% prettify dart %}
[!Future<void>!] main() async {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a little confusing to me that you added Future before the main() but didn't include this in the later side-by-side example.

The content says "If needed, update the function’s type signature". This makes me wonder "so why did you add a function’s type signature here but didn't add a function’s type signature in "Example: asynchronous functions".

Copy link
Contributor Author

@legalcodes legalcodes Aug 3, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm removing the If needed, update the function's type signature sentence.

Copy link
Contributor Author

@legalcodes legalcodes Aug 3, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with your point about you added Future before the main() but didn't include this in the later side-by-side example., which is why I think main() might not be the best choice for this example. @kathyw thoughts? It seems sort of odd to show examples with Future<void> main() everywhere, but it also seems odd to do it in some places but not others.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm curious about the rationale of changing from converts createOrderMessage () to concerts main().

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm trying to remember why we changed from createOrderMessage() to main(). I agree that it might be better to show something that isn't main(), so we don't have to dance around the return type declaration being OK to leave off. (Or we can do the dance later.)

I think the text was inconsistent about Future<void> vs. Future<TypeOfWhatYouReturn>, so we picked Future<void>. Also, maybe we wanted to handle the no-return case? But we could do that separately.

Copy link
Contributor

@galeyang galeyang Aug 6, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, maybe we wanted to handle the no-return case? But we could do that separately.

It seems that both examples in the What is a future? section has handled the no-return case using Future<void>.

description: Learn about and practice writing asynchronous code in DartPad!
---
This codelab teaches you how to write asynchronous code using
futures and the `async` and `await` keywords. This codelab includes
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Starting two sentences in a row with "This codelab" isn't ideal. My original suggestion was this:

This codelab teaches you how to write asynchronous....
Using the embedded DartPad editors, you can test your...


Here's an example that converts `main()` from a synchronous to asynchronous function.

First, add the `async` keyword before the function body.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see this change. The style guide favors using a colon if the intro immediately precedes the sample (https://developers.google.com/style/code-samples#intros).

Remember, you can only use the `await` keyword within an `async` function.
The following examples provide a comparison of synchronous and asynchronous functions.
If your window is wide enough, you'll see the two examples side-by-side.
Now that you have an async function, you can use the `await` keyword to wait
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

async function -> async function (global)

{{ site.alert.end }}

## Execution flow with async and await

As of Dart 2, functions marked as `async` run synchronously until the first
`await` keyword. This means that within an `async` function body, all
Async functions run synchronously until the first
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Async functions run -> An async function runs

@kwalrath
Copy link
Contributor

kwalrath commented Aug 5, 2019

(I can't add inline comments for this one)
In the section: "Example: Completing with an error": "How do you think you might handle the error?" This line throws me a question but doesn't tell me the answer. I'm not sure as a reader, what I'm supposed to do with this instruction and I may not know that I'll learn that later.

Maybe say just "A bit later you'll learn how to handle the error."

@@ -306,35 +324,40 @@ code snippets. Your task is to complete the exercise by writing code to make the
tests pass.
You don't need to implement `main()`.

To simulate asynchronous operations, your code will call the following functions, which are
To simulate asynchronous operations, call the following functions which are
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

which -> , which

* Example return value from `reportUserRole()`: `"User role: tester"`
* Note: you must use the actual value returned by `getRole()`; copying and pasting the example return value won't make the test pass.
* Get the user role by calling the provided function `getRole()`
Add code to the `reportUserRole` function so that it does the following:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reportUserRole -> reportUserRole()

Add code to the `reportUserRole` function so that it does the following:
<!-- Some bulleted items are intentionally lacking punctuation to avoid
confusing the users about characters in string values -->
* `reportUserRole()` Returns a future that completes with the following
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

delete reportUserRole()


#### Part 2: `reportLogins()`
Implement an `async` function `reportLogins()`:
Implement an async function `reportLogins()`:
* `reportLogins()` returns the string `"Total number of logins: <# of logins>"`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

similar changes to above

Copy link
Contributor

@kwalrath kwalrath left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few more comments... I hope these don't get lost in GH!

@@ -277,21 +277,21 @@ The asynchronous example is different in three ways:
**Key terms:**
* **async**: You can use the `async` keyword before a function's body to mark it as
asynchronous.
* **async function**: An async function is a function labeled with the `async`
* **async function**: An `async` function is a function labeled with the `async`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

async function -> async function

@kwalrath
Copy link
Contributor

kwalrath commented Aug 6, 2019

Uh oh, the build failed (on both stable & dev). Something about the code excerpts, but I didn't think you changed anything in the code. Can you figure this out, @legalcodes? (Or I can look at it tomorrow.)

Issue reported: #1818

@legalcodes
Copy link
Contributor Author

legalcodes commented Aug 6, 2019

Thanks for alerting me to this, I'll take look, will see what turns up.

{{ site.alert.end }}

## What's next?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a brief intro paragraph here.


{{ site.alert.info }}
You might have noticed that the functions in the exercises don't have return types. That's because Dart can infer the return type for you. Omitting return types is fine when you're prototyping, but when you write production code, we recommend that you specify the return type.
Dart can [infer the return type](https://dart.dev/guides/language/sound-dart#type-inference) for you.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Delete this final sentence, and move the link up to the second sentence of this note.

## What's next?

* [Asynchronous programming: futures & async-await](/tutorials/language/futures) tutorial
* [Dart's type system](/guides/language/sound-dart) (Includes more examples of type signatures with futures).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Includes more -> has
). -> )


## What's next?

* [Asynchronous programming: futures & async-await](/tutorials/language/futures) tutorial
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be good to have sub-items. Maybe something like this:

  • Play with DartPad
  • Try another codelab or a tutorial:
    • [Dart codelabs]
    • [Asynchronous programming...]
  • Read about [Dart's type system].

* [Asynchronous programming: futures & async-await](/tutorials/language/futures) tutorial
* [Dart's type system](/guides/language/sound-dart) (Includes more examples of type signatures with futures).
* [Preferring signatures in function type annotations](/guides/language/effective-dart/design#prefer-signatures-in-function-type-annotations)
* [Effective Dart](/guides/language/effective-dart)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these two Effective Dart links really something they might want to go to next? If so, explain why.

Copy link
Contributor

@galeyang galeyang Aug 6, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this tutorial https://dart.dev/tutorials/language/futures cover more content than this codelab? If it's mostly repetitive, maybe it's "other resources' rather than "next step".

--
In the previous UX study, users said they want to learn more about how Dart handles threads, controlling flow/loop, scheduling, and more complex asynchronous tasks other than grabbing values. It seems like Dart uses streams, Isolates, event loops for these Android related concepts. Hence, we can consider adding these two docs as next step.

{:.table .table-striped}

Use `async` and `await` to do the following:
* Implement an asynchronous `changeUsername()` function that calls the provided
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The flow seems slightly off. How about this:

Use async and await to implement an asynchronous changeUsername() function that does the following:

  • Calls the provided asynchronous function getNewUsername() and returns the result.
    • Example...
  • Catches any error that occurs and returns the string value of the error.
    • You can use...

### Exercise: Putting it all together

It's time to practice what you've learned in one final exercise.
To simulate asynchronous operations, this exercise provides the asynchronous
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Delete this sentence and the next one, or combine them somehow with the next paragraph. (As is, it's too repetitive.)

* `greetUser()` creates a greeting for the user by calling `addHello()`,
passing it the username, and returning the result.
* For example, if the username is "Jenny", `greetUser()` should create and
return the greeting "Hello Jenny"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Jenny" -> Jenny".
OR
the greeting... -> the following: "Hello Jenny"

#### Part 3: `sayGoodbye()`
<!-- pull out descriptions of -->
* Write a function `sayGoodbye()` that does the following:
* `sayGoodbye()` takes no arguments.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indent this and the following 2 items.
Delete the function name and capitalize the verb:

  • ...following:
    • Takes no arguments.
    • Catches any errors.
    • Calls...
  • If... succeeds, sayGoodbye() returns the string...

* `sayGoodbye()` calls the provided asynchronous function `logoutUser()`.
<!-- italicize <result> -->
* If `logoutUser()` succeeds, `sayGoodbye()` returns the string "\<result\>
Thanks, see you next time" where \<result\> is the String value returned by calling `logoutUser()`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

returned by calling -> produced (eventually) by logoutUser().

(or something else that acknowledges that logoutUser doesn't return a string value)

@@ -387,7 +387,7 @@ the same way you would in synchronous code.

### Example: async and await with try-catch
Run the following example to see how to handle an error from an
asynchronous function. Can you guess what the output will be before running it?
asynchronous function. What do you think the output will be before running it?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

delete "before running it"

asynchronous expression. The `await` keyword only works within an `async` function.
{{ site.alert.end }}

## Execution flow with async and await
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

## -> ###
(I noticed in the side nav that the exercise applies to "Working with futures", not "Execution flow". I think this change fixes that problem.)

Copy link
Contributor

@kwalrath kwalrath left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cla: yes Contributor has signed the Contributor License Agreement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants