Screen Shot 2014-05-12 at 8.24.33 AM

Greetings, and Happy Wednesday! We’re excited to announce that our long-awaited (and oft requested) update to our QuickBooks Online integration has officially arrived. We’ve written about this topic before, but to review, there are plenty of reasons to make the switch once your books are closed for April 2014. The most important reasons include:

  • Discontinued API. Our old integration, and the one you’re using, is on a deprecated QuickBooks API that will discontinue service in the coming weeks.
  • Vendor matching for company card transactions. We’ll match the merchant name on the Expensify transaction to any corresponding Vendors in QuickBooks Online. If none exist, we’ll assign a “Credit Card Misc.” vendor for later mapping, should you desire.
  • Saved export preferences. Our most requested feature, it’s now possible to set your export preference for reimbursable and non-reimbursable transactions.
  • Billable flags export successfully. Now you’re only an export button away from conveniently creating customer invoices in QuickBooks Online.

Exciting indeed! Now that you’re ready to switch, an extra word of caution: Please follow these three simple steps AFTER you’ve successfully processed all reports belonging to the previous accounting period. This will ensure a seamless transition between the old and new connections.

  1. Navigate to the Admin tab and then click on your policy name. Special note: You’ll need to do this for each company policy that connects to QuickBooks Online.
    Screen Shot 2014-05-12 at 9.00.10 AM
  2. In the Connections tab, click the “Disconnect” button to remove your old connection.
    Screen Shot 2014-05-12 at 9.06.46 AM
  3. Once disconnected, you’ll see the option to connect to our new QuickBooks Online integration. If you’d like a step-by-step guide we highly recommend our help page on establishing a successful connection, or as always, don’t hesitate to write help@expensify.com.

And you’re done! If you’d like to see further enhancements to our QuickBooks Online integration, or if you use QuickBooks Online internationally and would like to see tax support added, please write jason@expensify.com. We’d love to hear from you, thanks!

I don’t have an official title at Expensify but on any given day, I work with the financials, recruiting efforts, hiring, onboarding, office management, relocation, etc. My favorite part of the job? Interviewing candidates. I take great pride in overseeing the hiring process at Expensify, ensuring that we grow our team to match the amazing talent we already have on site.

With that said, I wanted to pass along some advice for interviewing. First and foremost, treat interviewing like dating. Whether you are good or bad at dating, mastering a good interview comes with some basic steps.

Introduce yourself

Introduce yourself

1. Introduce yourself: When you meet someone on a blind date (much like interviewing), you introduce yourself, right? You try talk about yourself a little bit to give your date a sense of who you are, what you are passionate about and why you might be interested in them. This allows your potential partner (or company…) the opportunity to see if it is a match. Résumés aren’t helpful for this, providing only a shallow overview of who you are and after a while, all CVs tend to look the same… which is why we ask our application questions. We want to give you the opportunity to introduce yourself, and put your best foot forward.

2. Make sure you actually put your best foot forward. When you meet your date for the first time, you shower right? You try to look presentable. You know that your date doesn’t have that much to judge you on and will be grasping at anything to make an assessment. Just like that first date, interviewing requires a bit of presentation. Take away anything that makes that might be a distraction from your best foot. Distractions can include (but are not limited) to spelling errors in your emails or on your CV or not following directions. Showering typically helps too but is not required.

Be yourself. Always.

Be yourself. Always.

3. Be yourself (don’t hold back). This one is fairly simple for us. We are a laid back, close knit company. We backpack for a month every year as a team, and let me tell you, things get intimate. Keeping that in mind, we want to see who we are going to work with every day. The reality is you spend a crazy amount of your waking hours at work, so its beneficial for you to feel comfortable letting your hair down.

4. Don’t let your nerves get the best of you. Remember we are trying to woo you too (say those last three words 10 times fast). We are as nervous as you are. Interviewing (and dating) is this back and forth of “does he like me? Do I like him?” If you are nervous, we might not be able to tell how much you actually like us.

Are you going to swipe right on Expensify?

Are you going to swipe right on Expensify?

