Jul 19, 2021

9 Best Practices for Cross-Platform Development

Careers Team

The Activity Content team is responsible for showcasing all the great activities and experiences GetYourGuide has in its inventory. The team values effectiveness, accuracy, and inspiration to help travelers book incredible travel experiences.


Elena Koval, senior backend engineer, Felipe Marino, senior iOS engineer, tackled a major challenge of building a complex cross-team feature while performing a tech migration. The pair reveal the processes, learnings, and techniques they used to succeed in this complex project.

As the company grows and more suppliers join our marketplace platform, duplicate activities started to appear on our activities page. This meant users needed to distinguish between similar or identical activities. For example, someone browsing the Louvre Museum would end up seeing the same activities in the Guided Tour category. To avoid this, we decided to aggregate these supplier activities for more clarity.

The Activity Content team cross-collaborated with many other teams to build a new activity details page. This page aggregates availability and simplifies information on how to experience a destination. The success of the project was truly a team effort, and we collaborated with these different stakeholders across the company:

A double-sided challenge

While implementing this feature, one of the biggest complications was that all the business logic was still tightly coupled in the monolith. This limited the feasibility of writing proper automated tests that guaranteed a high level of quality and detecting regressions.

It was necessary to iterate through many different domains to combine all the information and logic needed, which was harder without well-defined services, clear documentation, and expectations. It led to various edge cases, also derived from the fact that the same data was serving non-aggregated activities, which was hard to catch during implementation.

Working in such an environment gives us the ability to be part of the entire product development journey… These ceremonies and processes develop into solid principles on delivering a complex project and stable bugless code.

As a result, despite a successful product release, the first iteration had a few bugs. Many of them were challenging to identify and fix without unwanted side effects when doing changes in the monolith. At the same time, the performance of combining availability from different activities wasn't always optimized and had a good gap for improvement on destinations where many different options surfaced.

From this experience, the team got together to review the project, share thoughts, discuss learning points and write down action items for the next iterations. In the end, their experience in the first iteration became their best lessons, which, combined with a strong team mindset, led to new processes and techniques, which we're going to go through together next.

Here are our 9 best practices for cross-platform development:

  1. Involve your developers in the trade off
  2. Invest time in clear documentation
  3. Have patience for problem solving
  4. Align early on expectations
  5. Write readable and maintainable code
  6. Get validation from peers
  7. Bug bash before going live
  8. Test together
  9. Reframe challenges as learning opportunities

1. Involve your developers in the trade-off

Starting from the second iteration, all developers actively participated in user research sessions, adding feedback and pointing out all pitfalls in the later phases. We are writing software for other people and seeing how customers behave and react, which allows adjusting design based on the traveler's feedback and thinking about the test scenarios further into development.

The advantage of involving developers in the user research sessions was finding a compromise before giving an estimation on a complex task. Often we are in situations where trade-offs are involved, but many users would instead use software with some rough edges today than wait a year for the shiny version. Being a part of the user research and testing enables you to see how the customer uses the product you build and allows you to remember what customers need and want.

2. Invest time in clear documentation

The new version of the virtual activity began with collecting product and technical requirements in a WIKI tech guide. This included all architecture, sequence diagrams, test scenarios, blockers, integration, and defining all events to send to the analytics pipeline, release plan.

Writing documentation is not easy and takes time. Yet, on the other hand, it gives clarity for product persons, developers, and other stakeholders when dealing with the business logic, scope, and architectural decisions around it. Having such documentation also helped teams write better tests, validate peer work, bash bugs, release with confidence, and put up monitors for most critical paths before shipping to real customers.

You might also be interested in: Our engineering principals

3. Have patience for problem solving

As mentioned above, the biggest technical challenge was moving away from our monolith to the new microservice architecture. The first big technical challenge was that we had moved activity page business logic away from "Fishfarm" (pet name for our monolith) to Traveler Aggregator as our new backend service. At this point, we needed to read the code at Fishfarm and define all the rulesets that already existed, then implement them in the new layer. However, the integration of a data source for all activity information we did with a new catalog service was the second biggest challenge. We were the first consumers of the catalog, and it took us almost a quarter to completely migrate the page.

The next challenge was integrating with the new Search service to get VADP option ranking consistent with search and landing pages. The other huge progress has been made on other clients' platforms. The iOS and web apps migrated to use the new Traveler Aggregator service instead of Fishfarm. With all these changes and migration, we built a solid foundation for the virtual activity page.

