Tuesday, September 24, 2019

Sample Ballot: From pdf to custom page

Ballot Guide

Last year I wrote Ballot Guide to learn Flutter and Firebase and to make election information more accessible.

The 2019 election is coming up in November, so I thought, hey I'll use my app to get more information. But there was nothing.

Google Civic Information API

I went to check the list of elections on the Google Civic Information API and indeed, they don't have our local elections here in Colorado. But I still want to see what will be on my ballot before actual election time. Fortunately, my county publishes a sample ballot on the election website:

My first thought was, woah there are lots of stuff to vote on! Looking closer though, multiple cities and school districts are listed, and I don't reside in all of them, so my actual ballot should have fewer items than this. Can I filter it down to only the items relevant to me?

My voting districts

I went back to the Google Civic Information API and used the voterInfoQuery end point to find my voting districts. That works for city council, but not school districts, because that API does not return them.

Looking around, I found the shapefiles for Special Districts on the Colorado Department of Local Affairs (DOLA) GIS page. Great! But how do I query shapefiles?

Turf.js

I found a javascript library: Turf.js. A few steps to transform the data:

But that didn't work! I tried many things until I realized that the exported GeoJSON has points in (lng, lat) instead of (lat, lng). Gah! Need to write a script to convert that.

Split the sample ballot

Finally I have a way to find my school district. Now I need to split the sample ballot into each contest, and only show those matching mine. I create a Google spreadsheet and, gasp, copy and paste the data from the PDF by hand.

The worst are the ballot measures. The PDF is multi-column, and when I copy and paste the line runs from one column to the other, instead of go onto the logical next line. It was very not fun.

Ingest into Firebase

Once I have the information on Google sheet, I wrote a script to curl the tsv, convert to json, and upload it into Firebase using the Firebase Admin SDK.

Missing data

I have missing data on both the ballot side and the district side. For the ballot, not all counties have sample ballots yet, so I have to wait until closer to the election. On the district side, some cities are subdivided into wards. Google Civic Information does not always return ward information. And I don't always have the shapefiles to do it myself.

Annotations

With that, I am able to filter and display a sample ballot before the election. Mostly. However, I still want more information. Specifically, city council and school board contests are non-partisan, but I would like to know the registered party of the candidates.

Colorado voter registration information in public. Anyone can purchase the whole database for $50. The webiste voterrecords.com bought it and made a search interface out of it, so I queried the candidates and added that information to my Google sheet to be ingested into Firebase.

Try it out

You can see it in action at huddle4hope-districts.web.app, or embedded below:

Currently it works for Adams County, Boulder County, Larimer County and Weld County in Colorado. If you don't live in those counties, you can try these addresses:

  • 9440 Hoffman Way, Thornton, CO
  • 2000 Walnut St, Boulder, CO
  • 2446 Reception Ct, Fort Collins, CO
  • 1001 50th Ave, Greeley, CO

Let me know what you think!

Wednesday, March 20, 2019

Meetup Child Care: Parents Night Out

As a meetup organizer, I strive to be as inclusive as possible, but I struggle with picking a time that works for parents. I've surveyed the members to see if moving from a weeknight to weekday lunch time or weekend would work better, but there was no obvious time that works for everyone.

I was lamenting about this problem to Effie and she told me about Parents Night Out. Various companies and non-profits host evening activities where parents can drop off the kids and have some time to themselves. What about running a meetup on an evening when Parents Night Out is available?

I loved the idea, but I don't know the options available in the Boulder area. I mentioned that during a meetup and Sepideh said she knows some. I looked into the places she mentioned and March 15 was a good date at Shredder Ski, so I scheduled our annual Women Techmakers Lightning Talks that night.

I managed to get some event funding from Google to pay for the child care. I set up a Google Form for parents to sign up, and purchased gift certificates for them. This way, the parents did not need to worry about payment at all. Instead, I submit the receipts for the gift certificates and get reimbursed by Google.

I am so happy to find out about Parents Night Out! If you run a meetup, or know meetup organizers, please try this idea. Hope this will help make meetups more inclusive.

Sunday, May 20, 2018

Modular Meal Planning