5. Ask good questions. This one is more important than you might think. Whether its for dating or interviewing, we want to know how interested you are in us. The questions you ask are how we gauge that. It’s true, for Expensify at least, we have a ton of information on our site about the company, product, strategy etc. But we strongly believe in Albert Einstein’s saying “The important thing is not to stop questioning. Curiosity has its own reason for existing.”Our site doesn’t provide all the answers. Come on, we know you can think of something to ask us.

You are looking for a match in your job search. Interviewing is taking a chance, trying to find what role is going to fulfill your needs, provide satisfaction on a daily basis and help you grow into who you always hoped you would be.   So are you gonna swipe right, or what?

Expensify, just like all tech companies in the world, fights bugs on a daily basis. Most of them affect an insignificant part of our users (i.e. an app crash when resuming on a specific page). Some of them have an important impact on the main flow (i.e. taking a picture takes 10s longer than usual).

But sometimes, one small line of code will produce a bug that critically affects 100% of our users.

The Bug

Image

On December 18th, Expensify App 4.2.6 was published on the Apple Store after a one-week internal review. 4.2.6 was supposed to fix some medium-level crashes that 4.2.5 introduced. A few minutes later, we got an email from our #1 customer complaining about this new version: the app was crashing when going to the expenses list.

100% of our users couldn’t use the main feature of our app.

For those who already experienced such a thing, you know how bad it is. At this point, it would take at least two days to fix the issue since the App Store’s reviewing process is fairly slow.

We’ve always released our app on the Play Store first, using the custom roll-out feature that allows to progressively add more users in the release pool. When Android reaches 100% of the pool, we release the app on the App Store. As all our apps share the same code, it’s highly unlikely that the app crashes on iOS and not on Android.

We also had a few automated tests for Android & iOS that made sure that the main flows weren’t affected by our changes. And of course, all our versions are released internally so members of the team can test it and report any bug/crash they can find.

And yet, we had released the worst app version in Expensify’s history. It turned out that two of those three crucial barriers weren’t applied correctly. First of all, we didn’t run the automated tests on the very latest version of the code, but on the commit just before. The very last commit looked like this:

typo

This great typo totally passed our reviewing process and got merged into the master branch. To our foolish minds, such a small code change didn’t require launching a 1-hour long test, nor did it require publishing a new internal release. Also, this crash didn’t affect Android because this part of the code was never executed due to inconsistency between platform calls.

We’ve managed somehow to make the app stop crashing with a hack in the API, but the whole resolution time took about a day. Each time we release such a crappy version, we lose the trust of our customers, our image gets deteriorated piece by piece, and at the end of the day the Expensify App appears to be the work of amateurs incapable to create quality products (We’re pretty sure the last one isn’t true).

This can’t happen again

Something to know about the mobile team is that we are only 3 people, one of them being part-time. And yet we manage to support 4 platforms (iOS, Android, BlackBerry, Windows Phone) by having a shared Javascript code and a custom framework (YAPL) that manages platform calls. The app looks exactly the same on all platforms, which allows us to have the same Calabash tests for both Android & iOS.

Expensibuild

Following this “fire”, we’ve decided to drastically improve our release process, starting with the build system. We’ve shifted from manual builds to a complete Jenkins build system called Expensibuild.

expensibuild

Expensibuild runs on a Mac Mini on which are connected two iPhone & Android devices. Everyday it pulls the master branch, lints the Javascript code with jshint, launches the test suite (which currently has about 35 scenarios), and sends an internal TestFlight to everybody in the company and notifies everyone with an email.

testflight_email

This email describes exactly what changed in this release compared to the previous one, so we know what to test. If the tests failed, an alert is sent to the mobile team urging it to fix the bug.

Making people test

coffee_policy

But automated tests are not enough, there are flows that you can’t reproduce accurately with computers and you’ll always need real people to actually test your product before releasing it. However, people are busy and position specific priorities are a formidable force to infringe on.

So to encourage people to use the app we reimburse their afternoon coffee break as long as they used the latest version to expense it. Whenever Expensify’s employees go to the local coffee shop, they just have to SmartScan their receipt to get it reimbursed. We’ve been able to detect multiple bugs that our tests didn’t catch with this little trick.

Improve Bug Catching

