Pages

Wednesday, December 23, 2015

Cross-platform release of react-native-sound

I've added support for Android in the latest release of react-native-sound, a native module to play sound clips in React Native apps. Most features have been ported as shown in the following table:

FeatureiOSAndroid
Load sound from the app bundle
Load sound from other directories
Play sound
Playback completion callback
Pause
Resume
Stop
Release resource
Get duration
Get number of channels
Get/set volume
Get/set pan
Get/set loops
Get/set current time

I think react-native-sound is so far the most feature-rich open-source module for audio playback in React Native apps :)

Thursday, December 3, 2015

Major update of the react-native-sound module

I've published a major update of the react-native-sound native module for iOS. It now enables easy control of sound volume, pan position, loops, playback time, completion callback. It can also load sound files from directories other than the main bundle. To implement these features, I had to make some backward-incompatible changes to the JavaScript API. Please check out the new example and API doc before you upgrade.

Saturday, November 28, 2015

React Native Tip: TouchableOpacity supports multiple children

React Native's TouchableOpacity used to require a single child element. To attach a touch event handler to multiple components, you had to first wrap them inside a container <View>:
// Old way
<TouchableOpacity>
  <View>
    <Image ... />
    <Text>...</Text>
  </View>
</TouchableOpacity>
It wasn't documented anywhere, but one bonus effect of commit 725053a is that TouchableOpacity now has an Animated.View root which supports multiple children. So if you've upgraded to React Native 0.14.0 or higher, you can now get rid of the container view when using TouchableOpacity:
// New way
<TouchableOpacity>
  <Image ... />
  <Text>...</Text>
</TouchableOpacity>
TouchableHighlight and TouchableWithoutFeedback still require a single child as of RN 0.16.0, though I would normally avoid using them anyway — TouchableHighlight often creates undesirable artifacts, and TouchableWithoutFeedback leads to a poor user experience when used alone.

Monday, October 19, 2015

Playing sound in React Native apps

Update: I've made significant improvements to the module. Please refer to the documentation for the latest APIs.


I've open-sourced 'react-native-sound', a native module for playing sound files in React Native apps. It supports preloading and sound mixing with an audio player pool. The module is currently iOS-only, but an Android port is coming soon.

Installation

npm install react-native-sound --save

In XCode, right click Libraries. Click Add Files to "[Your project]". Navigate to node_modules/react-native-sound. Add the file RNSound.xcodeproj. In the project navigator, select your project. Click the build target. Click Build Phases. Expand Link Binary With Libraries. Click the plus button and add libRNSound.a under Workspace.

Usage example

Now you're ready to play sound clips in your React Native app. Just drop sound files in your XCode project and call the following APIs from JavaScript.

var Sound = require('react-native-sound');
Sound.enable(true); // Enable sound
Sound.prepare('tap.aac'); // Preload the sound file 'tap.aac'
Sound.play('tap.aac'); // Play the sound 'tap.aac'

Notes

  • Sound.enable(true) must be called before playing any sound.
  • Sound.prepare(...) preloads a sound file and prepares it for playback. If you do not call Sound.prepare(...) beforehand, Sound.play(...) will still work, but there might be a noticeable delay on the first call.
  • You can make multiple Sound.play(...) calls at the same time. Under the hood, this module uses AVAudioSessionCategoryAmbient to mix sounds.
  • The module wraps AVAudioPlayer which supports aac, aiff, mp3, wav etc. The full list of supported formats can be found at https://developer.apple.com/library/ios/documentation/AudioVideo/Conceptual/MultimediaPG/UsingAudio/UsingAudio.html

Tuesday, September 15, 2015

What I learned from building a React Native app

React Native is Facebook's open-source framework for building native mobile apps using JavaScript. Unlike PhoneGap/Cordova, React Native provides bindings for native UI controls which totally outclass HTML-based hybrid solutions. After playing with the sample app for a while, I decided to jettison my Cordova codebase and rewrite the Circadi app using this new framework. It took me about 96 working hours to finish an MVP, now published on the App Store. My overall experience with React Native is positive. I'm going to give an account of my key findings below for people who're considering to adopt the framework.

Advantages


Developer productivity