The topic of healthy eating often comes up when I'm chatting with friends. They are very impressed that my husband and I both work from home and cook lunch and dinner every day. We got quite the modular meal planning system in place and so I thought I'd share it here.

Our taste

I'm Chinese and my husband is French, so we have our own notion of comfort food. Vegetables are very prominent, and we like them mushy. No salad in our house haha.

The algorithm

  1. Make a grid for all the lunches and dinners for the week
  2. Fill in the fixed dishes:
    Sunday lunch: Pork Roast
    Monday lunch: California Bowl
    Tuesday lunch: Tacos
  3. Decide what mega dishes we want to make Saturday and Sunday evenings. These provide leftovers throughout the week
  4. Spread leftovers throughout the week
  5. Fill the remaining slots with one-meal dishes and single-ingredient sides + roast

Here is an example:

Sat L Leftovers
D Mega dish
Sun L Pork Roast
D Mega dish
Mon L California bowl
D Leftovers
Tue L Tacos
D Single-ingredient side + Roast
Wed L Single-ingredient side + Roast
D Leftovers
Thur L One-meal dish
D Leftovers
Fri L Single-ingredient side + Roast
D Leftovers

Advantages

Why we like this meal planning algorithm:

  • Enough constants that we don't need to think too hard
  • Enough variety that we don't get bored
  • Enough easy dishes (leftovers and single-ingredient dishes) for lunches when we don't have a lot of time

The modules

Fixed dishes

We make these every week, on the same days.

  • Pork Roast: Sunday lunch. Buy a chuck of pork loin, cut slots to embed garlic wedges, bake until 55°C. Take out of oven and rest until 60°C. This provides meat for the rest of the week. We cook just side dishes to go with it.
  • California bowl: Sushi without rolling. Set rice cooker on timer after breakfast. Scoop out at lunch, top with canned tuna, surimi, cucumber and avocado. Mix and eat.
  • Tacos: Cook tilapia or swai in pan. Remove when done. Cook onion with green bell pepper. Serve with tortillas and sliced avocado.

Mega dishes

We cook these weekend evenings, with the intent of eating the leftovers throughout the week. Many of the dishes are made in a pressure cooker 💨.

We rotate them so we don't eat the same dishes every week.

Single-ingredient sides

These are easy sides that we make, with the pork roast as the meat. There are 3 kinds:

  • Leafy vegetables Chinese-style. We cook napa cabbage, spinach and bok choy this way. Cut vegetable into small pieces. Add oil and garlic to pan. Add vegetables. Drizzle with sesame oil. Add salt. Cover and cook until vegetable is soft.
  • Vegetables French-style. We cook carrot, cauliflower and green beans this way. Cut vegetable into small pieces. Boil until soft. Drain. Add butter and garlic to pan. Put back vegetables to coat. Brown if desired (we do that for cauliflower).
  • Bake in oven. We cook sweet potatoes, squash, asparagus and broccoli this way.

The leafy veggies take the least time to cook so we usually do that for lunch.

One-meal dishes

We sprinkle these one-meal dishes in the meal plan to add variety. One-meal means there won't be leftovers. If the dish has no meat, we eat it with pork roast.

Suggestions?

What are you favorite dishes to make? I'd love to add more options to each category!

Monday, November 13, 2017

Types of Android Tests

I saw this Reddit discussion on Android testing concepts, which tries to categorize tests into short, medium and long. I don't find that a very useful way to think about different types of tests, so I thought I'd give offer my view.

Two dimensions

I think it's more useful to think of tests in two dimensions

  • Does it run on the JVM or needs a device?
  • Does it test the UI or not?

Depending on the answer to these two questions you get 4 types of tests.

JVM tests

JVM tests are the faster to run since you don't need to deploy to a device (physical or emulator), and should be preferred. Try to structure your app so that the logic is in pure Java classes i.e. does not use the Android framework.

Since we are writing Android apps, it is difficult to test the UI without the Android framework. There are two ways you can do that.

Robolectric

The first way to test the UI on the JVM is Robolectric, which mocks the Android framework. I don't recommend that, because the mocked classes don't necessarily reflect the actual behavior on the Android framework.

Model-View-Presenter (MVP)

