Our Doximity application has gone through many stages of evolution since the first commit in June of 2010. It began as a small Gemfile consisted of Rails 2.3.5, authlogic, paperclip and will_paginate. No micro-services, no Dockerfiles, no message queues, not even much JavaScript.

As we built richer user interfaces, we started writing more JavaScript using Backbone as the front-end framework. One thing became apparent over the years; JavaScript kept coming up in our retrospectives because it slowed down development. Writing features in Ruby on Rails was considerably faster than Backbone but we didn't want to compromise the flexibility we had with Backbone. It was time for us to reevaluate our front-end options.

Luckily for us, the JavaScript ecosystem has progressed rapidly over these 7 years. But porting 105,000 lines of JavaScript wasn't an easy pill to swallow. Without jumping to rash decisions, we decided to take a week to experiment with the popular frameworks that existed. Our initial choices for this experiment were Ember and React.

The Showdown

A group of four engineers took two weeks to build the initial front-end application in Ember and React. This included boilerplate tools we needed such as authentication and assets, and some commonly accessed pages. Thereafter, we sent an email to all of our engineers to take a week implementing specific features within the Ember and React applications. It took a bit of coordination due to engineers being on separate teams but we managed to make it work by staggering it across 4 weeks. Below is the email that kicked it off:

As per an earlier email I've sent out, we are going to spend a week learning and implementing features in Ember & React. Here are the schedules for when you will be working on it and who you will be pairing with. Due to an uneven number of people, there is one team of 3.

I haven't had a chance to check vacations, if you are on vacation that week please let me know ASAP.

[ Group Assignments ]

What To Do:
1. Join #javascript to ask any questions.
2. Spend 1-2 days reading up on Ember and React. Use the resources provided for
   Ember and React. Pair with your group for any questions or discussions that come
   up around the material. You will be assigned two small stories to implement a
   feature in Ember and React. Do both by pairing with your group and submit it as
   a pull request to the channel. Expect it to be reviewed by other members of the
   team.
3. Make any updates to the README as necessary to help the next group of people
   working on it.
4. Take notes on what you found useful, hard, complicated so when we review it
   weeks from now, you have notes.

If you have questions, reach out to me directly.

The Review

Once everyone finished their implementations, we started sharing the feedback within the team and did a retrospective on this experiment. During the experiment we had two new frameworks that made it into the mix unexpectedly. Angular 2 and Vue were introduced as people had extra time and believed they can also help solve our problems. Needless to say, there were plenty of opinions in the form of 32 lengthy emails, 12 pages of notes and too many Slack messages to count. The decision on our front-end framework boiled down to these five considerations:

  1. The community around the frameworks and how active they were.
  2. Our feature development process at Doximity. We work in two week iterations and allocate resources often towards spiking new prototypes and split testing new ideas. This was easy for us in Ruby on Rails, and we didn't want to lose velocity in this regard.
  3. Ease of implementing features following good design practices without fighting the framework. Ruby on Rails, once again, made this easy.
  4. Coordinating work with our design team and leveraging our Vital CSS framework.
  5. Writing end-to-end tests, which we never found ideal within a Ruby on Rails application.

For the majority of these decisions, React and Vue met most of our needs. We are all big fans of Ruby on Rails, especially for the convention over configuration aspect of it. React often led us into bikeshedding discussions. But with Vue - it just worked. Therefore, we chose to move forward with Vue slowly.

The Vue Forward

So, how were we planning to migrate our front-end features to a Vue SPA? The plan was going to take the better part of a year but we wanted to approach this cautiously. There was no rush. Here’s how we did it:

  1. We knew we had a lot of front-end components that we needed to build or port over from Backbone. Therefore we catalogued the components we had and the ones we would need and began work on these. We weren't implementing any user facing features but simply building the backbone so engineers can focus on building features. We eventually open sourced the project called Genome.
  2. We identified all the required features we needed within the SPA to build our pages - from server side rendering, to deployment strategies, to state hydration and created stories to track them.
  3. Following this, we had two dedicated engineers working on the SPA implementation to ensure the required feature sets were brought into the mix.
  4. Meanwhile, we provided material for other engineers to brush up on ES6 and Vue through online courses and books.

That brings us to where we are now - implementing user facing features with a single MOFO team. Keeping the implementation to a single team will help us continue to polish the SPA while we get our feet wet with Vue.

We could have moved much faster if we wanted to, but there is value in carefully evaluating technologies as they pertain to our business and teams. In this case, we chose to move slower with purpose and not break things.


Even the best interview process can be stressful and drawn-out. That's why Doximity aims to reduce stress and friction while making sure everyone still gets the most out of the interview.

tl;dr

We take a close look at all resumes as they come in. If a resume is a good match for the role, the first step is to schedule a 30-minute intro call. Take a look at our open positions for more info.

This call has a few important purposes. The first is to understand why you'd want to work at Doximity. We also want to make sure our expectations match up, so we’ll chat about salary, start date, and other important details. We’ll give you an overview of our company, discuss things like who we are, what we do, and tech stack. You'll learn more about our clients, products, and our team process. And last but not least, you'll have time to ask questions.

