Back to Venmo.Com

QuizTrain: A Swift framework for TestRail's API

· by David Gallagher

QuizTrain: A Swift framework for TestRail's API

At Venmo we love using TestRail to manage and track tests for our mobile and web apps. We wanted a way to integrate it with our automated iOS tests which are written in Swift. TestRail provides an excellent API but no Swift framework to use it. So we decided to build one and open source it under the MIT License so you can use it too!

QuizTrain allows you to do everything you can do with TestRail's API from the comforts of Swift on iOS, macOS, tvOS and watchOS. Acting as a foundation you can integrate it with your Swift testing framework or even build an app on top of it. We've been using it at Venmo since early 2018 and absolutely love it. 😀

How Venmo uses QuizTrain

On iOS we use Apple's User Interface Testing framework to run automation tests. It provides a great way to test Venmo from the perspective of users while remaining within Apple's development ecosystem. TestRail acts as our single source of truth for all test cases and results. Keeping this in mind we leveraged QuizTrain to do the following:

  • As tests run we log rich test case descriptions pulled from TestRail.
  • We track results as pass/fail based on assertion outcomes in tests.
  • When complete we create a test plan and submit results to TestRail.

This was accomplished by building a few objects on top of QuizTrain and extending XCTContext. You can find an example project in the QuizTrain repository containing this code.

  • TestManager.swift
    • Principal Class for our testing bundles.
    • This sets up QuizTrainManager before any tests run.
    • Contains global methods to log, start, and complete testing case IDs.
  • QuizTrainManager.swift
    • Conforms to and is registered for XCTestObservation.
    • Tracks cases being tested.
    • Tracks failed assertions.
    • Marks cases as passed/failed.
    • Handles submitting results to TestRail.
  • QuizTrainProject.swift
    • Stores a copy of our TestRail project in memory.
    • Provides rich descriptions for cases.
  • XCTContextExtensions.swift
    • Extends XCTContext.runActivity() to accept test case IDs to log, start, and complete tests.

The resulting test code is very simple:

class MyTestCase: XCTestCase {
    func testSomething() {
        XCTContext.runActivity(testing: 14539) { activity in
            XCTAssertTrue(true, "It was not true!")
        }
    }
}

That's it! What's happening:

  • testSomething() starts.
  • An activity is created for case ID 14539.
  • A rich description is logged for it.
  • Testing is started for the test case.
  • The activity closure is executed making assertions and completes.
  • Testing is completed for the test case.

If any assertions fail between steps 4 and 6 then the test case ID is marked as failed. Otherwise it passes. Later when results are submitted the failure message is appended to the result description so you can view it on TestRail. If multiple failures occur between steps 4 and 6 then every failure is included in the result description.

Multiple test case IDs can be grouped together and/or nested:

class MyTestCase: XCTestCase {

    func testSomethingElse() {

        XCTContext.runActivity(testing: [13803, 14002, 14016]) { activity in
            XCTAssertFalse(true, "It was not false!")
        }

        XCTContext.runActivity(testing: 13293) { activity in
            XCTAssertTrue(true, "If this fails then 13293 fails.")
            XCTContext.runActivity(testing: [13830, 13044]) { activity in
                XCTAssertTrue(false, "If this fails then 13293, 13830, and 13044 fail.")
            }
        }
    }
}

One rule we implemented is you can only start and complete a test case ID once during the entire test run. Otherwise a fatalError() will occur. Our reasoning for this is:

  • It enforces that our test cases are succinct.
    • If a test case is used more than once it is a sign that we made it too vague and we should break it up into multiple test cases.
  • It is DRY and prevents us from testing the same thing more than once.
  • It avoids the problem of how to deal with conflicting results for a test case.
    • What if it passed, failed, passed, and also had a custom result? How would you merge that into a single result?

You're more than welcome to modify QuizTrainManager.startTesting() if you prefer different behavior.

Have Fun!

We hope you enjoy using QuizTrain with TestRail as much as we have! Check out the QuizTrain readme and example project if you'd like to learn more. Happy testing! 📝🚆

Permalink

Python linting at Venmo

· by Simon Weber, Platform Engineer

Quick! What’s wrong with this (contrived) Python 2 code?

import sys

class NotFoundError(Exception):
   pass

def enforce_presence(key, entries):
   """Raise NotFoundError if key is not in entries."""

   for entry in entries:
       if entry == key:
           break
   else:
       NotFoundError

If you said the unused import and missing raise keyword, you’re right! But, if you took longer than a quarter of a second to answer, sorry: you were outperformed by my linting tools.

Don’t feel bad! Linting is designed to detect these problems more quickly and consistently than a human. There are two ways to make use of it: manually or automatically. The former is flexible but not robust, while the latter risks getting in the way. We lint automatically at Venmo; here’s how we strike a balance between flexibility and enforcement.

We use a collection of linting tools. Currently we use flake8, pylint and a custom internal tool. They each address different needs: flake8 quickly catches simple errors (like the unused import), pylint slowly catches complex errors (like the missing raise), and our internal tool catches errors that are only relevant to Venmo. For easy use from the shell, we combine their output with git-lint and a short script. This setup catches a wide variety of errors and can easily accommodate new linters. Here’s what it looks like when run on the code from this post:

$ ./lint example.py
Linting file: example.py FAILURE
line 1, col 1: [F401]: 'sys' imported but unused
line 15, col 8: Warning: [W0104]: Statement seems to have no effect

Linting happens in three places during our workflow: in-editor, pre-commit, and during builds. The first step varies for each of us since we don’t all use the same editor (though vim with syntastic is a common choice). This is the step with the fastest feedback loop: if you don’t currently use linting, start with this.

The second step is implemented with a git pre-commit hook. It lints all the files about to be committed and aborts the commit if there are problems. Sometimes we opt out of this check - maybe we know about the problems and plan to address them later - by using git’s built in --no-verify flag.

Finally, any errors that survive to a pull request will be caught during build linting on Jenkins. It’s similar to the pre-commit check, but runs on all files that have been changed in the feature branch. However, unlike the pre-commit check, our build script uses GitHub Enterprise’s comparison api to find these files. This eliminates the need to download the repository’s history, allowing us to save bandwidth and disk space with a git shallow clone.

No matter when linting is run, we always operate it at the granularity of an entire file. This is necessary to catch problems such as unused imports or dead code; these aren’t localized to only modified lines. It also means that any file that’s been touched recently is free of problems, so it’s rare that we need to fix problems unrelated to our changes.

All of our configuration is checked into git, pinning our desired checks to a specific version of the codebase. Checks that we want to enable are whitelisted, allowing us to safely update our linters without worrying about accidentally enabling new, unwanted checks.

When enabling a new check, we also fix any existing violations. This avoids chilling effects: we don’t want to discourage small changes through fear of cleaning up lots of linting violations. It also incentivizes automated fixes, which saves engineering time compared to distributed manual editing.

Hopefully, sharing our linting workflow helps save you some time as well!

Permalink

Coming Soon: Use your Fingerprint to unlock your Venmo App

· by Tiem Song, Android Engineer

Today, at Google I/O, Google unveiled Android M Developer Preview, which will include new fingerprint capability for Android devices when M rolls out, and we’ve integrated this new capability into the Venmo app.

Soon, consumers using Venmo on their Android device with a fingerprint sensor will be able to unlock their password protected Venmo app with their fingerprint instead of a PIN.

We’re always looking for ways to make Venmo simple and delightful to use, while keeping our high standards of security. Enabling fingerprint authentication on supported Android devices lets us maintain our security standards, yet reduce the friction of entering a PIN.

We’ll be rolling out the new Android-enabled fingerprint technology in the Venmo app later this year. Stay tuned to try it out!

Permalink

Awesome Venmo API Hacks