The second way is to make your Android classes as logic-free as possible. There are various architecture patterns you can use to achieve that, for an example Model-View-Presenter (MVP). MVP allows you to encapsulate the Android part inside the View (Activity or Fragment) and extract the logic into the Presenter, which does not use any Android framework code. This way, you can test the Presenter on the JVM.

Espresso

After you have tested your logic extensively on the JVM (you may want to aim for 100% test coverage), you should add some UI tests. Think of these as sanity checks, going through the happy path to make sure the app does not crash when you bump up the library version. I use Espresso for UI tests, together with Mockito and MockWebServer to set up a hermetic environment for repeatable tests.

More info

Thursday, May 11, 2017

Why I run a conference

As some of you know, I'm one of the organizers for 360|AnDev. It's a lot of work to run a conference, so why do I do it?

I started the conference because I want an inclusive place for people to learn about Android:

  1. We want it to be welcoming to beginners so that they can plug into the community right away. That's why we have a "Getting Started" track (see our CFP).
  2. We want to encourage first-time speakers, so we run Q&A Hangouts to answer as many questions as we can.
  3. We want people to speak regardless of their financial situation, which is why we cover the travel costs for speakers if their companies do not.
  4. We have inclusivity scholarships to help people who cannot otherwise attend.

We did not collect attendee statistics last year, but you can see from our speaker lineup that we were off to a good start in terms of inclusivity.

We need your help

Last year we managed to break even, which was really good for a first-year conference that covers travel costs for speakers. We hope to keep it up, to have a financially viable event that we can run again and again. But we need your help:

  1. Please spread the word. Tell everyone about the event:
    July 13 - 14, 2017. Denver Colorado. 360andev.com.
  2. If you plan to attend, please buy a ticket right away so us organizers are not sitting at the edge our seats wondering if anyone would come.
  3. If you are at a company, please ask your employer if they would like to sponsor the conference: 360andev.com/sponsorship.
  4. Support us via Patreon: https://www.patreon.com/360andev

Every bit helps. Thank you for your support!

Sunday, April 16, 2017

Droidcon Boston Keynote

I just came back from the inaugural edition of Droidcon Boston last week, at the beautiful Calderwood Pavilion.

Keynote preparation

I had the honor to deliver the Day 2 keynote at Droidcon Boston.

I prepared extensively when I first gave this keynote at Android Summit, so this time I was relatively chill about it. I updated some of the slides, and gave a practice version at Denver Droids. For a last minute refresher, I brought the video recording on my laptop and watched myself give the talk on my flight to Boston.

Fresh material

Normally I do not tweak my talk the day before the conference, but after seeing the shout-outs in Annyce's opening keynote I was inspired to do the same.

My talk is about how sharing makes you an expert, and I used tweets from day 1 of the conference as examples.

Learn from each other

That is the beauty of going to a conference: we learn, we share what we learn, and we lift each other up. It was really rewarding to see people getting out of their comfort zone to tweet, blog, sketchnote, and plot to give their very first talk. This is how we build a community.

Watch the keynote

Thursday, March 16, 2017

Lint stuck after upgrading gradle plugin to 2.3.0

app:lint hangs after I upgraded the gradle plugin to 2.3.0.

Unexpected failure during lint analysis (this is a bug in lint or one of the libraries it depends on)

It complains about ProblemReporter.isClassPathCorrect(ProblemReporter.java:4761) and other places in ProblemReporter, but I was not able to pinpoint the problem.

Turns out this is caused by libraries that uses old lint APIs, in my case Timber and Butterknife. Once I updated those dependencies, lint finishes.

Thanks Josh Burton for sharing his solution with me!

Monday, February 13, 2017

Constraint Layout beta5 lint error

Constraint Layout beta 5 is the release candidate, and added a lint to deprecate older versions.

The easiest way to get rid of the lint error is to press Alt-Enter and choose the first option to upgrade.

However, I encountered a bug, which forces me to stay with beta4 until the next version comes out with the fix. I still want to get rid of the lint error so my continuous build does not fail. I didn't want to change lintOptions abortOnError to false in build.gradle because I still want my build to catch other fatal lint errors.