We’ve also added a custom crash reporter to all platforms to collect Javascript crashes on our servers. Each crash type creates a Github issue so we can know exactly whether it’s fixed and by whom. Our goal is to fix the top 5 crashes for each release.

mobileportal

Each crash comes along with logs, user identifiers, device identifiers, and so on.

crashes

We’ve also added code to get a snapshot of the screen at the very time when a crash occurs, as well as the position of the last touch perform on the screen and the delay between the touch and the crash. This allows us to know exactly what happened and reproduce the bug easily.

snapshot

Results

The 4.2.7 release was the first to reach 5/5 stars on both the App Store & Play Store during its 2-month lifespan. It was also incredibly stable: only 1,500 crashes over about 3,000,000 sessions. Users were happy, and so were we.

But most of all, implementing those processes has removed the heavy work that we were doing manually: linting, testing, and building. It gave more time for engineers to focus on real things: fix bugs & implement features.

It’s sometimes better to think about what could be improved, what you can delegate to computers or what makes your process not good enough. Having this kind of introspection is essential for a team to enhance its process, but sometimes it takes a fire to remember that.

And, well, if you want to experience the joys of YAPL (our rockstar cross-platform mobile framework) and fire fighting, feel free to send us an email at jobs@expensify.com, we’d love to hear from you!

What do you mean we can't build it?

What do you mean we won’t support that customer?

Note: This is my guest post, originally published in Pando Daily.

Flat management structures are all the rage, and with good reason: innovation is the lifeblood of a startup, and nothing kills innovation like micromanagement. But scaling a flat management structure is harder than it seems. Plenty has already been written about the risks of accidentally creating the stuff of highschool nightmares, but even if you dodge those bullets you’re in for a little discussed treat: full out mutiny of your team.

Granted, if you do consumer or pure-SMB products, you might avoid this fate. The easiest form of innovation is “scratching your own itch”, and so long as you represent your own idealized customer, more sophisticated innovation might not be needed. But if your product is relevant to mid-market and true enterprise customers, then you will inevitably be faced with a very difficult moment that will shake your company to the core: the moment your first customer 10x larger than you expresses serious interest.

Prior to then, management is actually very easy — superfluous even. Everybody just does whatever feels right, and so long as you are disciplined about hiring smart people who work well in teams, “what feels right” is near enough to “what the customer needs” that there’s little reason to try harder. But scaling your product up to address the needs of a significantly larger company requires addressing needs that your team doesn’t have. This means if you want to get that customer, you need to scratch someone else’s itch. And a purely flat structure is notoriously ill-equipped to handle this. In my experience, it goes down like this:

Sales: “OMG I think customer X will actually buy us, but only if we do Y.”

Engineering: “Even though Y isn’t actually that hard, building it means overcomplicating the product and ruining our culture, so no.”

Sales: “…”

Handled poorly, this can lead to a full blown mutiny where your salespeople feel betrayed by your engineers, your engineers feel sold out by sales, and everyone starts drawing hard lines backed up by serious threats. And because the flat management structure has no… structure, the tools at your disposal to quiet the mob are very limited. It’s a pretty horrible experience, all resulting from the grievous sin of successfully creating something of significant value to unexpectedly large customers.

