Delivering award-winning enterprise cloud software to a global customer base, while maintaining an awesome technology stack and team culture is a big challenge! People often ask us how we do it.
Our products use a multi-tenant SaaS architecture to provide applications to end users: React and TypeScript on the front-end; dockerized Java services running in the application tier; MySQL and Redis on the backend; and Python for the tools and automation that tie it all together. Everything is hosted in AWS in multiple sites around the world, giving us global reach.
Internally, our products are structured as REST services which own their own data, with common services for cross-cutting needs such as user authorization and notifications.
Our developers use a mix of Macs, Linux, and Windows; IntelliJ and VS Code are the most heavily used IDEs. We can run any part of the stack locally for development and debugging, in addition to deploying to our engineering cluster. We use Gradle for builds and TeamCity for CI/CD. Automated tests use JUnit, tsUnit, Jest, Jasmine, Selenium, plus a few other tools. It is quick to compile, deploy, and run all automated tests.
‘Dev ownership’ is the primary philosophy for how we work. Large features are prioritized by our products team, but we also have large internal projects driven by our architects. They are broken down into manageable stories and tasks for individual devs to own. Whenever necessary, UX wireframes, acceptance criteria, and customer requests are brought in as well.
Devs are encouraged to know the ‘why’ of a story or task. For example, when adding a new feature, we ask questions like: Who will use it? When will they use it? What are they trying to accomplish? How would they define success? We approach other types of dev work like refactoring, architecture, tooling, and bug fixes the same way.
‘Dev ownership’ isn’t free – sometimes, we need to slow down to ask questions, learn, and debate. But the payoff is immense: better features, better code, and rapid career growth.
During the coding phase, we use a three-layer testing approach: unit tests as the base layer; integration tests as the middle layer, and end-to-end scenario tests as the final layer. We write tests that are fast, self-contained, and clean up after themselves. Sometimes we have to fall back on UI-driven functional tests executed in a Selenium grid.
Design reviews occur on a frequent basis to keep things on track, but also foster discussion and knowledge sharing of best practices. All commits (including tests) are extensively code reviewed before being committed to master, which is deployed to our engineering environment several times per day.
Operating within an agile framework, we typically release to customers every other week, but we have the ability to release daily if necessary. ‘Dev ownership’ extends to the production environment and the tools used to deploy releases, monitor the system, and automate maintenance tasks.
We have multiple full-stack scrum teams, pulling in our colleagues in product management or UX to work with us on projects when necessary. Some devs like to specialize on front-end or back-end while others prefer to be generalists. Our junior teammates receive ample coaching from other engineers to improve their skill sets over time. We make sure that schedules include time for that.
‘Dev ownership’ of one’s own career means always staying challenged! Every dev is encouraged to take on stories and tasks that are almost ‘too hard’ for them – our teams provide great support and safety, so this is the preferred way to deliver value and learn quickly.
We do Hackathons a couple times per year (with cash prizes for innovations that benefit our customers), which last about a week. Many Hackathon projects make it into production as new features, new products, or internal innovations that improve our architecture.
We handle periodic code refactoring by allocating time each sprint (for small things) and scheduling bigger projects into each quarter. Since our company has an engineering mindset, conversations about architecture and refactoring are quick, to the point, and easy.
Although we work hard, our office environment is casual. It can be very quiet or quite loud depending on time of day. Pair programming, spontaneous whiteboard sessions, and even an occasional nerf dart duel are all part of a typical day. Our office in downtown Boulder is conducive to team lunches and happy hours on a regular basis.
We always have room for improvement and we’re constantly evaluating new technologies to add to the stack – but we’re proud to be delivering great products – and we’re having fun doing it!
If all this sounds good to you, we’re hiring like crazy, both in new Boulder, Colorado office and in Bellevue, Washington! Check out our Careers Page.