React Native enables developers to write native apps in JavaScript with ECMAScript 5/6 features and optional type checking using Flow. This alone is a huge boon to my productivity even if cross-platform code reuse were never promised. Having written Objective-C and Java at my former employer, I much prefer writing apps in a more terse language like JavaScript despite its many foibles.

The interpretive nature of JavaScript also significantly shortens the RN app dev cycle, making it as easy as developing web pages. Reloading a RN app in a second by pressing ⌘+R turns out to be a truly refreshing experience. (You do need to recompile the XCode project when you switch between build targets, link in a new native module, add a resource file, patch an Objective-C implementation, or resolve the occasional red-screen-of-death.)

Another design choice that facilitates quick UI iteration is React Native's flexbox and styling abstraction, modeled after a carefully chosen subset of CSS features. Layout tweaking using the flexbox model rarely gives me any unpleasant surprises, unlike my traumatic experience grappling with Interface Builder's constraint editor.

App performance


React Native app's UI components feel native because they are native controls exposed to JavaScript via a JS/Obj-C bridge. Achieving the same level of look-and-feel in HTML is a sisyphean task — eventually you'll have to either compromise on fidelity or resort to a non-standard UI theme.

React Native borrows the virtual DOM diff idea from React and makes it conceptually simple to write high-performance UI. If you try to repaint a full-screen background 60 times per second, RN will stutter; but for most non-game apps with few moving parts, it's not hard to create a smooth experience.

Caveats


Cross-platform support


Facebook finally unveiled React Native for Android yesterday, almost six months after the iOS release. However, porting my RN app to Android is non-trivial. First of all, some of the UI controls such as SwitchIOS need to be replaced with Android counterparts; some (e.g. ActionSheetIOS) must be scratched and redesigned for the targeting platform. A more pressing issue is porting all of the native libraries my app depends on. I'll end up writing Java extensions or waiting for others to do it.

There's also no obvious way to write Apple Watch apps in RN yet.

Library support


React Native has fewer than 30 built-in components so far, iOS and Android combined. Chances are good that you'll need to find (or write your own) extensions to implement some basic features, for example, accessing SQLite databases or supporting in-app-purchase items. You'll be hurled back to the Dark Ages of app development, so be prepared with some knowledge of Objective-C and Java. Fluency in native code will be useful anyway even if you don't write RN extensions because: (1) React Native's documentation isn't on par with Apple's yet. You'll sometimes need to dive into the .m files to ferret out implementation details. (2) React Native is still a young framework, fraught with bugs on the other side across the JS bridge.

ES6 language support


Although you can use ECMAScript 6 features in your RN app, be aware that when you run react-native bundle --minify for release build, RN transpiles JavaScript into ES5 using Babel before calling UglifyJS2 for minification. However, not all ES6/7 syntax get transformed, and UglifyJS will choke on statements like for (... of ...), yield, etc. This is not technically a RN issue, but it will bite you during the release phase if you go too fancy with ES6 goodies.

Conclusion


I find React Native a good fit for JavaScript programmers to develop decent native apps with mostly standard UI. This fledgling framework has shown great promise to reduce app development cost, posing a real threat to Cordova and Appcelerator's Titanium.

Update: I published a game using React Native.

Wednesday, September 2, 2015

Crowd's reaction to Google's new logo

Shortly after announcing a company restructuring plan, Google unveiled a new logo yesterday. Do people like the sans-serif design or still prefer the classic logo? I set out to ask the question on three popular crowdsourcing platforms: Amazon Mechanical Turk (MT), CrowdFlower (CF), and Google Consumer Survey (GCS). My survey displays the new and the classic logo and asks participants to pick the one they like more. They may optionally write down a line to explain their choice.



Over the past few hours, 874 valid responses have been collected. Across all three platforms, there's a predominance of preference for the classic Google logo.









All GCS participants come from the US while 99% of the CF crowd are from other countries. The demographics of participants on MT are unknown, but 80% of the overall workforce there are US-based according to mturk-tracker.




Although it's optional to provide a reason, many people did opt to write one. Their descriptions of the classic logo are universally positive while reception of the new logo seems mixed.

Common words that describe the two logos:

New logo
cute, clean, fun, playful, friendly, casual, fresh, modern, whimsical, minimalist, bold, childish, juvenile, bland, plain, awkward, boring,
clunky, dull, bubbly, cheap, ugly
Classic logo
sophisticated, professional, recognizable, trustworthy, credible, authentic, elegant, classy, fluid, sleek, pleasing, familiar, stylish, sharp, iconic, attractive, striking, mature, cool