We typically decide on the same day of the screening call if we'd like to move forward. If there's a mutual fit, we’ll add you to our take-home assignment on Github. The assignment is a practical example of what you’d be working on at the job, rather than an abstract puzzle that might not tell us as much. It should take about two to four hours to complete, but there’s no hard limit. We want to see your best work, so we’ll give you time and space to shine.

When you’ve completed the assignment, a few engineers on the team will review it. We qualify the solution based on the following criteria:

  • ability to follow instructions
  • ability to solve the problem with clean and easy to maintain code
  • attention to detail and ability to make good decisions
  • completeness
  • performance considerations
  • test quality and coverage

After the assignment, we’ll decide if we want to move forward within a day. The next step is to schedule two 45-minute technical interviews. These take place onsite or over video conferencing, depending on your location. Nobody likes to answer the same questions over and over, so our interviewers will make sure to cover different topics. In these interviews, we’ll go over things like:

  • work experience
  • accomplishments you’re proud of
  • the take-home assignment
  • how you would solve real-world problems in software

It’s easy to get nervous during an interview and struggle with even a simple live coding session, so we won’t put you through one. You will be asked how you'd tackle technical solutions, and you may choose to use pseudo-code either verbally or on a whiteboard if it facilitates your problem-solving effort. There is no hard requirement to write any code, on the board or otherwise.

The Closer

If the technical interviews go well, we'll schedule a final 30-minute discussion for the following day with the engineering team lead. If you’ve reached this step, we'll likely extend you an offer. So, this is the time we discuss final logistics and answer any more questions you might have.

The last step is to check references and make a verbal offer. If you accept the terms, we’ll present a written offer within 48 hours.

Improving the Process for Everyone

Happily, our engineer hiring process has worked really well. Over the years, the take-home assignment has become fairly fine-tuned. In fact, we extend offers to about 40% of people we interview based on how they completed the assignment. We’ve found it to be a great way to put candidates on the right track and make the process more efficient.

Our method isn’t perfect, but we strive to appreciate and respect everyone’s time. And we’re always trying to make the process even better. We request anonymous feedback from those who have gone through the initial phone call, and we’ve gotten some great responses that help to make the interview process better for everyone.

Hope you enjoyed a peek into our recruiting process. Follow us @dox_engineering if you'd like to be notified about updates to this blog.

Thank you Hannah Frank for the illustrations.

Building software products starts with an idea.

A product idea can go a couple of ways depending on your company’s development culture. The idea could show up in a list of requests sent to someone higher on the food chain who will decide whether it’s a good idea. Or it could be an email to a specific engineer, pleading her to “PLEASE BUILD THIS IDEA”.

At Doximity, we develop ideas differently. We work towards what we call "MOFO" goals.

MOFO? Seriously?

Yes. MOFO is short for My Objectives For Offsite. What did you think it stood for?! A MOFO goal is:

  • Strategic: It should roll up into larger company goals
  • Achievable: A needle that can be moved in 12 weeks time
  • A stretch: No sand bagging here. We shoot for the stars

For example, a MOFO goal could be to launch and sign up 100 people on a new product. Or it could be to increase conversion on our registration funnel. Or it could be the less sexy, yet still important, task of reducing our page load time by 25%.

All MOFO teams set three MOFO goals per quarter to guide development priorities. We’ve found MOFO teams operate best in small, 5-10 person teams responsible for different products. Each team contains a group of engineers, a product manager, a data scientist, a designer and a QA engineer.

So how do we decide which three goals to focus on?

  1. As a team, we collect data, projections and ideas to discuss how these might fit into potential MOFO goals.
  2. Once the team has reviewed and discussed options, the product manager establishes baseline and goal numbers for each finalized MOFO.
  3. The leadership team reviews how the proposed MOFO goals align with company goals. Some ideas die here, and that can be a good thing.

Iterate / Implement / Iterate

MOFO teams work throughout the quarter in two-week iteration cycles. Our goals shape and prioritize the features in each iteration. While some traditional scrum roles emerge, the size of our teams encourages us to look beyond our functional specialties. That means the whole team has ownership and visibility into all aspects of development. For example:

  • Designers present on the potential variations they’re considering and get team feedback on which to use.
  • Data scientists share insights into the different models they’re testing and take suggestions on future model tweaks.
  • Engineers review and suggest product flow alternatives to help speed up user interactions or improve experiences.

As the team ships features, we showcase them on the all-hands weekly call with a summary of how the features impact the business or user experience. We also show how these features move us closer to reaching each MOFO goal, providing full transparency on development status.

The MOFO goals keep us focused but provide room for minor strategic shifts and creative solutions. Our 2 week roadmap can change based upon learnings from earlier tests.

The results are in...

At the end of the quarter, we meet at a company-wide offsite to discuss results. Did we meet our goals? How? We typically present on things like:

  • Split tests and variants. What did we test and how can we generalize those results?
  • New features that distinguish our products. How are we staying ahead of the competition?
  • Ways we reached or missed a goal. What if we had done things differently?