I tried to get Android Studio to fix this lint error for me by choosing Disable inspection from Alt-Enter. Alas, that only changed the local settings. Turns out that I need to go to Settings → Editor → Inspections to undo that.

The option I wanted is Suppress: Add tools:ignore="MissingConstraints" attribute, which modifies the xml for me to add the appropriate lint suppression.

<android.support.constraint.ConstraintLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  tools:ignore="MissingConstraints">
<!-- Cannot upgrade to beta5 due to http://b.android.com/233863 -->

Finally, I added a comment to remind me why I suppress the lint error.

More info: Suppress Lint Warnings.

Monday, January 16, 2017

Java compatibility in build.gradle

I got an email from Google asking me to update Fit Cat for Android Wear 2.0, so I tried to compile that app after I haven't touched it for a few months.

Since Android Studio evolves so quickly, I wasn't exactly surprised when I got an error:

Error converting bytecode to dex:
Cause: Dex cannot parse version 52 byte code.
This is caused by library dependencies that have been
compiled using Java 8 or above.

It asked me to add sourceCompatitbility and targetCompatitbility to Java submodules. What does that mean? After a lot of searching plus trial and error I found the answer.

In your top-level build.gradle, add this:

allprojects {
  tasks.withType(JavaCompile) {
    sourceCompatibility = JavaVersion.VERSION_1_7
    targetCompatibility = JavaVersion.VERSION_1_7
  }
}

Thursday, December 1, 2016

Elite Worship

Yesterday I read an article called In a world..., which talked about the problem of elite worship in the iOS community. I'm an Android developer, but I see the same problems in our community as well.

Here is how I see it:

  • People who tweet, blog, speak and open source are considered elites
  • Elites are held above the rest of the community, making it unwelcome for others

Does being loud make you a better developer?

Or, flipping the question, are people who don't share their work inherently worse? No, of course not. Unfortunately, unseen work is just that: unseen. Without external evidence, there is no way to tell if a developer is good or not, so we assume they are average. Not better, not worse.

I, too, would like to believe that we live in a meritocracy where good work is automatically recognized. But how? How do people know what you are doing if you don't tell them?

This encourages people to run up a hill and yell on top of their voice. And the people who are comfortable doing that are rewarded, are seen as "better".

However, this is not automatically lead to elite worship. Yes, there will always be some people who are more visible in the community. But that does not mean it has to be a small group who are revered above all else.

What you can do

When you see good work, point it out

One problem of elite worship is that we ended up comparing ourselves with people with more Twitter followers, more mentions in the industry newsletter, more conference talks etc and feel defeated. We can counter that by pointing out the good work we see that is not enshrined on the internet.

Here is a concrete thing you can do: When you do a code review, don't just point out the things to fix. Remark on the good parts as well.

When something takes longer than expected, write it down

We need more voices in our community. Blogging is great, because there is no gatekeeper to decide who gets to publish and who doesn't. But there is still one hurdle: What to write about?

Pay attention to what you do day to day. If you spent more time figuring out how to do something than you thought you would, it is worth writing down.

Don't worry about looking stupid because others must know how to do it already. You don't have to push the boundaries of human knowledge. That's PhD theses, not blog posts.

Think of it as notes to your future self, a place to put codes and commands in monospace font so you can come back in 3 months to copy and paste them.

Just because some people share more doesn't mean there is no place for you to do it. Everyone has a different experience, and we want to hear from you.

Speak at local meetups

In the original article, the author laments that there is no diversity at conferences. Always the same faces, always the same topics. As a conference organizer, I can tell you that speaker selection is hard. There were so many people that very much deserved a speaking slot but didn't get one, because we had a very limited number. You can read more about how we try to have a balanced speaker roster at 360|AnDev.

That said, we don't have to let conferences be the only place where technical talks are given. There are numerous meetups happening all over the world on any given week. And they are always, always looking for speakers. Sure, it does not come with the prestige of conference speaking, but does that make them worthless?

If you think the local audience is too small to worth your time, record your talk and post it on the internet. I wrote a guide on how to record your screen and voice with QuickTime. Would love it if someone write one for Open Broadcaster Software (OBS)!

Give talks yourself, and encourage those around you to do it. That is how we get new voices. Don't let the conference speaking circuit dictate who gets to speak and who doesn't.