Foundation for the virtual activity page

4. Align early on expectations

User stories are prepared by product owners based on business requests and OKR goals. Once we understand the business requirements, design and developers can turn them into technical solutions. When the user story is ready to be picked up by the developer, we always do a kick-off to make sure that we:

  • Have a shared understanding of the story and the result
  • Agree on the contract and integration plan between clients and backend
  • Get an answer for all open questions
  • Define blockers
  • Coordinate cross-team requirements
  • Discuss the potential checks that you need to set up after (monitorings, alerts), teaching events) events

Having a kick-off meeting before giving an estimation and starting implementation helped us meet the deadlines and create visibility across platforms.

You might also be interested in: How we deal with legacy code

5. Write readable and maintainable code

While we are working on implementation we always use critical thinking to check if that the code is readable by:

  • Generating our domains from the API specification (Swagger), which gives the advantage of having valid documentation. A well-specified contract can help eliminate misunderstandings
  • Avoiding big pull requests and don’t get approval without tests
  • Surfacing information regarding test coverage during pull requests — to empower and hold the team accountable — we use Codacy
  • Avoiding additional and unnecessary calls which could make code slow and introduce new bugs
  • Good modularization and hiding implementation behind small, well-documented interfaces
  • Covering code with different sets of automated tests, the major benefits of testing happen when you think about and write tests, not just when you run them
  • We do unit tests covering different and edge cases scenarios included
  • E2E tests for the main flows
  • Snapshot tests for covering the UI under different circumstances - The iOS team uses Snapshot Testing from Point Free
  • Refactor code: see if there is a way to improve

You might also be interested in: Practicing Coding Dojo to level up knowledge between engineering functions

6. Get validation from peers

After the implementation is done we deploy immediately and move the ticket to the validation stage. What does validation mean? We ask peers to validate the task. While asking we add validation steps for the verification. This instruction is already based on the tests that the developer added during the implementation. Testing by the developer is not about finding bugs, it’s about getting feedback on your code: aspects of design, the API, coupling, and so on.


When this becomes a regular process and force of habit, it’s fast and straightforward. The benefit of this process is that integration tests already cover all possible bugs. We already saw that we had significantly fewer bugs as a result of practicing this during the iOS integration.

7. Bug bash before going live

Before the project went live to customers, we did an internal bug bash with stakeholders and other teams. At this pre-release test party, bugs and inconsistencies are found, prioritized, and fixed before releasing to real users. It was an excellent opportunity for collaboration across the company to improve the product. That gave us valued feedback and an understanding of expectations from the shipped product.

When we found the bugs, we used the same validation approach mentioned above.  We added monitors, synthetic tests, and alerts on Datadog to check the health status, failures and to measure performance and response time.

8. Test together

We improved the team default process with a testing phase on our scrum routine—any customer-facing changes required at least one validation from a team member. Our project managers and designers also got involved for the most critical ones to ensure the business rules were applied as expected. This provided us more certainty when shipping, got us closer to what other team members were doing and accomplishing daily, and empowered us, engineers, to own the product even further. The validation process is also a time to give feedback and share more about best practices in each platform.  

Working in such an environment gives us the ability to be part of the entire product development journey. It gives us the chance to use different tools and techniques to make sure that the code is good and that the customers are satisfied. These ceremonies and processes develop into solid principles on delivering a complex project and stable bugless code.

9. Reframe challenges as learning opportunities

At first, it might seem like doing complex product features while migrating the tech stack would be a bad idea, but challenges allow us to improve and raise the bar. Don’t be afraid of failure. It’s a chance to learn.

The project we faced, coupled with GetYourGuide’s strong culture, empowered us to have ownership over our processes and technical standards. We have matured the documentation of main projects, how to surface and keep business logic up to date, how to ensure better quality, detect regressions with different sets of automated and non-automated tests, and better monitor the different aspects of our products and systems health.

If you’re interested in joining our engineering team, check out our open roles.

Other articles from this series
No items found.

Featured roles

Marketing Executive
Full-time / Permanent
Marketing Executive
Full-time / Permanent
Marketing Executive
Full-time / Permanent

Join the journey.

Our 800+ strong team is changing the way millions experience the world, and you can help.

Keep up to date with the latest news

Oops! Something went wrong while submitting the form.