· by Cassidy Williams


By Cassidy Williams

Hi friends!

Venmo loves going to hackathons and seeing awesome projects that developers come up with. I recently talked to a few people who made some great ones, and I'm going to tell you about them!

Via

Michigan State students Caitlin McDonald and Erin Hoffman built this project and won the Venmo prize at MHacks V!

Students and families alike love to take road trips across the country. Road trips are a fun way to experience small town America while getting us to our final destinations with minimal expenses. Despite their advantages, however, road trips can involve tedious financial concerns, ranging from finding the cheapest gas along the route to ordering at a drive-thru window with a car full of people. With Via, these issues evaporate to provide a fun, carefree roadtripping experience.

Via provides some helpful roadtripping features while also tracking all of your expenses along the way, allowing for easy reimbursements between roadtrippers.

The team built Via as a mobile web app, using Ruby on Rails and PostgreSQL for the database. The main API used was Venmo (for user login, friend lists, and payments), but they also used the Google Maps API, Google Places API, and the MyGasFeed API. The icons are Twitter emoji, but the rest of the graphics they made themselves.

Take a look at Via on ChallengePost!

Paybble

Purdue students Vipul Nataraj, Drew Ruberson, Josh Foeh, and Zachary Simpson worked on this fun project for the Pebble watch.

Paybble is an application developed for Boilermake Fall 2014 that allows you to pay people on your contact list directly through your Pebble watch. In order to use the service, the user has to have the companion iPhone application installed and allow application access to their Venmo account. Once these prerequisites are complete, the user can then use the Pebble watch to cycle through their contact list and select a contact to pay as well as an amount. After confirmation, the application carries out the transaction and even sends both the payer and the payee notifications via text message. This application is targeted towards people that want to utilize Venmo but are always too lazy to pull out their phones to do it.

Gotta love those lazy piles. <3 data-preserve-html-node="true"

If you want to see more about the project, check it out on ChallengePost

The team also wanted to share their favorite joke with you.
Q: Why do Aliens always choose functional programming languages as their main development languages?
A: Because they’re both stateless.

SiriKit

University of Michigan students Janum Trivedi and Noah Shutty built this project for iPhone, and they won the Venmo prize at PennAppsX!

We love Siri--Apple's sassy voice assistant has delighted us since day one. But why can't Siri make one-time and recurring payments to your friends? Find your backpack for you? Activate your Jambox? Control your automated home? Interface with all your IoT devices?

Though Apple has not released a public API for its voice interface, the team found a workaround that allows third-party apps to grab data from Siri and take actions in response. Importantly, this proceeds without any traffic proxying, data limitations (eg, wifi only), or browser trickery.

Siri, plain and simple. And now limitless.

Check out SiriKit on ChallengePost!

They also shared a funny with us, a quote from Mitch Hedburg: "My fake plants died because I did not pretend to water them."

RideShare

At the recent HackTheDrive hackathon run by BMW in San Francisco, Gregor Engelmann and his team of 3 built an iOS application that explored a way of identifying energy/fuel costs per passenger based on local fuel/energy rates at the destination.

The application utilized data like GPS location and power consumption, as well as sensor readings like car door status and passenger location within the car from the BMW i3 to identify how many people are sharing the fuel costs for a certain distance driven, and how much it would cost to refuel the car based on local service point rates at the driving destination. The Venmo and PayPal APIs were used to process in-app money requests from passengers.

Want to see more?Check out this list!
Want to make your own?Go for it!

Permalink

Thank you, open-source community

· by Ayaka Nonaka


By Ayaka Nonaka

We open-source a lot of things at Venmo, and we also use a lot of open-source libraries. To show some appreciation to all of the open-source maintainers and contributors out there, we thought it might be cool to share a list of open-source libraries and tools that the Venmo iOS team relies on. Thank you everyone out there who has contributed to these projects and other projects out there. Here’s to a great 2015!

  • 1PasswordExtension adds 1Password support to our login. (Psssst... Look out for it in our next release!)
  • AFNetworking is great for all things networking, but we especially like UIImageView+AFNetworking for async image loading.
  • Alcatraz is the package manager that brings XVim, FuzzyAutocomplete, GitGutter, etc. to Xcode. Such a must have.
  • BZGFormViewController is great for simple forms that require validation. We use it in our app for our sign up and edit profile views.
  • BZGMailgunEmailValidation is perfect if you use Mailgun for email validation.
  • BlocksKit because dismissWithClickedButtonIndex:animated: delegate methods are no fun at all. Besides, who “clicks” on an iOS device?
  • Braintree allows our users to pay via Venmo on apps like YPlan.
  • CMPopTipView has been useful when we want to draw attention to a new feature that we added.
  • CocoaPods is how we manage all of our dependencies, including private pods. Can’t wait for their 0.36 release which supports Swift!
  • DAZABTest provides a super simple API to do basic A/B tests.
  • Expecta is a great matcher framework that makes your tests read like English. expect(myTests).toNot.beEmpty()
  • Facebook-iOS-SDK makes it easier our users to sign up and find friends to start using Venmo with.
  • FLEX is built into all of our debug and dogfood builds, and it makes finding and fixing UI bugs so much fun and so much easier.
  • FuzzyAutocomplete because Cocoa API’s is so verbose.

objc initRecurrenceWithFrequency:interval:daysOfTheWeek:daysOfTheMonth:monthsOfTheYear:weeksOfTheYear:daysOfTheYear:setPositions:end: anyone?

  • FXBlurView makes it super easy to have your own blurred views to match iOS 7 and 8’s frosty look.
  • FrameAccessor is perfect for the lazy programmer who would prefer to type view.width = 50 intead of CGRect newFrame = view.frame; newFrame.size.width = 50; view.frame = newFrame;
  • GBDeviceInfo tells us useful things about the device our app is running on so we can optimize a little for older devices, etc.
  • GitGutter shows you what lines were changed, added, and removed right in Xcode’s gutter!
  • Godzippa has been immensely helpful when uploading large amounts of data to our API.
  • iRate because we love hearing back from our users. <3 data-preserve-html-node="true"
  • JTSImageViewController is what you see when you tap on a picture on a friend’s profile. We love the interaction where you can flick the image off the screen.
  • KGStatusBar is used to show “offline mode” in the status bar for Braintree merchants to test out Venmo integration. Super simple to use!
  • KIF makes writing automated UI tests such a fun experience. It looks like magic!
  • libextobjc provides us with things like @weakify and @strongify, and one of our favorites is EXTKeyPathCoding which lets us avoid @"stringlyTyped". For example, [NSSortDescriptor sortDescriptorWithKey:@keypath([Story new], createdDate) ascending:NO] which gets checked at compile time, as opposed to [NSSortDescriptor sortDescriptorWithKey:@"createdDate" ascending:NO] which is prone to typos and harder to refactor.
  • Mantle makes converting JSON reponses to and from objects a breeze.
  • MCDateExtensions adds some nice additions to NSDate that make it a lot more manageable to do date computations, etc.
  • Mixpanel has a really nice dashboard and handles all of our analytics.
  • MMDrawerController is really easy if you want add drawer navigation to your app. We’re looking to bid farewell to our hamburger button in the near future though.
  • MZFormSheetController brings iPad’s UIModalPresentationFormSheet to iPhone.
  • Nocilla is our favorite HTTP stubbing libary because it has such a simple and elegant API.
  • NSURL+QueryDictionary makes it easy to convert URL query params to a dictionary and vice versa.
  • ObjectiveSugar is exactly as it sounds. Add some sugar to your Objective-C!
  • OCMock because dependencies. Though with Swift and its focus on value types, we might be using fewer mocks!
  • oh-my-zsh because all we can say is, “OH MY ZSHELL!”
  • PSTAlertController provides an API similar to iOS 8’s UIAlertController, and it’s backwards compatible with iOS 7.
  • ReactiveCocoa is a different way of thinking about architecture, and we like it. We’re moving more and more towards FRP.
  • Specta allows our specs to read like English and have better structure. it(@"should allow the user to log in", ^{ ... }); instead of testUserShouldBeAbleToLogIn. We think it’s a lot nicer thanReadingABunchOfCamelCasedSentences.
  • SSKeychain provides an elegant abstraction around Apple’s Keychain Services API.
  • SVProgressHUD is basically every spinning progress loader in our app.
  • TOWebViewController is so nice for the few web views that we have in our app, although we’re slowly but surely moving away from them.
  • TTTAttributedLabel appears over and over in our app. Any stylized, tappable looking sections of UILabel’s in our app is probably a TTTAttributedLabel.
  • Underscore.m is one of my personal favorites. Never write a for-loop again.
  • xcpretty makes our Travis CI build output so much cleaner and prettier.
  • XVim I think I’m the only one who thinks this on my team, but it’s impossible to navigate quickly around Xcode without this.