Sharing != Elite Worship

People are lazy. If we see the same name over and over, we think that person must know something. This is fundamentally what leads to elite worship. We can't change human nature, but we can spread the love. Point out each other's good work, encourage each other to make it visible. Make the elite circle so large that it is no longer elite.

Thursday, October 13, 2016

Dennis Ritchie Dies Again

Yesterday many people on my Twitter timeline sharing an article about Dennis Ritchie's death:

I clicked through to read the article, which was from 2011. Why is this circulating again?

My guess is that some people were retweeting without bothering to read the article, and thought he died recently.

This makes me think of a reaction to a tweet I posted.

I was furious. Why would I post something that I'm not sure about? I even backed it up with a slide. Why are you doubting me?

Took me a while to remember that that's what other people do. Say things even when they are only 60% sure. I look back at my career and cringe to think of all the times when other people were regarded more knowledgeable because they open their mouths even when they are not sure.

This time, I am happy that I checked the details before passing it on.

Saturday, October 8, 2016

Constraint Layout: Icon Label Text

I am making one of those classic layouts: an icon with two lines of text. I would like to use vector drawable for the icon, and scale it according to the text sizes. I want the top edge of the icon to line up with the top edge of the first line of text, and the bottom edge of the icon to line up with the bottom edge of the second line.

How would I do that? With ConstraintLayout!

<ImageView
  android:id="@+id/flower_image"
  android:layout_width="0dp"
  android:layout_height="0dp"
  app:layout_constraintTop_toTopOf="@+id/label"
  app:layout_constraintBottom_toBottomOf="@+id/text"
  app:layout_constraintLeft_toLeftOf="parent"
  app:layout_constraintDimensionRatio="1:1"
  app:srcCompat="@drawable/ic_flower"/>
<TextView
  android:id="@+id/label"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  app:layout_constraintLeft_toRightOf="@+id/image"
  app:layout_constraintTop_toTopOf="parent"
  android:text="@string/flower"
  android:textSize="16sp"/>
<TextView
  android:id="@+id/text"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  app:layout_constraintTop_toBottomOf="@+id/label"
  app:layout_constraintLeft_toLeftOf="@+id/label"
  android:text="@string/jasmine"
  android:textSize="24sp"/>

The width and the height of the ImageView is 0dp. This tells ConstraintLayout to compute them by the constraints. In this case, the height of the ImageView is determined by these constraints:

app:layout_constraintTop_toTopOf="@+id/label"
app:layout_constraintBottom_toBottomOf="@+id/text"

The width is the same as the height.

app:layout_constraintDimensionRatio="1:1"

The rest of the constraints are for positioning.

With that, the image scales up as the text sizes increase. It stays sharp because it is a vector.

Layout Editor

I tried to make this layout with the Layout Editor, but could not figure out how to create the constraint app:layout_constraintTop_toTopOf="@+id/label" for the ImageView. I was hovering my cursor around the top edge but not sure how to drag it to link the two views. So I added up playing with the editor a bit to deduce the XML attributes, and switched to editing the XML directly. I hope to use the layout editor in my next attempt to use Constraint Layout.

Follow-up Twitter discussion:

Read the whole Twitter thread.

Source code

github.com/chiuki/iconlabeltext

Click on either TextView to increase its size. Click on the image to reset.

Friday, September 16, 2016

TransactionTooLargeException crashes on Nougat

I was testing my app on Android Nougat, and it crashed when I try to move from one Activity to another. I saw this in the log: java.lang.RuntimeException: android.os.TransactionTooLargeException: data parcel size 700848 bytes.

Actually, the platform has been printing warning log about this for a while, but let's be honest, who has time to read all the logs? Nougat (API 24) throws TransactionTooLargeExceptions as RuntimeExceptions, so we cannot ignore that any more.

onSaveInstanceState

Turns out I was saving a big list of search results during onSaveInstanceState to persist them over rotation. Time to move that to a Loader!

But what is the limit?

But now I'm curious: What is the limit? I wrote a sample app to find out.