Having gone through the valley of death and come out the other side (multiple times), here are some common patterns I’ve seen that you might look out for:

    1. Your people are awesome, it’s your structure that sucks. It’s hard to remember this when people start raising crazy and irrational objections to each others’ reasonable (or even obvious) concerns. But never forget that flat management is a conscious choice to not create a well defined, widely accepted vision based on a shared set of complex assumptions. Said another way, flat management is about avoiding the need for agreement on a huge range of issues by just accepting (and indeed thriving) on disagreement: when everybody just does what they feel is best, there’s no incentive to really care if anybody else agrees — or a process to achieve it if they did care. Flat management encourages creative disagreement and, in my case at least, mission accomplished.
    2. Mutiny strikes without warning. What makes this whole circumstance especially complicated is it comes like a lightning bolt, out of the blue. Everything is fine and everyone is happy one day, and then suddenly you’re faced with an unexpected but very significant choice: do we do what it takes to get this larger customer, or not? But even though you didn’t ask to make this decision, you’ve got to make it — and no matter which way you go, people will disagree. Vehemently.
    3. There is no such thing as “status quo”. The fact that you are making this decision indicates that a change has already happened. Yesterday taking on a 10x larger customer was just a hypothetical possibility. Today it’s a realistic opportunity. There’s no undoing that change.
    4. If you don’t take the opportunity, your salespeople will hate you. They spend their every waking moment trying to convince someone to use your product, against all odds. And it’s one thing to try and fail. But to succeed and be denied support? Your best people will quit.
    5. If you do take the opportunity, your engineers will hate you. They spend their every waking moment trying to improve the product as best as they can imagine, no matter how grueling, and how difficult. And it’s one thing to struggle building something they believe in and use. But something they don’t believe in and will never use? Your best people will quit.
    6. The longer you delay, the more everyone hates you. Even those who aren’t especially passionate one way or the other (and these are often your best people), they are passionate about working someplace they enjoy — and nothing about a mutiny is fun for anybody, including the mutineers. Your best people will quit.
    7. Once the mutiny has been quelled, it just happens again. Whether you take or pass on this opportunity, more opportunities will come your way (hopefully). And each time you get an opportunity an order of magnitude larger than the ones before, the cycle repeats.

So what to do about it? I wish I knew. We’ve experienced this cycle about three times so far, and I’m anticipating a fourth as we start engaging our first 100K employee accounts. But luckily, each time gets a little easier, because in practice: this is a great problem to have. The fact that you’re facing this is a sign that your team is great and you are on the right track — and when those things are true, the rest sorts itself out.

Granted, it doesn’t always sort out as well as you’d like: no matter how you decide, some people just can’t get on board and will either leave or need to be removed. But if properly managed, your best people will stay and you will leave the chaos a stronger, more talent-dense, and better team than you entered. Great teams step up to any challenge, and that includes adjusting for new realities.

Because at the end of the day, the whole “flat management structure” you thought you had was actually a mirage all along: there was always a power structure, just not one you formally recognized. Use this opportunity to recognize your best and brightest, lean on them to help you make things right, and like bones forming they’ll get stronger the more weight they carry.

It’s not a fast process: you can’t drink Skele-Gro and get a hardened management structure overnight. (And unless your team has the healing powers of Wolverine — or can’t find better jobs — injecting a structure from the outside is a recipe for instant death.) Just be patient and use your position of authority to clear away the smoke, engage your natural leaders to put out the fires, and slowly step back as they slowly step forward. Over time you’ll graduate from “flat management” to becoming an “agile enterprise” organization that can scratch its own itch and address the critical, repeatable needs of ever-larger customers.

It requires patience and resolve. But the earlier you start on a gradual path of controlled evolution, the better prepared you’ll be for sudden, unexpected revolution.

Editor’s note: This is a guest post by David Barrett, Founder and CEO of ExpensifyThe post went through PandoDaily’s usual editorial process. Mr Barrett was not paid for this post.

Here’s a quick look at a few things we’ve done in the past few months to make sure Expensify runs faster than a <insert inappropriate joke here>.

Cache, cache, cache

Before (gray) and after (blue) chart of API Response Times

Before (dashed) and after (solid blue) chart of API response times – from New Relic

The biggest change we’ve made to speed up our API was introducing a global caching layer, aware of the relationships between the data we handle, and capable of prefetching resources in bulk when necessary. This has reduced the read load on our database server by around 25% (!), freeing resources to serve more customers at any time, especially at peak load. The API is used by all of our apps, including expensify.com – so the benefits of this can be perceived across all of our services.

Similarly, all of our clients cache most of the data fetched from the API – but you guessed that didn’t you? You’re smart! So let’s look at a couple non-obvious caching examples, courtesy of our mobile apps.

In-memory File Cache

The app uses a number of JSON files to preserve app state and persist some other non-critical data. These files are accessed frequently, changed frequently, and pretty small – which makes them great candidates for an in-memory caching layer. They’re loaded in memory when first accessed, then read and written in memory, and committed to persistent storage when the app is about to shut down. This greatly outperforms any caching provided by the system.

Gradients!