Presenting our results to other MOFO teams helps us to cross-pollinate ideas to improve upon the following quarter.

MOFOs allow us to try new ideas, to evaluate them and to decide whether that idea-turned-product is worth pursuing. This keeps us honest; if a product isn’t really working out after 3 months, should we keep trying? If something works, could we refactor our code to make it work with fewer errors? If it’s working well, how could we invest more to make it really shine?

Software development cultures come in different shapes and forms. Building product starts with an idea, but ideas can often falter without a process and cadence to guide them into production. For us, MOFO goals help empower teams to prioritize ideas and shape them into great products.

As we did last year, we'd like to share tools we found useful in 2016. This is by no means a comprehensive list, simply some of the highlights.

Ripgrep

by: Julio Monteiro

In the beginning, there was grep. Then ack, a pure Perl script that made searching faster compared to grep. A few years ago we got The Silver Searcher (ag), a tool built with C namely faster (and "33% sorter") than ack. Finally this year, ripgrep (rg) was launched, built with Rust and until this point the faster command-line utility for searching plain-text data sets around.

Other than being fast, its regular expression engine uses finite automata and guarantees linear time searching. Searching across huge code repositories is fun again. At Doximity, searching across all our private code repositories takes less than a single second. Give it a try, I'm sure you're going to like it.

Giphy Capture

by: Ben Fischer

Giphy Capture is a tool to take your pull requests to the next level. Make a 20 second recording and embed it right into the PR description. This helps reviewers understand the intention of your change faster. If anyone does a git blame in the future and comes back to your pull they'll see with their own eyes that your code was working. Alternatively you can also use LICEcap mentioned next.

LICEcap

by: Jaymes Waters

Licecap is a dead simple gif creator. It records & saves a gif from a selected area of your desktop. It has been an invaluable tool to create quick, simple animations to share with product managers, quality assurance & other developers.

Re:dash

by: Mujtaba Badat

Anyone that spends a lot of time analyzing data knows how much of a pain it is to organize queries, build visualizations, and keep those visualizations fresh. Re:dash does all of that and more by allowing you to write SQL and turn it into shareable dashboards. Key metrics are the compass that guide entire teams in the murky waters of developing new products. By making dashboards easy for everyone, re:Dash helps teams never lose sight of what matters most.

Devdocs.io

by: Marcus Derencenius

DevDocs is a web app that provides documentation for many languages and frameworks. The kicker is that it provides offline support. It is super fast and gets updated frequently.

What tools did you adopt in 2016 that helped you get work done? Follow us @dox_engineering if you'd like to be notified about updates to this blog.

Funneler is a simple gem developed to: group different pages from one or more apps into a cohesive flow.

At Doximity we want to ensure our users get the most out of the medical network they're joining. In order to make that happen, we provide a personalized onboarding experience for each user. Our customization spans the device the user is on (web, mobile web, and our mobile applications) as well as other variations such as taking into account how or when a user is registered. Of course accounting for all these variations is easier said than done.

Funneler provides us the simple tool we need to make that happen:

  1. It groups pages together via a funnel_token parameter
  2. It is light weight - meaning there is very little overhead to modifying a controller to use that parameter when present, or fallback to a default behavior otherwise
  3. The funnel_token is not dependent on any datastore
  4. And thus it can link pages across different applications
  5. It is simply a link, and therefore can easily be used in emails

Let's take a look at how to use funneler. For a moment, pretend your application has two pages you want your user to see /welcome, and /setup before landing at their final destination /home.

Naturally the simple solution would be to setup each controller/action to link to the next page. However, as you know that is brittle, and certainly can't be customized per user without a lot of code. This is exactly what funneler now provides:

funnel = Funneler.build(routes: ['/welcome', '/setup', '/home'])
redirect_to funnel.first_page

This will redirect to a route like /welcome?funnel_token=...... The funnel_token is a JWT token encoded with a few simple pieces of data:

  • routes - the array of routes to funnel a user through
  • current_page_index - the current index into the routes array

On subsequent requests, any controller can read the funnel_token and redirect to the next_page such as:

funnel = Funneler.from_token(token: params[:funnel_token])
redirect_to funnel.next_page

The funnel simply builds a new token which has an updated current_page_index, and returns the route at that index with the new funnel_token in the query string.

Of course this is a simple example with a static set of routes. However it shouldn't be hard to imagine customizing the behavior by dynamically generating the routes given different inputs and parameters. The best part about using funneler is that creates a clear separation between controller behavior, and the business logic determining which pages should be included in the funnel.

Funneler has been open sourced on GitHub - feel free to contribute!

Developer happiness is what brought me to Ruby in the first place. And of all the new compiled languages, Crystal is the only one that shares this value. The syntax and idioms are entirely Ruby inspired.

Although Crystal looks very similar to Ruby, there are big differences between the two. Crystal is statically typed and dispatched. While there are no runtime dynamic features, the compile-time macros solve many of the same problems.

In this session, we’ll take a close look at these differences as well as the similarities, and what Ruby developers can learn from this exciting language.

For more videos, visit our new Videos channel.