public class MainActivity extends Activity {
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    Intent intent = new Intent(this, AnotherActivity.class);
    startActivity(intent);
  }

  @Override
  protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);

    int length = 1000;
    Uri uri = getIntent().getData();
    if (uri != null) {
      try {
        length = Integer.parseInt(uri.getLastPathSegment());
      } catch (NumberFormatException e) {
      }
    }

    byte[] data = new byte[length];
    outState.putByteArray("data", data);
  }
}

To try different sizes, I start the app like this:

adb shell am start \
  -a android.intent.action.View \
  -n com.sqisland.tutorial.transcation_too_large/.MainActivity \
  -d 700000

This launches MainActivity, which immediately goes to AnotherActivity. When that happens, the system calls onSaveInstanceState, which tries to stash away a byte array of the length specified in the adb command, retrieved by getIntent().getData(). This way, I can try different numbers without recompiling and redeploying the app.

I did a binary search on a Nougat emulator and my Nexus 9. The limit is slightly different, but it hovers around 500000. That is not a small number, but not too hard to exceed if you try to store data rather than state.

Thursday, August 25, 2016

Speaking profile

Your speaking profile showcases your speaking experience. Conference organizers can see where you have spoken at, look at the slides, and watch videos of your talk.

Make one now, even if you are just getting started. You can list the topics you would like to speak about, and then add your talks as you schedule and give them.

Here are 3 places you can host your speaking profile.

Blog page

Most blogging platforms e.g. wordpress, blogger allows you to add pages independent of the blog posts. You can add a speaking page there.

Example: Annyce Davis.

GitHub pages

If you don't have a blog, you can use GitHub pages to host your speaking page.

Example: Margaret Maynard-Reid.

Lanyrd

If you don't want to deal with formatting your page, you can create a profile on lanyrd.com. You will need to find the conference you are speaking at (create it if there is no entry), add a session, and mark yourself as the speaker. It is a bit of a hassle to enter all that structured data, but you get cool stats.

Example: Estelle Weyl.

Further reading

Even more examples: https://github.com/asg-feminati/speakers

Watch my How to Write a Conference Proposal talk where I mentioned how to use speaking profiles to discover conferences.

Friday, August 12, 2016

360|AnDev: Money

360|AnDev is the first time I run a conference. I was raised to be frugal, never spending money that I don't have, but putting on a conference requires exactly that. We have to book the venue, order badges, buy plane tickets for speakers etc, all without knowing if any one will actually buy tickets to the conference. It was nerve-racking.

50 Shades of No

Our first source of income is sponsorship. As a first year conference, we have no track record to show, and it has been difficult to attract sponsors.

We were so grateful that POSSIBLE Mobile and Tack mobile jumped in as sponsors the moment we announced. But after that, we had a long period of nothing. I was cold emailing a lot of companies, getting various versions of no.

  • The classic: No reply.
  • The cliff: Initial interest, but no follow up.
  • The black hole: Ask me to submit to a ticketing system.
  • The clash: "We are already sponsoring a conference in the same city in the same month."
  • The budgeteer: "We have no more budget for this year / month."
  • The freeloader: "We would rather get presence for free through the CFP." (Okay they didn't say that, but that's what happened)

Surprising Yes Stories

I was quite discouraged, to be honest. Fortunately my co-organizer John has put on many conferences before, and knows that everyone procrastinates until the last moment. So I should not give up hope.

And indeed, we got an influx of sponsors in the last month. Some of which are the same people that we have been pinging, and the reminder of "Hey, conference is really soon" kicked them into action.

One sponsor approached us out of nowhere, pretty late. When I talked to them at the conference, they told me that one of their employees saw me at Write/Speak/Code the month before, and the company decided that really want to be a part of our community-focused conference. Wow, I had no idea!

Another sponsor came from counter-solicitation. From time to time I get recruiter emails, and I have been replying with, "No, I don't need a job, but please sponsor my conference to reach out to other Android developers." Most of the time I get "Oh I am just a recruiter I can't make decisions like that", but one company actually followed through and became our sponsor!

I was genuinely surprised. This really reinforces my belief that you should always ask for what you want. You need to give people a chance to say yes!

Attendees

Same as sponsors, attendees are major slackers. I had this exchange with so many of my friends:

Friend: I'm so excited about 360|AnDev!
Me: Yay! You bought your ticket already, right?
Friend: hmm... no.