While profiling the iOS version of our mobile app, we realized drawing the gradients that acted as a background for the buttons was a performance bottleneck – even though that choice was initially made with performance in mind: fewer images to load, so it’s gotta be faster, right? Well, wrong! The initial load time for that tiny PNG is negligible and only happens once – subsequent drawing is fast as can be. Never assume! So we went back to using images for the button backgrounds, which when you think about it, qualifies as “caching” those gradients.

Asset Optimization

We all know that distributing smaller assets is important for web applications, but what about mobile apps? They don’t need to be downloaded so it doesn’t matter, right? Well we profiled that, and as it turns out loading image assets has a significant impact on launch time. Since we weren’t loading any useless images, the only solution was to shrink the ones we had.

See the difference? (trick question)

Trick question: See the difference?

You’d be surprised how much this helps, especially considering it’s extremely easy to do. We ran all of our image assets through optipng, a free and open source lossless PNG optimizer, which shrank them by ~20%, or ~220KB. This has no impact on memory usage and the savings are irrelevant in terms of reducing the total size of the app, but it significantly reduces the time it takes to load those images into memory, making the app launch and load new screens perceivably faster.

Brain hacks!

Sometimes, performance is in the eyes of the beholder. Here are a few examples.

Highlighting UI Controls

When I first started working on our mobile apps, I noticed that something felt a bit slow and clunky when navigating around. This turned out to be caused by a small delay between the time a button was touched and the time where it visually highlighted. The cause of the delay was the simultaneous presence of two gesture recognizers on our pages: the “pan” recognizer for scrolling, and the “tap” recognizer for button presses. The “tap” recognizer would only fire after the “pan” recognizer was sure that the current touch was never going to be a scrolling gesture. Disabling scrolling (where appropriate) resolved the issue. This did nothing to the actual time it takes to navigate between screens, but it surely feels snappier!

Animation

loader

Did you see the new loading animation on expensify.com? That great-looking and infinitely folding/unfolding version of our logo? Things like these have been proven to reduce the perceived duration of waits. Waiting for a task to complete is boring and stressful at the same time, because there’s nothing to reassure you that the task is going to complete successfully. Animation alone plays a big role in relieving the stress, because it visually communicates that progress is being made – even if it isn’t! But I also believe that the playfulness and complexity of the specific animation we chose helps with the boredom part. It’s nice to look at and kind of mesmerizing. Additionally, it takes longer for it to complete (before it repeats) than the classic “spinners” you see everywhere – I even find myself wishing for it to run for a few more seconds at times. But don’t worry – we’re always working to reduce actual wait times too.

Beauty

Did you know that beauty plays a great role in performance? Studies have shown that users are significantly more patient, tolerant and trusting if the product they’re using is beautiful. Slow doesn’t feel so slow, bugs don’t seem so annoying. I’m sure you noticed that our design language has evolved over the last couple years, and in my eyes the results are impressive across all of our services. Now that everything is prettier, it doesn’t only look nicer – it feels nicer (and faster, and better!) as well.

What’s next?

There are many performance oriented projects cooking here - some big, some small, some planned, some in progress. You might read about some of them in this blog soon. And a lot more has been done so far in addition to the few things mentioned above. We’re working hard so that Expensify is always there when you need it, ready to make your expense reports suck less every day.

But with less walls and and more coding.

Our challenges have fewer walls and and more coding, but same idea.

It’s widely repeated that “great people are 100x more productive than average people.”  But while everybody says it, most companies just hire 100x more average people.  At Expensify, we try very, very hard to hold the line and only hire people we think are truly great.  This means that despite ample resources and more than enough work to go around, we hire extremely slowly — and spend an enormous amount of energy doing it.  A lot of that energy is directed toward refining the hiring process itself, with a major recurring topic being: what makes someone great?

Last week we had a long conversation on this within the engineering team, and the main conclusion was — there is nowhere near consensus on this topic.  Strong, conflicting opinions were held across the team.  I don’t know that there was a single tangible item that everybody agreed was a true minimum requirement, or a true showstopper.

Accordingly, so far as our “official hiring policy” goes, we’re still far from having a checklist evaluation of candidates.  For better or worse (and I’d argue “for better”), everybody is evaluated on an individual basis, and pretty much any single attribute is fair game.  However, it seems to me that there are three general themes we use to assess the “minimum viable employee” — whether someone meets the most baseline requirements for us to say yes:

Aspires to Excellence

In our team conversation last week, we reviewed a series of programmer applications to share thoughts on each.  To everybody’s surprise, by far the most discussion was on something that seems so trivial on the surface: grammar, punctuation, and capitalization of the cover letter.  Everybody kept saying “ok, we’ve talked about this enough”, but then everybody kept talking.  It was strange, and we intentionally stopped to meta-discuss why we were so concerned by this.  We tossed around a couple possible explanations for why this seemed so important (to some of us), and like everything, there was no consensus.  But my view is this:

Someone who doesn’t proofread and spellcheck something like a cover letter simply isn’t trying their hardest.  Whether they don’t care enough to try, or don’t try even when they do care — either way, this is someone who isn’t putting in the effort to excel, and that’s not someone we want on the team.

To be clear, this isn’t to say that grammar is the sign of excellence.  It’s only saying that poor grammar signifies a lack of excellence.  Other items can too, including:

  • Being late for a call (even by a few minutes)
  • Being slow or failing to respond to an email
  • Inconsistent indentation and other style
  • Poor variable nomenclature
  • Terse answers to open-ended questions
  • Lack of enthusiasm or curiosity

Note how none of this relates to skill: everybody “knows” how to do all these, and to not do them is a choice.  Because in practice these aren’t individual choices, but one large choice — and this decision to consistently excel in everything under your control is very nearly an innate quality.  Either you do it, or you don’t, and no amount of cajoling is going to change that (at least, not fast enough for our needs).  And for this reason, I’d say any indicators about the candidate’s aspiration to excellence weigh extremely heavily on my go/no-go decision, and for many others on our team.

Knows Enough to Learn Fast

It’s hard to say that this second item is less important as the first, as both are necessary but insufficient: you need to both demonstrate that you aspire to excellence, and have also acquired the basic skills to enable you to achieve it.  As for what exactly those minimal skills are is a subject of intense debate.  Most of the team would generally say we shouldn’t hire anyone with less skills than they had when they joined, and some would even say their own skills are too low a bar.  But from where I sit, I think the minimum set of skills — for a programmer, at least — is something like:

  • Can create something from scratch.  There are a surprising number of pretty good programmers that haven’t ever started a project from scratch, and don’t actually know how.  This means setting up some kind of development environment and getting “Hello world” to successfully run in some relevant language.
  • Doesn’t need a framework.  Don’t get me wrong, the right framework can be a huge accelerant to a project.  But it’s important to avoid becoming overly dependent on any particular framework otherwise you lose objectivity — and use it not because it’s actually right for the problem at hand, but because you simply can’t do anything else.  So knowledge of a framework gets bonus points, but the ability to work outside a framework is a prerequisite.
  • Successfully finishes the challenge.  It sounds obvious, but if we give a programming challenge with an unlimited timeframe, we expect the candidate to deliver a functioning result.  It’s amazing how many people send something that simply doesn’t work.
  • Actually writes their own code.  Additionally, it’s clear that many applicants just copy/paste snippets they found online, without even the decency to hide it by reformatting it into a consistent style.  Certainly, the ability to leverage the internet to help you solve problems is a great skill.  But learning and applying a lesson is different than copying a code snippet without understanding.
  • Reuses code appropriately.  It’s not enough to create a functioning result, it also needs to be done in a way that minimizes redundancy.  This means pulling out shared code into reusable functions, reusing rather than recalculating outputs, etc.  Great people are naturally efficient, making minimal, deliberate actions to achieve their goals.
  • Makes sound layering decisions.  Knowing where to solve a problem is at least as important as knowing how.  The ideal candidate intuitively recognizes those areas that are tightly coupled and should be kept together as a single unit, from those that are loosely coupled and should be isolated through formal interfaces.

And for me, that’s really about it.  I think a fantastic application is one that has a solid, obvious solution, with consistent style, good layering, and appropriate reuse.  A great application doesn’t need to do much.  But what it does, should be done right.  This shows the candidate has a solid, clean foundation on which new skills can be quickly learned.  Because in the fast-changing world of computer programming, how much you can learn is far more important than how much you know.