A huge thank you to everyone who contributes to open-source. It makes development so much more collaborative, faster, and fun.

Giving back

Since we use so many open-source libraries, we wanted to give a little back to the community. We hope you find something that you like!

  • DryDock is basically our internal “App Store” for distributing beta builds to the rest of the team.
  • synx reorganizes your Xcode project folder to match your Xcode groups, because Xcode doesn’t already do that for some reason.
  • slather lets you measure test coverage in your iOS projects and optionally hook it into CI.
  • VENCalculatorInputView is the calculator keyboard for the amount field of a payment flow.
  • VENPromotionsManager is what we use for location / time dependent events, like our SXSW promotion last year.
  • VENSeparatorView is the zig-zaggy line that shows up in your payment feed for cash out events, etc.
  • VENTokenField is the Messages.app style recipients field that we use in our payment and invite flows.
  • VENTouchLock is our Touch ID + pin code integration.
  • VENVersionTracker is what we use to auto-update our dogfood versions. We’re looking to move to using HockeyApp’s equivalent though.
  • Venmo-iOS-SDK lets you build apps that integrate Venmo payments really easily.
Permalink

Python Logging Traps

· by Simon Weber

By Simon Weber

Python's logging framework is powerful, but gives you plenty of ways to shoot yourself in the foot. To make matters worse, logging mistakes are subtle and slip through code review easily.

In my time at Venmo, I've seen logging mistakes cause everything from unneeded debugging to application crashes. Here are the most common culprits:

Manual Interpolation

Bad:

logger.info("My data: %s" % some_data)
# or, equivalently
logger.info("My data: {}".format(some_data))

Good:

logger.info("My data: %s", some_data)