It's probably too early to call Google's new logo a branding failure. The general public's initial negative reaction might be attributed to change aversion. I recognize that, for example, my personal bias against the new logo is not just an aesthetic judgment but also a result of an emotional attachment to the classic Catull font. Many of my Googler friends share the same sentiment, but some of them reported that after a week-long preview period, they hated it less. Maybe the sans-serif new logo will eventually grow on us as the company evolves.

Wednesday, July 22, 2015

New Project: Circadi

As mentioned in Phil Johnson's latest ITWorld story on code golf at Google, I'm now building a free mobile app called Circadi that aims to help people live a more conscious, fulfilling life. I designed Circadi to scratch my own itch, but if you're interested in the quantified-self movement or are using wearable devices to track biometrics, you might want to leave your email at circadi.com to be an early adopter.

Friday, July 10, 2015

Code Golf at Google

Update: Phil Johnson from ITWorld wrote an article on this.


What is code golf

Code golf is a type of programming competition where contestants strive to write the shortest code that solves a specific problem. Solutions are solely ranked by their code size as long as they pass all tests within certain time and space limits. This mostly sedentary recreational activity has nothing to do with swinging clubs on golf links other than the similarity between the two scoring systems, where lower is better.

Excelling at conventional programming competitions (e.g. ACM ICPC, Code Jam, or TopCoder) demands mastery of algorithms and speed of coding. Code golf, however, celebrates a different skill set. Expert golfers exhibit not only algorithmic prowess but also a deep knowledge of arcane language features.


Code golf at Google

During a two-week leave from Google in June 2014, I was reflecting on the convoluted Java frameworks widely adopted at work. Those hefty frameworks brought coding structures and conventions to large engineering teams; meanwhile, they also sucked the fun of programming like a Pastafarian monster slurping all the tomato sauce on a plate of spaghetti.

To bring back the fun while fostering a culture that hails code brevity, I decided to start a 20% project to create an internal code golf platform — a playground for Google engineers to show off wits, a fountain of programming tricks for the studious, and a symbol of defiance against the trend of technical complexity permeating through the company. Later in the development, it occurred to me that the system could also be purposed as a recruiting tool: interviewers would benefit from a growing repertoire of coding questions with high-coverage test cases against which candidates's code can be automatically validated. And that became the ostensible mission statement on the code golf site to justify the business case ;)


Design choices

The site I designed (http://go/codegolf if you're a Googler) differentiates itself in two major aspects from public code golf attractions such as http://codegolf.stackexchange.com/ and http://golf.shinh.org/:

Ease-of-use

Each programming puzzle asks you to write a single function rather than a full program. This eliminates the need to write any boilerplate I/O logic. It's pretty easy to write code directly in the browser which displays instant test results, but if you prefer offline testing, all test cases used by the online judge are conveniently available in JSON.

As of July 2015, the site supports automated testing of code in JavaScript, Go, Python, C++, and Haskell. Depending on the language you choose, the corresponding function signature is automatically formatted for you. Once your solution passes all the tests, it instantly gets ranked on the leaderboard against other entries in the same language category based on the total byte size.

Competitiveness

The site runs a new contest every week. Scores and authors of the top solutions are always shown on the leaderboard, but the source code won't be revealed until the contest is over — at which point, challengers are allowed to submit even shorter code, though that won't affect the finalized ranking. To encourage early submissions, time is used as a tie-breaker. At the end of a contest, everyone who has solved a problem receives a performance score based on their ranking, relative code size, and participation rate of the contest. The very top contestants also get special badges of honor.


Tech stack

The code golf site runs on Google App Engine and Compute Engine. It's a concoction of a frontend server in Go and JavaScript plus a collection of backend sandboxes. The biggest challenge was building those sandboxes to execute untrusted code in a controlled environment. Another tricky part was modeling the data to enable problem writing in a language-agnostic way.


Code golf community at Google

Since its launch in mid-June 2014, the code golf site has garnered a growing number of loyal users. Hundreds of Googlers have participated in the weekly contests. Some of them confessed in private that they had developed an unhealthy addiction that negatively impacted their productivity, to which I remedied by refraining from offering any monetary rewards to code golf winners ;)