Knows Little that Needs Unlearning

This last item is at least as important as the first two, and since those were deemed “necessary but insufficient” I’d say the same about this.  Even more important than what you need to learn, is what you need to unlearn.  It’s at least twice as expensive (but probably more like 4x) to unlearn a bad skill than to learn a new skill from scratch.  This is because the cost to learn the skill is the same, but then you need to add the “unlearning cost” — which is probably more expensive than what it took to learn in the first place.  Here are a few hard habits to break for which we’re always on the lookout:

  • Overengineering.  Defensive programming to anticipate and handle a wide range of scenarios can be great.  But it’s easy to go too far, creating custom logic for scenarios that are extremely unlikely in practice, complicating the solution (and often introducing bugs) for the much more common cases.
  • Excessive encapsulation.  Abstraction is a powerful tool for reuse, as well as to create layered decoupling.  But done poorly, “unused reusability” can add such bloated and complicated overhead so as to leave the codebase larger, more fragile and less understandable than before it was “simplified” with abstraction.
  • Premature optimization.  It’s good to be efficient, and to naturally take advantage of low-hanging-fruit performance opportunities where convenient and clear.  But the most important thing to optimize for is code clarity, and that should only be compromised when genuinely necessary.
  • Unnecessary cleverness.  Modern languages have a huge range of esoteric features that enable for enormously powerful and succinct solutions.  But great candidates amaze with simplicity rather than sophistication.

Admittedly, all of those bullets are really just different flavors of the same thing: solving problems that don’t actually exist, while creating new problems in the process.  It’s insidious, as good programmers can imagine a wide range of potential future problems — ranging from performance, to maintainability, to extensibility, and more — and the temptation to solve them all right now can at times be overwhelming.  But we need people with strong impulse control who can remain focused on solving the problems of today, without adding to them unnecessarily.

 

Anyway, I think these are three high level themes we use when evaluating a candidate.  (And if it wasn’t already apparent, note that where you went to school, what degree you have, where you’ve worked, who has referred you — none of that matters, at all, and I think that’s the one thing we all agree on.)  But getting more detailed than that is extremely contentious, and despite how helpful it would be, there really is no such thing as a clear “minimum viable employee” so far as we can tell.

So if you want to impress me, keep the above criteria in mind.  But in all honesty, I’m not the only one (or even the most important one) you want to impress – so view my suggestions above as “necessary but not sufficient” to get the job.

You’ve heard about Expensify’s culture, right?  Well if you have, you surely know about our legendary, annual “Offshore” trips. In short, Expensify works abroad for an entire month together, because why not?!  The purpose and goal being not only an opportunity to see another part of this beautiful world, but also come together as a team and focus on what we are doing, where we are going and most importantly, why.  Last year we went to Croatia and this is what work looked like for a month:

 IMG_1201 IMG_1128

As you can imagine, we’ve missed it terribly and cooked up an incredible idea to ease the longing. Why not take Offshore, onshore?  We live in arguably one of the most beautiful cities in the US, and San Francisco has a plethora of colorful neighborhoods that we could really settle into and enjoy for a day of work outside the office.  Offshore/ Onshore would take place in the North Beach neighborhood (fondly referred to as “Little Italy” and closely associated with the Beat Generation celebs like Kerourac and Ginsberg).

It happened to be a rainy day, but that didn’t stop us!  We explored the best cafes, had the fanciest of caffeinated beverages, and got to know North Beach a tiny bit better than we did before.

IMG_2348 IMG_2345

It wouldn’t be a proper “Offshore” without a proper hoppy brew.  Following a sales meeting, a few of us decided to finish off our workday at the world-renowned, historic Vesuvio Cafe (across the alleyway from the infamous “City Lights Bookstore” and home to the aforementioned Beat celebs).  Nothing tastes better than a frosty beer amongst your coworkers and heroes (beat poets), except perhaps the beer in Croatia!

IMG_20140326_181552 IMG_20140326_180911

The night officially ended with a beautiful Team/Family Dinner.

IMG_2352 (1)

As we brought the day to a close with a round of limoncello shots, we declared Onshore a success and an instant tradition.

Want to get in on our excellent and original traditions? Apply on our Jobs page.