John told me that they always procrastinate, no matter what you do. I was sitting at the edge of my seat until the day of the conference, not knowing if we were going to break even.

I was promoting the conference as hard as I could, but there was still a lot of people who did not hear about the conference, or did not know until it was too late to arrange travel. Perhaps I have been promoting it within my echo chamber? How can I reach out?

Again?

The conference has come and gone, and yes, we broke even. I went into this knowing that I am not running a conference for the money, but still, the uncertainty was no fun.

Will I run 360|AnDev again next year? Right now I am leaning towards yes. I was so happy to see so many people connecting with each other and lifting each other up. With a stellar first edition, I hope next year it will be easier to get sponsors and sell tickets.

Do you want to be a part of 360|AnDev next year? Sign up to stay in the know!

Saturday, August 6, 2016

360|AnDev: CFP process

One of the reasons why I decided to run 360|AnDev is that I want a inclusive place for Android developers to learn from each other. Inclusivity has many dimensions: identities, financial status, level of experience, to name a few. We want everyone to feel welcome, and we know that the speakers will set a tone for the whole conference, so we were very careful in our CFP process.

Core track

I know from experience that conferences are great to forge connections that help you in your career, but a lot of beginners fear that they do not have enough background to participate. To address that, we dedicated one room one day to cover fundamental topics, to let beginners know that there is something for them.

The rest of the conference has more advanced topics so that we take of experienced developers as well.

Clear, specific guideline

When I reach out and ask people to speak, they often ask, why would anyone listen to me, and what would I talk about? We address those two questions specifically on the Call For Papers page.

Contrary to popular belief, you do not need to be an expert to teach. In fact, for fundamental classes it is often best to hear from someone who has just learned it. They know the pain points, and highlight details which may seem obvious to experts.

After that, we offer some topics to get people started. It is not an exhaustive list, but it gives a flavor of what we are looking for, which is much more useful than, "Everything is good, just submit!"

Cover travel cost

We want everyone to be able to come and speak, regardless of their financial situation. It costs quite a bit extra to cover 2 nights of hotel plus flight for each speaker, but we care about inclusivity enough to do so. This way, people don't shy away from submitting because they are between jobs, they work for themselves, their companies have murky policies about conference reimbursements etc.

Q&A hangout

Even with a detailed CFP page, we know we cannot anticipate all the questions. We hosted a Q&A hangout for potential speakers to chat with us directly. Yes, we answered questions, but the most powerful part about the hangout is to put a human face behind the conference, to have a chance to tell everyone that, yes, we want you. We have a few talks that resulted directly from the hangout.

Anonymous voting

With all that effort, we hope to have a variety of talk proposals from speakers with different background. Next step is to make sure that the selection process preserves that, rather than just pick out the famous people.

Our talk selection has two rounds. In the first round, we removed all personally identifiable information from titles and abstracts, and send them out to members of the Android community for voting. Here is the voting guideline:

  • 5: OMG I'll drop everything to see this talk (Please do not give this score to more than 20 talks).
  • 4: I'd like to see this talk.
  • 3: Neutral. I'll probably see this talk, but skip if there is another talk at the same time.
  • 2: I'd rather be in the hallway than see this talk.
  • 1: Offensive/Too commercial/Inappropriate.
  • 0: Abstain.

In the second round, Dave and I look at proposals from each track, from the highest-scoring one down. For the most part we just take the ones ranked highest by the voters, but sometimes there are multiple proposals on the same topic, and their scores are too close to use as a differentiator.

In that case, we compare the titles and abstracts to see what will be covered. We also look into the speaker to try to get a sense of how well the material will be delivered. This is why this round is no longer anonymous.

Final program

While there are still many ways to improve, we are very proud of what we managed to achieve for the first year of our conference. Here is our final speaker roster:

Friday, July 1, 2016

One year of sketchnoting

I made my first sketchnote at Write/Speak/Code 2015 on the impostor syndrome talk by Neha Batra.

I started with a single black pen, added a gray marker as I experimented with shading.

My friend saw the little gray hearts and suggested that I get the primary colors, which was perfect since I was about to attend Google I/O.