Code golf tournaments have covered a diverse range of challenges from deceptively trivial CS101 exercises to number theory riddles. The themes also vary greatly, including tributes to acts of Googliness, travesty of the performance review system, and taunts on unpopular company decisions.

What fascinated me most was the extraordinary quality of winning entries. Sometimes I would run a contest that's identical to one on codegolf.stackexchange.com. The top voted entries on Stack Exchange are just not on par with the best solutions I've witnessed at Google, which exude an elevated level of creativity and craftsmanship rarely found elsewhere. Reading the code can easily trigger a software engineer's imposter syndrome, a profound feeling of humbleness, tinged with a sense of proudness to be working with these talented people.

For example, in real world scenarios, I've never encountered a single use case of division by zero; but at code golf, a former mathematics professor once won a JavaScript challenge by employing an ingenious "m/=0" expression to reduce code size. He later wrote a 1200-word monograph to dissect his winning entry and shed light on previous iterations. From his article, I also learned that in JavaScript, calling Math.min() with zero arguments returns infinity — an interesting tidbit that may never be useful.

I feel obliged to share some outstanding one-liner solutions for a classic programming problem below: Given a list of strings representing a grid of cells ("0"s for dead cells, "1"s for live cells), write a function g() that returns the next iteration following the rules of Conway's Game of Life. For example, given the input ["111", "110", "100"], the expected output is ["101", "001", "110"].

JavaScript (114B)
function g(b,y,e){for(j=s='';q=e&&b[j++]*16+8;s+=q&1)for(x=9;x--;q>>=(10+e[y-x%3+1])[j+x/3|0]);return s||b.map(g)}
Go (118B)
func g(a[]string)(r[]string){for i,p:=range a{r=append(r,"");for j,q:=range p{x:=1/-^i*3;q^=18;for;x/3<3-i/^-len(a);x++{q<<=("0"+a[i+x/3-1]+"0")[j+x%3]%2};r[i]+="01"[q/16&1:][:1]}};return}
Python (123B)
g=lambda a,e=enumerate:[`[+(2<`zip(*a[i+i/~i:i+2])[j+j/~j:j+2]`.count('1')<4+int(c))for j,c in e(x)]`[1::3]for i,x in e(a)]
C++ (138B)
template<class V>V g(V a){V b=a;for(r:b)for(p:r){p^=50;for(R:a)for(P:R)p<<=&R-&a[&r-&b[1]]<3u&3u>&p-&r[&P-&R[1]]&P;p=48+p/16%2;}return b;}
Haskell (104B)
z=zip[2..] f i=drop(i-3).take i g a=[[("0001"++c:"0000")!!mod(read$f i a>>=f j)9|(j,c)<-z r]|(i,r)<-z a]

(If you're a Googler, check out the full contest results and discussions at http://go/codegolf/11)

I was the sole maintainer of the code golf site for a while. Over time, more contributors volunteered to design problems, review tests, write editorials, implement features, and eventually take over the site ownership when I left Google. It's a bittersweet feeling to leave my brainchild to more capable hands. I don't really feel attached to any code I wrote, but the amazing code golf subculture at Google and the friendships developed within the community will always have a special place in my heart.

Saturday, May 23, 2015

Custom Bazel build rules to compile TypeScript

I've written a Skylark module for Bazel to compile TypeScript projects. Source code and example build files are available at https://github.com/zmxv/bazel-custom-rules.

Two new rules are introduced by typescript.bzl: ts_library (to group TypeScript modules) and ts_binary (to compile TypeScript sources into a single JavaScript file). Additional compiler options may be passed to tsc via the optional flags attribute as shown below.

ts_library(
  name = "externs",
  srcs = ["externs.d.ts"],
)

ts_library(
  name = "common",
  srcs = ["common.ts"],
  deps = [":externs"],
)

ts_binary(
  name = "main"
  srcs = ["main.ts"],
  deps = [":common"],
  flags = [
      "--removeComments",
      "--noEmitOnError",
  ],
)

Monday, May 18, 2015

A quick update on WordGap

Nimble Development from Central Oregon has acquired the domain wordgap.com from me to promote their mobile game Word Gap. The game is Windows 8 only, but the developers have started porting it to iOS and Android.

My original anagram search app for English and French word games is still accessible from https://word-gap.appspot.com/.