This pushes the interpolation off to the logging framework:

  • interpolation overhead is skipped if info level is not enabled
  • encoding problems will not raise an exception (they'll be logged instead)
  • tools like Sentry will be able to aggregate log messages intelligently

Pylint will detect this antipattern as W1201 and W1202.

logger.error(...e) in exception handlers

Bad:

try: ... except FooException as e: logger.error("Uh oh! Error: %s", e)

Good:

try: ... except FooException: logger.exception("Uh oh!") 

Formatting an exception throws away the traceback, which you usually want for debugging. logger.exception is a helper that calls logger.error but also logs the traceback.

Implicitly encoding unicode data

Bad:

checkmark = '√'.decode('utf-8') logger.info("My data: %s", checkmark) 

Good:

logger.info("My data: %r", checkmark) 

Using %s with a unicode string will cause it to be encoded, which will cause an EncodingError unless your default encoding is utf-8. Using %r will format the unicode in \u-escaped repr format instead.

Permalink

Building a Sample App with the Android App Switch SDK

· by Matthew Gotteiner

By Matthew Gotteiner

The Venmo Android App Switch SDK enables anyone to easily add person-to-person payments to an app. After adding the required sample files to your project, all that's left is to add a few input fields and fire off a request. To demonstrate how simple it is to integrate the App Switch SDK, let's walk through a sample app that allows a user to send a Venmo payment to a contact by searching for a name or phone number. Integrating contacts into your app is not a requirement to use our SDK, but it is a common use case so I decided to go over that process here. Download the source code for the complete app here: https://github.com/mgottein/app-switch-demo

This tutorial uses an AutoCompleteTextView widget to search a user's contact list. AutoCompleteTextView is similar to EditText, except that it provides a list of suggestions to the user based on what they are typing and allows the user to click on one to complete their entry.

In order for AutocompleteTextView to know what suggestions to provide to the user, we must provide it a ListAdapter that implements Filterable. The ListAdapter allows the AutocompleteTextView to access your suggestions, and implementing Filterable filters the list by what the user is currently typing. We'll be using the SimpleCursorAdapter ListAdapter.

First, retrieve a user's contact information by adding the read contacts permission to AndroidManifest.xml. If we don't add this permission, we will be prevented from reading contact info. Add this line under the manifest tag:

<uses-permission android:name="android.permission.READ_CONTACTS" />

Contact information in Android is exposed by a ContentProvider, a class that allows applications to access content. The contact ContentProvider allows us to look up the contact information via a SQLite query. The contact information will be inside a Cursor, a class that encapsulates the query results. Since our data is inside a Cursor, we don't have to implement our own ListAdapter from scratch and can instead use a SimpleCursorAdapter which handles much of the adapter boilerplate code for us. We can access the contact ContentProvider by using a ContentResolver. ContentResolver provides a query method that looks like a SQLite query. Let's take a look at its definition:

ContentResolver.query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
  • uri allows the ContentResolver to identify a ContentProvider that will handle this query. We will be using this parameter to address our query to the contacts ContentProvider
  • projection is a list of columns we want the query to return
  • selection is a list of predicates that allow us to filter out unwanted results
  • selectionArgs is a list of arguments to our WHERE clause. Question marks will be replaced with the selection args in the order they appear (first question mark maps to selectionArgs[0], …)
  • sortOrder specifies how the results should be ordered in the cursor

This generates a SQLite query that will look something like this:

SELECT <projection> FROM <uri> WHERE <selection> ORDER BY <sortOrder>`

Making the Projection Statement

There are many columns in the Android Contact entity, but we only need a few of them here. We care about Contacts.DISPLAY_NAME_PRIMARY, Phone.NUMBER, and Data._ID.

We can now set up our projection:

Java private static final String[] PROJECTION = new String[]{ Data._ID, Contacts.DISPLAY_NAME_PRIMARY, Phone.NUMBER };

Making the SQLite Selection Statement

Building SQLite queries in Java can be confusing, so let's walk through this step-by-step. - Check if either Contact.DISPLAY_NAME_PRIMARY or Phone.NUMBER start with the input text. Since the contact name and phone number are strings, we can use the LIKE operator to see if the input text matches.

private final String SELECTION = '(' + Contacts.DISPLAY_NAME_PRIMARY + " LIKE ? OR " + Phone.NUMBER + " LIKE ?) AND " +

- Compare thePhone.TYPEcolumn to thePhone.TYPE_MOBILE` column to make sure we are only looking at mobile phone numbers.

Phone.TYPE + "='" + Phone.TYPE_MOBILE + "' AND " +`
  • Because there are many different types of information associated with a contact, compare the Data.MIME_TYPE column to Phone.CONTENT_ITEM_TYPE using the equality operator to make sure we are dealing with phone number information.
Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'";

Instantiating the Adapter

In order to instantiate the adapter, we need to provide a valid Context, a layout resource for a single list item, and a mapping between columns and view IDs. This mapping allows the SimpleCursorAdapter to automatically display a list item for us with very little code. We can choose to provide a cursor at instantiation, but for our purposes this is unnecessary. We are using a pre-existing layout resource for simplicity.

SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,
    android.R.layout.simple_list_item_2,
    null,
    new String[]{
        Contacts.DISPLAY_NAME_PRIMARY,
        Phone.NUMBER},
    new int[]{
        android.R.id.text1,
        android.R.id.text2
    },
    0
);

Set a FilterQueryProvider so the adapter knows how to get content, given text to filter with. The query is run on a background thread, so we don't have to worry about blocking the main thread.

adapter.setFilterQueryProvider(new FilterQueryProvider() {
    @Override
    public Cursor runQuery(CharSequence constraint) {
        String constraintWithWildcard = constraint + "%";
        return getContentResolver().query(
            Data.CONTENT_URI,
            PROJECTION,
            SELECTION,
            new String[]{
                    constraintWithWildcard,
                    constraintWithWildcard
            },
            Contacts.DISPLAY_NAME_PRIMARY + " DESC"
        );
    }
});

We also need to provide a CursorToStringConverter so the adapter knows how to convert a contact row into a string the AutoCompleteTextView can use to complete a user's entry.

adapter.setCursorToStringConverter(new SimpleCursorAdapter.CursorToStringConverter() {
    @Override
    public CharSequence convertToString(Cursor cursor) {
        int phoneNumberIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
        return cursor.getString(phoneNumberIndex);
    }
});

All that's left is to set the adapter on the AutoCompleteTextView itself:

mRecipient = (AutoCompleteTextView) findViewById(R.id.recipient);
mRecipient.setAdapter(adapter);

Now that we can get contact info, let's see how we can open the Venmo app and pay a contact. Let's walk through a sample method to open Venmo and make a transaction.

private void doTransaction(String recipient, String amount, String note, String txn) {
    try {
        Intent venmoIntent = VenmoLibrary.openVenmoPayment(APP_ID, APP_NAME, recipient, amount, note, txn);
        startActivityForResult(venmoIntent, 1); //1 is the requestCode we are using for Venmo. Feel free to change this to another number.
    } catch (android.content.ActivityNotFoundException e) //Venmo native app not install on device, so let's instead open a mobile web version of Venmo in a WebView
    {
        Intent venmoIntent = new Intent(MyActivity.this, VenmoWebViewActivity.class);
        String venmo_uri = VenmoLibrary.openVenmoPaymentInWebView(APP_ID, APP_NAME, recipient, amount, note, txn);
        venmoIntent.putExtra("url", venmo_uri);
        startActivityForResult(venmoIntent, VENMO_REQUEST_CODE);
    }
}

We are using an Intent, a class Android provides to launch other components, to launch the Venmo app in order to complete a transaction. Note that if the app is not installed, a WebView will be launched that uses the Venmo website to complete the transaction. To get results from the App Switch SDK, we can define onActivityResult in our Activity, like so:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
    switch(requestCode) {
        case 1: { //1 is the requestCode we picked for Venmo earlier when we called startActivityForResult
            if(resultCode == RESULT_OK) {
                String signedrequest = data.getStringExtra("signedrequest");
                if(signedrequest != null) {
                    VenmoResponse response = (new VenmoLibrary()).validateVenmoPaymentResponse(signedrequest, app_secret);
                    if(response.getSuccess().equals("1")) {
                        //Payment successful.  Use data from response object to display a success message
                        String note = response.getNote();
                        String amount = response.getAmount();
                    }
                }
                else {
                    String error_message = data.getStringExtra("error_message");
                    //An error occurred.  Display the error_message to the user.
                }   
}
            else if(resultCode == RESULT_CANCELED) {
                //The user cancelled the payment
            }
        break;
        }
    }
}

And that's it!

Permalink

Migrating Webviews

· by Julian Connor


By Julian Connor

For the last month, the web team has been diligently working on porting our webview code from one repository to another. Through this long and tedious process we've learned a lot about the code we used to write and the code we now write. The striking contrast reminds us that sustained piecemeal progress gives large code bases the opportunity to bloom.

In this blog post, I will go through two valuable lessons we learned:

  • You can't put toothpaste back in the tube.
  • Do one thing at a time.

You can't put toothpaste back in the tube

Imagine you are a developer who is blazing his or her own trail through the unknown; in this case, an unfamiliar repository. Wouldn't you repurpose patterns and conventions in order to complete your task?

Of course you would. All engineers are guilty of copying code every now and then. Despite being efficient, code copying has the potential to propagate anti-patterns throughout your codebase.

Here's an example of how a Backbone Model anti-pattern got out of the tube:

Backbone exposes a get method on its models. This method accesses an object on the model instance and returns the value if found, e.g., model.get('foo'). Unfortunately, it's also possible to access the attributes directly on the model like so model.attributes.foo. Invoking a get method is ideal because it allows for functionality to be tied into accessing model data. E.g., one may need to increment a counter every time a model attribute is accessed.

The pattern of directly accessing the model attributes was used once and began organically propagating itself. Once anti-patterns are out of the tube they become increasingly difficult to subdue as their footprint greatens over time.

How to avoid needing to put toothpaste back in its tube

Define and document a set of interactions for the code base: - How do we run tests? Create builds? Install dependencies? Start the dev server? - Is there a style guide? How about a linting process? - etc...

Additionally, think long and hard about the foundational aspects of your repository: Are we happy with the overhead of adding new files to the repo? (E.g., boilerplate, dependency management, pathing, etc..) Is the code architecture sustainable? I.e., Do we foresee these patterns scaling well?

Foundations dictate the resilience of their burdens.

Only refactor one thing at a time

It's easy to become distracted when interacting with large amounts of legacy code. In the majority of cases, flaws and anti-patterns will emerge, potentially leading to lengthy spirals of refactoring.

Before getting started, it's important to clearly define the goal of the refactoring and stay within its bounds. Two rounds of well defined refactorings can be completed in a much more steadfast manner than one round of wavering changes and improvements.

Conclusion

Code quality is a function of its development environment. Defining a strong safety net, style guides, and best practices will lead to self-curation and the propagation of code that the team loves.

Permalink

Hack Week at Venmo

· by Cassidy Williams

By Cassidy Williams

Every quarter, Venmo does something that I think is pretty darn great: we have Hack Week!

For an entire week, we can work on pretty much anything related to Venmo. Some people work on new Venmo features, some people work with new people, some work on making new apps… it’s a free for all. And it’s awesome.

One of the interesting things that everyone tries is working on support cases. As you can imagine, Venmo has a lot of questions coming in, both about the app and how to do certain tasks! So, everyone who participates in Hack Week spends a half day helping our support team help our users. At first it was a bit daunting, but after a while it was kind of fun working through the problems.

We don’t have to just work on technical projects. Some people work on copy for our website, some mock up new designs, and one of our engineers even threw an improv-teaching event for anyone who wanted to join in! A bunch of us took over a conference room and had a blast playing games and laughing with each other. My favorite game had us all acting out superheroes. I was Batman.

Some really cool projects have come out of Hack Week in the past. Some people have built their own laptop stands, a couple made a street light that reacts to our tests, we’ve had apps that integrate our APIs with another service, and we've had whole new features of Venmo that are now in production (and will be soon!). This time around, I built a Venmo Snapchat dashboard with Django that I’m pretty proud of.

So, what are the prizes for these fabulous projects? Well, because we’re classy folk who love to eat, the best overall hack gets a fancy dinner with a Venmo employee. For the other prizes, the hackers get to choose snacks for the office (which is a pretty big deal, trust me).

Honestly though, everyone’s a winner at Hack Week. Our employees get to work on projects they don’t normally get to try, and they work with people they don’t normally get to work with. Plus our users get some cool features that they wouldn’t normally see until later. Boo yah.

Permalink

Data Driven Design

· by Annie Corbett

A case study on how Venmo uses Looker to make product and design decisions

Venmo’s engineers and designers are constantly tweaking and upgrading the Venmo app. They are always working on new designs and new features to make paying friends more enjoyable, intuitive, and engaging. As our user base grows, so does the amount and variety of data we have access to, which we can use to inform how we improve the product.

We recently started using Looker at Venmo, and this has made it much easier for PMs, engineers, and designers to leverage this data and make informed product decisions.

The engineering team’s first use of Looker occurred during a recent app release and design change.

Up until recently, the compose screen on the venmo iOS app had the design seen below. A user would enter her friend's name, payment amount, and payment description, and then would select whether she wanted to pay or charge.

Once the user selected pay or charge, they were taken to a confirmation screen to send payment or send charge. This binary option forced a user to choose and confirm their action.

pic

On June 4, 2014, Venmo released iOS version 6.0. In this release, the design and product team decided to eliminate the binary option, and each Venmo transaction defaulted to pay. Before hitting send, the user could toggle back and forth at the top of the screen to choose between pay or charge.

pic

Venmo’s support team closely monitors cases from our users to see the types of issues they are having. When the support team notices an influx in a certain category of case, or a new, unique problem that starts to arise, they reach out to the Venmo product team to investigate.

In the case of the updated iOS release, v6.0, the support team saw a sudden influx in users writing in, asking to reverse their payments because they had accidentally paid when they meant to charge.

pic

In the Venmo feed, we were also seeing that users were paying their friends, then realizing their mistakes and charging their friends for double the initial amount. This person actually made the mistake three times in a row…

pic

The support team notified the product team to investigate the problem. It was clear some users were accidentally paying instead of charging, but it wasn't clear how widespread the problem was and whether it was worth prioritizing a fix.

The product team then reached out to the data team, to do deeper analysis into the problem and see how many users were actually making the mistake. Initially, the data team did not use Looker; whenever we were asked for data, we would write a custom script, print out a bunch of data to excel, do a bunch of manual calculations, and then repeat this process whenever the product team wanted to extend the timeframe.

The data team decided to build this analysis using Looker, our new business intelligence tool. Looker’s browser-based platform makes it easy for us to discover what’s going on in our business and how people are using our product. So using Looker, we created a table with custom dimensions and measures to identify these payments with just one boolean flag. We tracked these errors in payments by flagging users that make a payment and then charge the same user two times the original amount, within two days of the initial payment (a common behavior we noticed for users who made the pay/charge mistake).

pic

We first looked at the percentage of charges that are mixups across payment mediums (iOS, android, and web). We found that when version 6.0 was released, the percentage of mistaken charges on iOS increased from less than .5% to over 6%, which suggested that the iOS v6.0 release was somehow to blame.

pic

x-axis shows the day the charge was made, y-axis shows #of charge mistakes/# of charges made on that day

So, we dug a little deeper and looked at the different app versions used in charge mixups, pre version 6.0 vs. version 6.0. Users that didn’t upgrade to version 6.0 stayed constant; however, users that upgraded saw a surge in charge mixups.

pic

After reviewing the data with the engineering and design teams, we knew that version 6.0 was causing the problem and that we had to implement a solution. On July 21, 2014, the product team released version 6.2 for iOS, reintroducing the binary payment option, with the pay and request buttons at the bottom of the payment screen.

pic

Since releasing version 6.2, we have been monitoring the pay/charge mixups across app versions; pre version 6, version 6.0 - 6.1, and version 6.2. While mistakes are not back to the pre-version 6.0 numbers, updating the pay/charge buttons decreased errors by more than half.

pic

As of August 8th, 43% of iOS users had upgraded to v6.2, and our support team has continued to see a decrease in payment/charge confusion cases as the new version’s adoption increases.

Looker made this analysis much easier for the data, product, and engineering teams. Once the product and engineering teams sent the original data request, everything they needed was easily accessible in their customized Looker dashboard, giving them all the data they needed right at their fingertips.

We're super excited to continue using Looker to help us make data-driven product decisions at Venmo.

Permalink

A Weekend at BattleHack Boston

· by Cassidy Williams

By Cassidy Williams

Hello!

So, this weekend was my first big event during my time at Venmo: BattleHack Boston.

Now, I've done a lot of hackathons, on the participating, planning, and sponsoring side.

This hackathon beat almost every single one. The PayPal/Braintree team that put it together (and lovingly allowed me to join them) was so organized and well-prepared, I can't say anything negative about the event!

It all started with the set up the night before.

There was TONS of swag.

It felt like the swag and props were never ending. Which is a good thing.

When I first heard the term, "BattleHack," I admit I was afraid it'd be a little cheesy. But this was far from it. This hackathon was epic. Even just from prep day, I could tell that it was going to be a really smooth, impactful event.

So, on the day of the event, we all got to our stations early. I was in charge of the swag table. For those of you who know me well, you know just how perfect that position was for me. Few people really appreciate good swag. I thrive on it.

From the beginning, we were loaded up with absolutely delicious food. It was actually shocking how well they fed us. We started with bagels (with a wide variety of toppings) on the first day, and throughout the event we had a waffle bar, a grilled cheese bar, lobster rolls, clam chowder, Italian food, Asian cuisine, candy, beer, pop, juices and teas, coffee... I could actually make a whole post about the food, but we have more important things to discuss. But seriously. Well done on the food, BattleHack team.

Before we kicked off the event, Matt Hamilton (also a Venmo rep) and I struck a pose. Because you simply couldn't resist those costumes.

The room got crowded fast. This hackathon was geared towards anyone 18 or older, so we had a really wide range of people. The intros to the event were pretty standard, but well done. They talked about the importance of hacking for social good, and the structure of BattleHack (it's a global competition, you can check out their website here).

And of course, we had to talk about the prizes. Throughout the event there would be smaller prizes for Best Progress and for Best Tweet, but the big prizes for hacks consisted of PS4s, cameras, and a chance to win $100,000 after being flown out to California on PayPal/Braintree's dime.

Once people settled down about the awesomeness of the prizes, we got to demos and rules. In order to be eligible for the big prizes, one had to use a PayPal, Braintree, or Venmo API. One could still win partner prizes from the companies Twilio, Mashery, SendGrid, and Context.io if you used their technologies. I had the pleasure of demoing the Venmo iOS SDK.

Once demos were done, it was lunchtime. Everyone was eating and pitching ideas and putting together teams. Hackers had been able to pitch ideas on video before the event started, so some people knew what they were doing, and others were starting completely clean.

Finally, just before 1PM, we had a big countdown to start. We banged the gong, and we were off! Teams quickly started sketching out ideas and setting up their stations.

Over the next few hours, Matt and I were approached several times about using the Venmo API, which was great. The PayPal/Braintree dev evangelists kept thanking us on the side for coming. They said that Venmo has been one of the most popular APIs of the entire BattleHack competition so far, and they loved having us there to help.

Time went on, more food was served throughout the night. The BattleHack team brought in professional masseuses (holy crap, am I right?) and soon Matt's and my shift was over. We were able to leave at about 9, as long as we got back by 4AM. That was one of the things I appreciated about the planning that went into BattleHack; designated shifts aren't always thought of for the staff of hackathons.

After a nearly sleepless night, I got back at 4 and started circling the room looking for the Best Progress award. Teams had been working hard. Some included hardware components, some were trying to use every API available. It was very impressive to see the work being done. Eventually, the team we decided had the Best Progress was FundRunner, an application that assisted those running and those donating to people running in various races for charity. It checked when certain milestones were hit using geolocation, it texted donors when their maximum donation amount was hit, it sent emails... their work so far was pretty darn solid.

Throughout the morning, Matt and I were hit up with Venmo questions. Some were pretty technical, some were simply, "why would I use Venmo over PayPal?" But overall, we were kept busy. Matt and I took notes of flaws on our end and desires on the developers' end for future reference.

Rehearsals were another big part of Sunday morning. Every team practiced their pitches (which were going to be 2 minutes long) and got feedback from the BattleHack team. This is another part of the hackathon that I appreciated and don't often see. People in general, without feedback, aren't successful without an outside perspective.

And finally, after a lip-smacking lunch of lobster rolls and a grilled cheese bar, it was time for presentations. There were some really cool ones, and quite a few using Venmo! A few cool ones where:

  • AgriGate, an "Etsy for farmers" that allowed farmers to post their produce for people to buy, and included a hardware component of a packing slip being printed
  • Street Music is a platform that connects users to street performers to legitimize their profession and allows donation through Venmo and PayPal (they kicked off their presentation by singing, I was impressed)
  • HaveKnow proves your identity for emergency rescue payments when you've lost your ID and/or wallet, and lets you pay people with PayPal/Venmo after they give you cash
  • Honk is a license plate-based messaging app that allows users to send compliments and constructive criticism to drivers (sent in the form of a Venmo charge/payment)
  • FundMatch is a web-based platform dedicated to efficient giving for nonprofits and allows donations through PayPal (the cool part of this one was they took in organization emails and information and parsed them into an easy-to-read form for donors to understand)
  • Pothole Sonar app uses audio to enhance the awareness of mobile users to the dangerous potholes nearby and compiles pothole data
  • Nome (short for "metronome") is a "git for music" where people can collaborate on music projects and donate to other musicians with Venmo

There were a bunch more, and overall the event was so cool. The winners of the event made "Late Night Safety Kit," an app with tools that allows a user to stay safe by sending alerts for crime and to the police station in the area.

And so, as the BattleHack saying goes: City Conquered! I had to run off after the presentations for my train back to NYC. Overall, I genuinely enjoyed my time at BattleHack Boston. The planning team was a well-oiled machine, on top of every single nuance. I loved helping them and being a part of such an impressive event.

Until next time! :)

Permalink

Bind in JavaScript

· by Sarah Ransohoff

By Sarah Ransohoff

The web team here at Venmo works almost entirely in JavaScript. One function we use often is bind. Let's take a look at what's going on here.

Here's a simple example of how you might use bind:

var obj = { foo: function() { console.log(this); this.name = 'baz'; (function() { console.log('inside func'); console.log(this.name); }.bind(this))(); } } obj.foo(); // Object {foo: function} // inside func // baz 

In the example above, bind allows the function inside of foo's outer function to have access to this.name. If we did not bind then this.name would return undefined. And it would do so because this now refers to the global object. No good if we want to be able to work with the same this in a nested function.

So what is going on behind the scenes with bind? What's this sneaky guy doing? Well, bind returns a function with new or added context, optionally adding any additional supplied parameters to the beginning of the arguments collection. Let's take a look at a rewrite below.

Function.prototype.bind = function(ctx) { var fn = this; var args = arguments.slice(1);

return function() { return fn.apply(ctx, args.concat(arguments)); }; }; 

So, let's go through it:

  1. Bind takes a context (ctx).
  2. The function on which bind will be called is this
  3. The arguments (args) passed into the function include everything but the first argument, ctx
  4. bind returns a new function that applies ctx and args to the original fn

This is essentially how bind returns a function that will execute in a given context.

To really hammer it home, let's take a look at an instance where we do not use bind:

$('.gist-author img').click(function() { // my avatar image on gist.github.com :-P
  console.log(this);
  (function() {
    console.log('inside');
    console.log(this);
  })();
});
// if you click that image, you'll get the following...
// <img src="https://avatars1.githubusercontent.com/u/4968408?s=140" width="26" height="26">
// inside
// Window {top: Window, window: Window, location: Location, external: Object, chrome: Object…}

Yikes. If we want to perform a function on the original this -- in this case, img -- we can't. Inside the inner function, this refers to the window because this defaults to window when inside a jQuery function. This is the problem that bind tries to solve: to allow us to be specific with our context.

Awesome. I hope that's helpful. It certainly helps us at Venmo.

Until next time,

Sarah Ransohoff

Permalink

Introducing Background Nearby with iBeacons

· by Dasmer Singh, iOS Engineer

Beacons are game-changing. Ever since Apple extended its developer API to support beacons in iOS 7, articles and blog posts have inundated the web to extol their use-cases in retail. Apple has pioneered this initiative by placing beacons throughout its stores, to notify and educate customers about the products they are standing next to as they walk around.

At Venmo, we were eager to learn more about how beacons work and excited to explore their potential. We wrote and open-sourced VENPromotionsManager, an iOS library that schedules in-app promotions that trigger when a user enters specified regions created by beacons. To experiment, we loaded our offices with Estimote beacons which triggered fun little messages on internal builds of Venmo.

When Apple introduced its iOS 7.1 update, we noticed that they had vastly improved beacon scanning by moving this responsibility from the app-level to the core OS-level. To our surprise, our devices were notifying us of entering a beacon’s region even if Venmo was not running in the background. In addition, our iPhones were detecting these beacons much faster than before (in fewer than 2 seconds on average).

In February, we introduced Venmo Nearby, which utilizes Apple’s MultiPeer Connectivity (MPC) framework to discover nearby users over Bluetooth Low Energy (BLE) and WiFi Bonjour networks. We’ve received more positive feedback and press about Nearby than any other feature we had ever released.

Our users loved Nearby, but one thing prevented the feature from being as useful as we would have liked it to be: both users needed to have the Venmo app open in order to discover one another. This limitation is inherent in Apple’s MPC framework, which only allows devices to broadcast and listen for unique peer identifiers when the app is foregrounded. However, with Apple’s recent enhancements in iOS 7.1, we discovered that we could finally detect nearby Venmo users even when the Venmo app has been terminated and a user's phone is in standby.


How did we do this?

To make this work, if a user opts-in to Nearby, their device not only advertises a unique peer identifier over Apple’s MPC network, but also broadcasts a beacon region with a UUID unique to Venmo whenever the app is open and active. Devices that have Background Nearby enabled are always scanning for this Venmo beacon region, even if they are locked and their screens are off (this scan uses extremely low battery power because it utilizes Bluetooth LE). Whenever a device enters a beacon region, it briefly launches the Venmo app into the foreground in order to broadcast its peer identifier over the MPC framework, thus establishing a Nearby connection. In other words, whenever our users open Venmo to pay or charge the people they are around, they can instantly emit a beacon signal that momentarily wakes up their friends’ devices to connect and populate the user's Nearby drawer. This makes Nearby more powerful and useful than ever before.

We released Background Nearby in our latest update to the Apple App Store and are extremely excited for our users to try it out! At Venmo, we believe that in order to create an extraordinary experience for our users, we need to provide a service that enables them to spend more time cherishing the moments they value with the ones they are with and less time figuring out how to settle the bill. With solutions like Background Nearby, we hope to keep innovating and do just that.

Permalink

Blissful UI programming with ReactiveCocoa

· by Ben Guo


By Ben Guo

We've recently started using ReactiveCocoa in the Venmo iOS app, and we've found that it provides an expressive, unified alternative to patterns like callback blocks, delegate methods, target-action, notifications, and KVO. If you haven't heard of ReactiveCocoa or Functional Reactive Programming (FRP), we recommend starting with this awesome post by Josh Abernathy and the official introduction. In this post, we'll walk through implementing a simple reactive user interface, with and without ReactiveCocoa. Hopefully, we'll inspire you to start experimenting with FRP on your own!

We'll be working on a simple signup form that looks like this:

Let's start with the top of the form, where the user can add or change their profile photo.

// SignupViewController.h // ... @property (weak, nonatomic) IBOutlet UIImageView *imageView; @property (weak, nonatomic) IBOutlet UIButton *photoButton; // ... 

The photoButton's text should be either "Add photo" or "Change photo", depending on whether or not a photo has been added, and the imageView's image should be the currently chosen photo. Here's a reasonable imperative implementation:

(1a) Imperative

// SignupViewController.m

# import "SignupViewController.h"

@interface SignupViewController ()

@property (strong, nonatomic) UIImage *photo;

@end

@implementation SignupViewController

* (void)viewDidLoad { [self.photoButton addTarget:self action:@selector(photoButtonAction) forControlEvents:UIControlEventTouchUpInside]; }
* (void)setPhoto:(UIImage *)photo { _photo = photo; self.imageView.image = photo; if (photo) { [self.photoButton setTitle:@"Change photo" forState:UIControlStateNormal]; } else { [self.photoButton setTitle:@"Add photo" forState:UIControlStateNormal]; } }
* (void)photoButtonAction { UIImagePickerController *imagePicker = [UIImagePickerController new]; imagePicker.delegate = self; [self presentViewController:imagePicker animated:YES completion:nil]; }
* (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { self.photo = [info objectForKey:UIImagePickerControllerOriginalImage]; [self dismissViewControllerAnimated:YES completion:nil]; }


Imperative programming involves describing how to do something. Reactive programming, on the other hand, involves describing what something is, using streams of values. Here's an equivalent implementation, with ReactiveCocoa.

(1b) Reactive

 // SignupViewController.m

# import "SignupViewController.h"

# import


<reactivecocoa reactivecocoa.h=""></reactivecocoa>

# import


<libextobjc extscope.h=""></libextobjc>

@interface EditProfileViewController ()

@property (strong, nonatomic) UIImage *photo;

@end

@implementation SignupViewController

* (void)viewDidLoad { [super viewDidLoad]; [self configureImageView]; [self configurePhotoButton]; }
* (void)configureImageView { RAC(self.imageView, image) = RACObserve(self, photo); }
* (void)configurePhotoButton { @weakify(self); [RACObserve(self, photo) subscribeNext:^(UIImage *image) { @strongify(self); if (image) { [self.photoButton setTitle:@"Change photo" forState:UIControlStateNormal]; return; } [self.photoButton setTitle:@"Add photo" forState:UIControlStateNormal]; }]; [[self.photoButton rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(UIButton *button) { @strongify(self); UIImagePickerController *imagePicker = [UIImagePickerController new]; imagePicker.delegate = self; [self presentViewController:imagePicker animated:YES completion:nil]; }]; }
* (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { self.photo = [info objectForKey:UIImagePickerControllerOriginalImage]; [self dismissViewControllerAnimated:YES completion:nil]; }


@end 

Our reactive code is more linear than our imperative code, but also arguably more difficult to parse. It's hard to see the value of reactive programming at this level of complexity, but as we add more functionality, we'll begin to see the benefits of choosing ReactiveCocoa.

To finish our form, we'll need a username field, a password field, and a submit button. The submit button should only be enabled when we've added a photo and entered a username and password. For some extra reactivity, let's make each text field's text turn orange while editing.

// SignupViewController.h // ... @property (weak, nonatomic) IBOutlet UITextField *usernameTextField; @property (weak, nonatomic) IBOutlet UITextField *passwordTextField; @property (weak, nonatomic) IBOutlet UIButton *submitButton; /// ... 

First, let's try updating our imperative implementation from (1a).

(2a) Imperative

- (void)viewDidLoad {

    // ...
    
    [self.usernameTextField addTarget:self 
                               action:@selector(textFieldDidChange:)
                     forControlEvents:UIControlEventEditingDidBegin | UIControlEventEditingChanged | UIControlEventEditingDidEnd];
    [self.passwordTextField addTarget:self 
                               action:@selector(textFieldDidChange:)
                     forControlEvents:UIControlEventEditingDidBegin | UIControlEventEditingChanged | UIControlEventEditingDidEnd];
    [self updateSubmitButton];

}

* (void)setPhoto:(UIImage *)photo {


// ...

[self updateSubmitButton]; }

// ...

* (void)textFieldDidChange:(UITextField *)sender { [self updateSubmitButton]; [self updateTextFieldColors]; }
* (void)updateSubmitButton { self.submitButton.enabled = self.photo && self.usernameTextField.text.length > 0 && self.passwordTextField.text.length > 0; }
* (void)updateTextFieldColors { self.usernameTextField.textColor = self.usernameTextField.editing ? [UIColor orangeColor] : [UIColor blackColor]; self.passwordTextField.textColor = self.passwordTextField.editing ? [UIColor orangeColor] : [UIColor blackColor]; }

Dealing with state is messy in the imperative world. Our code has become rather difficult to understand — we update the submit button in three different places, setPhoto: has three side effects, and in general, things seem to be happening all over the place. Also, notice that modifying our imperative implementation required touching nearly everything we'd written in (1a). Adding functionality usually means adding new events and states. In the imperative world, we have to respond to discrete events and state changes and make sure everything stays up to date, resulting in less linear, more tightly coupled code that's more difficult to understand and update.

Let's try updating our reactive implementation.

(2b) Reactive

- (void)viewDidLoad {

    // ...
    
    [self configureTextFields];
    [self configureSubmitButton];

}

// ...

* (void)configureTextFields { RAC(self.usernameTextField, textColor) = [RACObserve(self.usernameTextField, editing) map:^UIColor *(NSNumber *editing) { return editing ? [UIColor orangeColor] : [UIColor blackColor]; }];


RAC(self.passwordTextField, textColor) = [RACObserve(self.passwordTextField, editing) map:^UIColor *(NSNumber *editing) { return editing ? [UIColor orangeColor] : [UIColor blackColor]; }]; } * (void)configureSubmitButton { RAC(self.submitButton, enabled) = [RACSignal combineLatest:@[RACObserve(self, photo), self.usernameTextField.rac_textSignal, self.passwordTextField.rac_textSignal] reduce:^NSNumber *(UIImage *photo, NSString *username, NSString *password){ return @(photo && username.length > 0 && password.length > 0); }]; } 

Updating our reactive implementation hardly required any changes to what we wrote in (1b), and the resulting code is much more linear. Because state changes propagate automatically, we can define the flow of state rather than responding to discrete events. Even in this simple example, reactive programming has empowered us to write code that's easier to understand and maintain.

We've only scratched the surface of ReactiveCocoa, but hopefully we've given you a more concrete sense of the power of reactive programming. So go forth, compose signals, minimize state, and put away that spaghetti — let's make lasagna ;)

If you're interested, you can check out the complete example project here.

Permalink

Testing React.js

· by Julian Connor

By Julian Connor

Testing With React

At Venmo, we’ve started using React on our front-end. React is a javascript library for building reactive (dynamic) user interfaces. We use React for our view layer and Backbone for our data layer. Here you can find a blog post by my colleague Thomas Boyt on how we leverage both of these awesome libraries.

Why React?

As our client-side apps grew in size, maintaining and testing our Backbone views became a burden. React ships with JSX, Javascript XML Syntax Transform, which greatly reduces the amount of complexity that large views incur over time by providing a new way to construct your app’s markup. Backbone views rely on templating and selectors for inserting elements into the DOM, while React components are declarative.

If you're looking for more information on why you should consider replacing Backbone.View with React, check out Clay Allsopp's awesome blog post- From Backbone to React.

Here’s an example of how both libraries approach constructing app markup.

// Backbone define(['./view'], function(View) {

var BackboneView = Backbone.View.extend({

    render: function() {
      this.$el.html(_.template($('#skeleton_template').html()));
      this.$('.container').html(new View().render().el);
    
      return this;
    }

});

});

// React define(['./view'], function(View) {

var ReactComponent = React.createClass({

    render: function() {
      return (
        <div className='container'>
          <View />
        </div>
      );
    }

});
return ReactComponent; }); 

At first glance, the difference may seem trivial. But over time your views will gain complexity and a simple Backbone view like the one above may end up manually populating several containers, each with its own markup. The React approach is much easier to reason about and moves the concerns of markup construction into the JSX block.

Testing

Why does this point matter? Well, a test that would have looked like this:

it('renders 3 comments', function() { 
    var comments = new CommentsCollection(commentFixtures); 
    var commentList = new CommentsListView({ collection: comments }).render();
    expect(commentList.$('.comment').length).to.be(3); }); {% endhighlight %}

Now looks like this:

var TU = React.addons.TestUtils;

it('renders 3 comments', function() { 
    var commentList = TU.renderIntoDocument(new CommentsComponent({
        collection: new CommentsCollection(commentFixtures) }));

    var commentList = TU.scryRenderedDOMComponentWithType(commentList,      CommentComponent); expect(commentList.length).to.be(3); }); 

Testing with React allows your tests to be markup agnostic. This means that React is only concerned with whether or not three instances of CommentComponent exist rather than their markup. The example test written in React is much less brittle because it does not rely on the class name .comment. Thus, if someone were to swoop through the codebase and change a bunch of class names and DOM structure, your tests would still make all the proper assertions. This is a massive step towards building a rock-solid app and test suite.

Here’s another example:

var TU = React.addons.TestUtils;

it('renders a FooForm', function() { 
    var app = TU.renderIntoDocument(new App());

// TU.findRenderedComponentWithType will throw an exception if it’s unable to // find any children that have type `FooForm` expect(TU.findRenderedComponentWithType).withArgs(app, FooForm)         .to.throwException(); }); 

This test is amazing. It simply asserts that our App component contains a FooForm component. We don’t care about how FooForm behaves or what it contains (that’s what spec_foo_form.js is for); we simply care about its existence.

Conclusion

We’re huge fans of tests. Having a solid test suite has helped us avoid regressions, sleep better, and cool our conscience. In an ideal world, regardless of what library you use, your Javascript app would be composed of many small, modular, extendable and test-covered units. By allowing us to write markup-agnostic tests, React brings us a step forward in our never-ending quest for Javascript testing nirvana.

Permalink

Testing React.js

· by Julian Connor

At Venmo, we’ve started using React on our front-end. React is a javascript library for building reactive (dynamic) user interfaces. We use React for our view layer and Backbone for our data layer. Here you can find a blog post by my colleague Thomas Boyt on how we leverage both of these awesome libraries.

Why react?

Read the rest of this post at the Venmo engineering blog.

Permalink

VCR.py at Venmo

· by Simon Weber

We've been improving our Python test suite at Venmo. Three months ago, builds were flaky and took 45 minutes; now they’re robust and run in 6 minutes. This is the first in a series of posts about how we achieved this.

Our goal at Venmo is to connect the world and empower people through payments. We interact with a variety of external services to accomplish this, including social networks, credit card processors and identity providers.

Over time, our test suite accumulated unmocked interactions with these services. This slowed down builds and introduced flaky tests. While we occasionally mocked problematic interactions manually, this was error-prone and annoying for test authors. We needed an automatic solution -- something that would let us easily mock old and new tests.

Read the rest of this post at the Venmo engineering blog.

Permalink

DryDock. An open-source internal installer for iOS

· by Chris Maddern

What is DryDock?

DryDock is an open-source internal installer for iOS that enables rapid-deployment of experimental builds to the team and allows (permitted) users to install internal product releases on demand while remaining on a supported internal update track! Huzzah.

You can check it out on GitHub here

Why?

At Venmo, we try to experiment as broadly and continually as we can. As we've gotten better (and faster) at this, we've also had to get better at getting builds in to teammates, users and stakeholders' hands quickly & efficiently.

On average, we're typically working on 4-5 new features at any given time and engineers & stakeholders don't want to wait for the next internal 'release' to get a functional prototype in their hands. (This could be for user testing or just general 'touch-testing'.)

Old Solution

Plug their device in to Xcode and build to it. Simple, but it has a few downsides:

Any device you directly build to is then on an 'unsupported' build without updates. Team members would come to us with issues because they were still stuck on an Xcode-built version of 4.4.0a2 (or something similar) which had a half-baked version of Nearby, for example.

We then have to manage 'UDIDs' in the developer portal as builds aren't release signed.

New Solution


DryDock

An internal installer to rapidly share builds with the team on, be able to easily re-install them if anything goes wrong and where we can get people back on to supported builds. As we built the first version of DryDock, we also realized that this could solve a problem for our support team; being able to install any past version of the app to reproduce issues.

Build Versioning

DryDock works with VENVersionTracker to make sure that users don't get crossed-over between individual experimental builds, but that they get upgraded to later versions of the main internal releases. We do this with a build versioning system..

Assuming a two week sprint which targets a minor-version release, builds will be versioned as follows:

Week 1 Development & Experimental builds: 4.x.0ax
Week 1 Internal releases : 4.x.0a(1-9)

i.e. any internal development and 'experimental builds' of Venmo are bucketed to the 4.x.0ax version, meaning they're isolated from releases on Crashlytics & tracking tools. Meanwhile, any release that's broadly distributed has clear usage & crash reporting.

Week 2 Development & Experimental builds: 4.x.0bx
Week 2 Internal releases : 4.x.0b(1-9)

--- Cut release branch here ---

End of Week 2: 4.x.0rc(1-9) // Bugfixes only at this point

VENVersionTracker will upgrade any 4.x.0ax build to 4.x.0bx or 4.x.0b(1-9) when it becomes available, so we effectively stop orphaned builds from development branches. This gives experimental one-offs a life-span of 'until the next internal release', which is fine.. they should be in that release if they're intended to be long-lived experiments.

We've been using DryDock for a few weeks internally now & love it so we thought we'd open source it so that anybody can easily create an internal installer app.

Built on Parse

DryDock is our first internal tool supported by the Parse backend.

Why Parse? It was the simplest way to get the backend up and running and was an easy way to ensure that whatever we made would easily be able to be used by others. The simplicity of building on Parse is impressive & their client SDK is intuitive to use. They also have SDKs / libraries for a broad array of languages & platforms, so extending this to work on Android or to be updated from a build tool to push from CI would not be too difficult.

Try it out & feel free to extend it

We're sharing this pretty early & have lots of improvements that we want to make; things ranging from automatic updates from build scripts to test-status for each app on a details screen, not to mention access controls to have different groups of users.

If you think of something that you'd like it to do for your team, feel free to fork & extend DryDock and if it's something that seems useful generally we'll merge it and everybody can benefit!

Let us know what you think!

Permalink

Our approach to mobile engineering

· by Chris Maddern

Our approach to mobile engineering

At Venmo, we're in it for the long game. That means that we need a maintainable codebase which is easily extendable and flexible to ever-changing company goals. While our product is social, we're also a finance app and so we have to take a very serious approach to software quality and security. Users feel safe using Venmo because they trust us -- part of this trust is creating a stable & enjoyable experience.

Read More →

Performance Tuning On Android

· by Robert Cheung

Performance Tuning On Android

Earlier this summer, we released a major update to our Android app. It shipped with a revamped UI, a new robust networking layer, and plenty of awesome. Our users loved the new experience and responded with a lot of positive feedback. It was a great release, but we were a little unhappy with how smooth the UI was. Scrolling on the feed seemed choppy, especially when scrolling quickly. 

So let’s talk about UI performance.

Read More →