The overwhelmingly positive reaction I got for my sketchnotes gave me the confidence to try drawing as well, which, mind you, I grew up believing that I cannot draw. It was a pleasant surprise to discover the joy of copying and coloring.

When I first wrote about sketchnoting, I said there is no way I can draw portraits. Guess what, I do that now!

At Write/Speak/Code 2016 I sketchnoted for Neha again, and it is really fun to see how much I have progressed in a year.

You can do it too

I have seen many other engineers start sketchnoting since I posted my first sketchnote last year, and it was been absolutely delightful. Wanna get started? Here are some resources:

Saturday, June 25, 2016

Write/Speak/Code: 10x Myself

I am very active in the Android community, blogging and speaking and sharing code, but I can only do so much as one person. To scale my efforts, I mentor others to do the same, which aligns with the goals of Write/Speak/Code exactly.

During Write day last year I shared my conference report blogging formula, I have seen it being adopted widely. Some examples:

For speaking, last year I met fellow Android developers Yash Prabhu and Danielle Vass at Write/Speak/Code, and I am delighted to see them start their speaking careers shortly afterwards.

This year, I was on the writing panel again, and also moderated the conference organizers panel. I hope to inspire many more women to go forth and share their knowledge. Storify:

Besides mentoring, I took the opportunity of being surrounded by amazing women to level up my own career as well. One of my 2016 speaking goals is to give a keynote, and during Write/Speak/Code I brainstormed and refined a topic that I am super excited about: The State of Android Testing.

I'd love to hear your Write/Speak/Code story. Did you get started on writing, speaking or open source because of it? Let me know!

The State of Android Testing

We all know testing is good for you, but it is very overwhelming. What is a unit test? What is an instrumentation test? Espresso, Robolectric, Mockito… what do all these libraries do? More fundamentally, why should I test?

I'd like to give a keynote talk to answer all these questions. Do you know a conference that would be interested? Perhaps Droidcon NYC?

Saturday, June 4, 2016

Coding live stream

I first heard about live streaming when I watched Dina Rodriguez hand lettering on Twitch.

But I wasn't sure what to do in front of a live audience, so I didn't do anything about it until I met Liam Spradlin at Google I/O. He started streaming after watching Dina, and encouraged me to try it, giving me lots of practical tips. There was a lot of code labs announced at Google I/O, so I thought, hey I want to do them anyway, why not live stream too?

Software

OBS, Open Broadcaster Software. Free, available in Windows, Mac and Linux.

Streaming service

restream.io: Stream to many places at the same time. I picked:

Layout

Here is how my desktop looked like during live stream:

My monitor resolution is 2560x1600, and I cropped the Display Capture to 1920x1080 so get the 16:9 aspect ratio. I popped out the chats from the 3 services so I can monitor them, but put them outside of the capture area so my audience won't see them.

I put the emulator outside as well, and declare it as a source in OBS so it is always visible, even when I type in Android Studio. If I want to hide it, I move it down in the list of sources in OBS.

The last source is my webcam. I cropped it to a square.

Here is how it looks like when I stream:

The emulator source is in the top right, and the webcam source is in the bottom right.

Preparation

  • Click "Start Recording" in OBS to see what it captures, and adjust the microphone, webcam etc as needed.
  • Set up the channels in restream.io, and copy the stream key to OBS.
  • For each channel, set up archiving on the site itself e.g. YouTube.
  • Set up OBS with the instructions from livecoding.tv: https://www.livecoding.tv/obs-guide
  • Increase the font size of your browser and IDE.
  • Try out a little bit whatever you plan to do while streaming. I was going to stream from my Linux box, but couldn't get the Android Wear N Preivew emulator going, so I had to switch to my Mac.
  • Advertise multiple times before the live stream, and once again after you have started streaming.

Streaming

Keep an eye out on the chat windows when you stream. Live stream is much less fun without audience interaction! I say my reply out loud, but type links into the chat window so people can click on them.

Results

I trimmed the video to skip the initial part when I'm setting things up and waiting for people to show up.

People seem to like it!

Next

I'll try to stream once a month. I'll be announcing them on Twitter, and you can also subscribe to our YouTube channel to get notified of the recorded videos.