<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Dodo Engineering</title>
    <description>The latest articles on DEV Community by Dodo Engineering (@dodoengineering).</description>
    <link>https://dev.to/dodoengineering</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F6908%2F7230b5ac-9c51-43e8-89e8-263e0431eb84.png</url>
      <title>DEV Community: Dodo Engineering</title>
      <link>https://dev.to/dodoengineering</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dodoengineering"/>
    <language>en</language>
    <item>
      <title>How many testers should ensure Dodo IS high quality</title>
      <dc:creator>Evgeniy Ivanchenko</dc:creator>
      <pubDate>Thu, 26 Oct 2023 09:10:28 +0000</pubDate>
      <link>https://dev.to/dodoengineering/how-many-testers-should-ensure-dodo-is-high-quality-2iop</link>
      <guid>https://dev.to/dodoengineering/how-many-testers-should-ensure-dodo-is-high-quality-2iop</guid>
      <description>&lt;p&gt;How many testers should ensure high quality in an IT company? I have been asked this question so many times that I have finally decided to answer it.&lt;/p&gt;

&lt;p&gt;First of all, I have to admit that asking "How many testers does a company need to ensure high quality?" is too abstract, because there is no right answer. Anyway, I did a little bit of research and found some tips such as "one tester for every three developers". Such answers are very similar to tips like: "You should drink 2 liters of water" or "You should take 10k steps per day". These tips apply to everyone and to no one at the same time. There is only one correct answer to this question - "It depends.&lt;/p&gt;

&lt;p&gt;Let's have a look together at what influences the ratio of testers to developers.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Critical products, where people's lives, safety and health depend, need more testers. Your ratio of testers to developers needs to be higher if you are developing a software for self-driving cars than if you are developing apps for selling pizzas.&lt;/li&gt;
&lt;li&gt;Level of developers and testers. If you have three senior developers, a junior tester is not going to take over the tasks of those three developers. And the other way round, a senior tester is over-qualified for a team of three junior developers.&lt;/li&gt;
&lt;li&gt;The culture of the company. If there is no culture in the company where all team members are responsible for product quality, but developers are only responsible for writing code and testers are responsible for testing this code and product quality. You need more testers than a company that has this culture. By the way, I have no idea how testers who don't write code for a product can be responsible for its quality.&lt;/li&gt;
&lt;li&gt;The size and the complexity of the product. If you have a huge and complex product, you will need more testers than if you have a small and simple product. But remember that without deep knowledge of the product and its context, it's easy to underestimate the size and complexity of a product.&lt;/li&gt;
&lt;li&gt;Process maturity If the whole team is responsible for quality and developers can test the product themselves before the tester starts testing: In this case you only need a few testers. You will need even fewer testers if the developers write not only unit tests, but also integration and end-to-end tests. You will need fewer testers if you have good monitoring, canary releases, or other ways of detecting problems quickly.&lt;/li&gt;
&lt;li&gt;How to deploy. If you have a complex way of distributing your products, e.g. software for cars, and your customers need to visit the service center to get their software updated, you will need more testers compared to a company that only updates its products online.&lt;/li&gt;
&lt;li&gt;The automation potential of the product. If your product is difficult to automate, you need more testers. Consider a company making printers. You can cover drivers with tests, but it's hard to automate integration of hardware and software. I really don't know how to automate the next case: Checking the text printed on the paper. Maybe we can use computer vision. But how much does it cost? And what about the ROI of this job?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Speaking of how many testers we need to ensure the high quality of Dodo IS: Let me give you some examples.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We have two teams with two developers and no testers. These teams own non-critical services. These services are mostly covered by unit, integration and end-to-end tests. These services can be rolled back in a few minutes. The developers in these teams can test the services themselves. Sometimes, before they build some features, they call in testers to help them with acceptance criteria.&lt;/li&gt;
&lt;li&gt;There is another team that has three developers and one tester. This team owns our system's core service. But the engineering culture in this team is high: fast releases, fast rollbacks, and high coverage by tests - after every problem in production, this team will create a new set of automated tests that will cover that problem. Great monitoring and alerting allow testers from this team to not only test their own features, but also do a lot of work for the QA guild.&lt;/li&gt;
&lt;li&gt;There are a number of teams that consist of 6 developers and 1 tester. Those teams develop mobile applications. Here the situation is a bit more complex. The developers are not as active in creating automated tests and in most cases rely on the testers for all quality and testing issues. For mobile apps, the cost of failure is higher than for web apps. You can't easily roll back your app on customers' devices. But for such teams, one tester is still enough because they have two backend developers, two Android developers, and two iOS developers, which means this team can develop two features simultaneously instead of a team of three fullstack developers developing three features simultaneously. That is why a single tester will be sufficient for this team.&lt;/li&gt;
&lt;li&gt;And we have another option: two teams (7+3 devs) and 1 tester. In this case, one tester is enough, because the devs can partially cover some testing tasks. But there is one thing that might be unpleasant: the tester has to be part of two PBRs, two daily scrum meetings, two planning meetings, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, as you can see, there is no right answer in general. As far as I'm concerned, I'm sure that every two-pizza team should have at least one tester/QA. This person provides testing and QA expertise, but testing and creating autotests can be done by the whole team. Then review the above criteria and determine whether additional testers are needed. Now we have 22 testers/QA and 34 development teams. We haven't reached my absolute minimum number of testers. But we're moving in that direction. What is your ideal ratio? Or what kind of unique ratio have you found? &lt;/p&gt;

</description>
      <category>testing</category>
      <category>qa</category>
      <category>developers</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>6 reasons why Dodo IS developers go to Gemba</title>
      <dc:creator>Evgeniy Ivanchenko</dc:creator>
      <pubDate>Wed, 28 Jun 2023 09:51:59 +0000</pubDate>
      <link>https://dev.to/dodoengineering/6-reasons-why-dodo-is-developers-go-to-gemba-31l7</link>
      <guid>https://dev.to/dodoengineering/6-reasons-why-dodo-is-developers-go-to-gemba-31l7</guid>
      <description>&lt;p&gt;As a QA engineer, I strongly believe that Gemba is a great opportunity for understanding your product. It helps to answer the question: “Am I doing bullshit or not?” Today I want to tell you more about its advantages and the insights that we got after visiting a pizzeria.&lt;/p&gt;

&lt;h2&gt;
  
  
  What does Gemba stand for
&lt;/h2&gt;

&lt;p&gt;Gemba (Japanese 現場), Genchi Genbutsu (Japanese 現地現物) translates as “the real location, real thing” (meaning “the situation onsite”) denotes an approach specific to the Japanese kaizen management practice. According to it, it is necessary to come to Gemba — the place where the work process is performed, collect the facts, and make a decision directly on the spot in order to fully understand the situation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Gemba"&gt;Wikipedia&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I will start from the beginning to talk about why we need Gemba. Our product is the Dodo IS — information system, which unites all parts of our business:&lt;/p&gt;

&lt;p&gt;· B2C (website and mobile apps);&lt;/p&gt;

&lt;p&gt;· B2B (apps for shift control, point of sale management, warehouse balances, cash register interfaces, etc.)&lt;/p&gt;

&lt;p&gt;It is quite difficult to create a high-quality product without knowing how it is used and who works with it. To assess the quality, we use 2 approaches:&lt;/p&gt;

&lt;p&gt;· &lt;strong&gt;Eat your own dog food&lt;/strong&gt; (for B2C) — a method of probing user experience when employees in a company use the products they produce. This approach is quite easy to use in real life. Like all customers, we order pizza when we are going by subway, walking in the rain, at -30C, or lying on the beach. Flaws, bugs, and bad UX are easy to feel.&lt;/p&gt;

&lt;p&gt;· &lt;strong&gt;Gemba&lt;/strong&gt; (for B2B) — a method of probing user experience when employees in a company use the products they develop. But in our case, it implies a deeper immersion into the product and the environment because you cannot go to work as a pizza maker at any time or become a manager in a pizzeria in order to understand how the system works.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who should go to Gemba
&lt;/h2&gt;

&lt;p&gt;No one has to, but everyone can. Going to Gemba is a right. No one forbids going to a pizzeria, coffee shop, or doner, but no one forces you either. Testers, developers, and product managers can go there. The main thing about it is the difference in focus.&lt;/p&gt;

&lt;p&gt;· &lt;strong&gt;For products&lt;/strong&gt;, this is one of the main activities. In a pizzeria, they find ideas, get insights, and can see the whole picture. Product managers use Gemba for hypothesis testing, in-depth interviews, customer development, customer journey mapping, and so on.&lt;/p&gt;

&lt;p&gt;· &lt;strong&gt;Developers and QA engineers&lt;/strong&gt; go to Gemba with the aim of “touching” the product they have made. A side effect of this is uncontrolled insights and ideas for product development. After returning from Gemba, not a single engineer said that it was a waste of time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why go to Gemba
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Cheap and cheerful
&lt;/h3&gt;

&lt;p&gt;Going to Gemba is easy to implement. The developer goes to a pizzeria or coffee shop and uses the product. That’s all. This is easier than simulating a pizzeria or coffee shop in the office, inviting actual employees of the pizzeria, and fictitiously demonstrating their user experience in the conditions of a spherical cow in a vacuum.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Automation Insights
&lt;/h3&gt;

&lt;p&gt;There can be insights about business process automation. One of our Android developers went to Gemba and saw what the marking process was like. Employees were COUNTING IN HEAD and HANDWRITING labels with the expiry dates of the products. For each product, they count and write the start date of defrosting, the validity date, and the expiry date. Product labeling is a boring routine process in which careless mistakes constantly occur.&lt;/p&gt;

&lt;p&gt;The developer realized that this was absolute bullshit. To automate this was “half an hour of a programmer’s work,” so he went ahead and automated it. This is how the mobile application for printing labels was born. The operation is reduced to the following: an employee selects a heading on the tablet, makes a tap, and a label with all the terms is printed, that’s it.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Flaws in the field
&lt;/h3&gt;

&lt;p&gt;In Gemba, the defects of the product are more evident. Dodo IS has features for auditing. These features were developed for the tablet. During the audit, an employee can enter data directly into the tablet, but it is too cold in the freezer and refrigerator, the tablet refuses to work, sometimes the connection is lost, and the interface itself is not very convenient. That’s why the results of the audit are written down on paper, and entered into Dodo IS later. Double work!&lt;/p&gt;

&lt;p&gt;Before rewriting the interface of the auditor, the development team went to night revisions in order to understand the process. They returned with ideas for improvement. For example, if the connection is lost, then the input of information must be made asynchronous, the data must be stored in local storage, and sent to the server when the connection is restored.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dxEC2A5Q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/48t9m3l74dzyq0tmyo3i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dxEC2A5Q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/48t9m3l74dzyq0tmyo3i.png" alt="Nighttime. Meanwhile, the developers are counting the tomatoes" width="800" height="1066"&gt;&lt;/a&gt;&lt;/p&gt;
Nighttime. Meanwhile, the developers are counting the tomatoes



&lt;h3&gt;
  
  
  4. Real working conditions
&lt;/h3&gt;

&lt;p&gt;In a pizzeria, you can see the working conditions in which the applications are used. One of the development teams created Pizzeria Tracking. It's a set of six tablets displaying the pizza, the recipe with ingredients added or removed, and the location of the pizza in the kitchen at the moment.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LtCZHRRj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c5qmrf3hwju1427mcjnh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LtCZHRRj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c5qmrf3hwju1427mcjnh.png" alt="Dough rolling tablet" width="800" height="554"&gt;&lt;/a&gt;&lt;/p&gt;
Dough rolling tablet



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CTzktAug--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uvmeg9pwf9mlyntxb1p4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CTzktAug--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uvmeg9pwf9mlyntxb1p4.png" alt="Packing tablet" width="800" height="553"&gt;&lt;/a&gt;&lt;/p&gt;
Packing tablet



&lt;p&gt;The team turned on the new tracking in one of the pizzerias and went to see how it worked. In the pizzeria, the developers saw that pizza makers were in a hurry to tap on the tablet very quickly, and they were doing it with their hands dirty with sauce or cheese. As a result, it was not always possible to tap on the tablet the first time. The team was very surprised. Surely, in the office, we clicked on the tablet with clean hands and there was no hurry. After going to Gemba, the team got back and redesigned the tap method in such a way, so that users could mark products even when they were doing it very quickly and with dirty hands.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Problem-solving
&lt;/h3&gt;

&lt;p&gt;After going to a pizzeria, you offer the most suitable solutions. You know how the business works, how processes are set up in real life. When the business comes to you with a problem, having a broad view of the business and knowing how the system works inside, you can offer a simpler or more systematic solution to the problem.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hy_uBmy_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hx0swktah5rlhmg3txqp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hy_uBmy_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hx0swktah5rlhmg3txqp.png" alt="Happy developers in Gemba" width="800" height="1066"&gt;&lt;/a&gt;&lt;/p&gt;
Happy developers in Gemba



&lt;h3&gt;
  
  
  6. Product Impact
&lt;/h3&gt;

&lt;p&gt;You can see how the inaccessibility or complex interface of the product affects employees and customers. You are standing at the checkout, and it is getting slow, there is a queue, and some customers are getting nervous or leaving. Without this valuable knowledge, the developer might not have noticed the increase in response latency.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZWX6TFyY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yo0kpn18fqksq5dnpx5c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZWX6TFyY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yo0kpn18fqksq5dnpx5c.png" alt="QA engineer is taking orders at the checkout" width="768" height="1024"&gt;&lt;/a&gt;&lt;/p&gt;
QA engineer is taking orders at the checkout



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tIBeP25H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p4w60qlam346rmxwtpk2.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tIBeP25H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p4w60qlam346rmxwtpk2.jpeg" alt="Our CTO is happy to deliver your pizza" width="800" height="1067"&gt;&lt;/a&gt;&lt;/p&gt;
Our CTO &lt;a class="mentioned-user" href="https://dev.to/pritchin"&gt;@pritchin&lt;/a&gt; is happy to deliver your pizza



&lt;h2&gt;
  
  
  Why not go to Gemba
&lt;/h2&gt;

&lt;p&gt;I have never been able to imagine any disadvantages of this approach except for one: our developers who go to Gemba are not financially justified. We receive a lot of feedback that we are doing expensive bullshit, we are paying a developer for spinning pizza, distracting him from work and his immediate tasks. My opinion is simple — we pay developers for their work, for their product. They just perform work in a pizzeria, look at the product with the eyes of a client and answer themselves in real-time to the question “Have we done bullshit or not?”.&lt;/p&gt;

&lt;h2&gt;
  
  
  The End
&lt;/h2&gt;

&lt;p&gt;At Dodo Brands, going to Gemba is a common thing. This is a cool experience, which helps us to check that we make a high-quality product.&lt;/p&gt;

&lt;p&gt;I liked how one of our developers wrote: “For me, as a developer who has never gone to Gemba, a developer who went to Gemba looks like a bearer of secret knowledge. During a discussion at a general meeting, such a person may say: “The feature you propose will not work, because I was in a pizzeria and saw how it really was there. In general, you need to go to Gemba at least for this”.&lt;/p&gt;

&lt;p&gt;Two most common questions about Gemba and IT people&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do you go to a pizzeria without a medical certificate?&lt;/strong&gt; No way. You can’t go to Gemba without a medical certificate. We are normal people and strictly observe the standards of cleanliness. There can be no exceptions. Before you go to Gemba, you need to pass a medical examination and obtain the appropriate work permit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do developers need to clean the toilets?&lt;/strong&gt; We go to pizzerias in order to understand how our product works in “combat” conditions. But when we come to a pizzeria, we become full-fledged trainees, so we can still be asked to clean up, and we will do it.&lt;/p&gt;

</description>
      <category>qa</category>
      <category>developers</category>
      <category>testing</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Ensuring reliability: SLOs, on-call process, and postmortems</title>
      <dc:creator>Pavel Pritchin</dc:creator>
      <pubDate>Wed, 07 Jun 2023 12:28:00 +0000</pubDate>
      <link>https://dev.to/dodoengineering/ensuring-reliability-slos-on-call-process-and-postmortems-5a64</link>
      <guid>https://dev.to/dodoengineering/ensuring-reliability-slos-on-call-process-and-postmortems-5a64</guid>
      <description>&lt;p&gt;Hello there, my name is Pavel Pritchin, and I’m CTO at Dodo Engineering, part of Dodo Brands. My previous role was Head of SRE, and since then, the reliability of our IT system Dodo IS has been one of my responsibilities. Today I’d like to share which practices help us to ensure the stability of our system and even share some templates that anyone can use at their company.&lt;/p&gt;

&lt;p&gt;Dodo Brands is a franchise business, and the IT system developed by Dodo Engineering team is provided as software as a service for partners. The head company covers the cost of development and maintains the stability of the Dodo information system (Dodo IS). We introduced the Service Level concept to ensure system reliability and set Service Level Objectives (SLOs). There are also processes in place to maintain reliability.&lt;/p&gt;

&lt;h3&gt;
  
  
  Service Level Objectives
&lt;/h3&gt;

&lt;p&gt;Our SLOs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SLOs for monitoring application errors (success rate),&lt;/li&gt;
&lt;li&gt;SLO for the number of bugs per product,&lt;/li&gt;
&lt;li&gt;SLO for the crash-free rate of mobile applications.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Different teams can add their custom stability goals. For example, someone may have a target value for release frequency.&lt;/p&gt;

&lt;p&gt;It's not enough to set the objective; it must also be maintained. For example, the SLO for errors has an overall target SLO for the entire system of 99.9%.&lt;/p&gt;

&lt;p&gt;Dodo IS’ services status dashboard:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxdogenxps5dxsn13zcbb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxdogenxps5dxsn13zcbb.png" alt="Dodo IS’ services status dashboard image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The critical services have established SLOs, typically 99.99%. Each service has an owner team whose task is to monitor and fix stability issues. The screenshot shows a summary dashboard that allows the service owner team to write actions to fix the problem with their service. Even fixing minor deviations from the target value helps maintain the overall stability of the Dodo IS.&lt;/p&gt;

&lt;p&gt;To maintain service level, it's not enough to analyze problems after the fact. It's also necessary to respond quickly to service failures. Here comes on-call process to deal with it.&lt;/p&gt;

&lt;h3&gt;
  
  
  On-call
&lt;/h3&gt;

&lt;p&gt;Every development team is responsible for the services of its domain. Duty rotations include separate shifts during work hours, nonworking hours, and on weekends or holidays. For critical services, we implemented 24/7 duty shifts.&lt;/p&gt;

&lt;p&gt;All system services are divided into three levels of criticality. They are called pools: A, B, and C. We have an escalation system outside of business hours for services in pools A and B. Pool C includes all other services regardless of their criticality. A, B, and C pools have their target MTTA, SLO, and compensation coefficients. We watch every service and are ready to fix any issue.&lt;/p&gt;

&lt;p&gt;Each on-call engineer undergoes workshops and other training and has a deep knowledge of the services they work with every day. In case of a service failure, the on-call engineer should start to look into the problem within 5 minutes, and the incident management pipeline handles the situation. For their work on incidents and being on-call for critical services, on-call engineers receive various compensations.&lt;/p&gt;

&lt;p&gt;Compensations and target metrics for on-call engineers in different on-call pools:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvlk3961t3f34g8djlbw2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvlk3961t3f34g8djlbw2.png" alt="Compensations and target metrics for on-call engineers image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's see how it works at night or on weekends (at the right part of the scheme). The monitoring signal comes to the 1st support line. 1st line decides whether the failure is critical or if these are minor fluctuations or flops alerts. If the issue is severe, 1st line escalates it to 1 of 8 on-call engineers in pools A and B. On-call engineer can call those on duty at that moment or get to people in another pool if there are problems in related systems and services. We developed an escalation system for cases where no one answers, so we can still find engineers to fix the issue as quickly as possible.&lt;/p&gt;

&lt;p&gt;Incident management with on-call process:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff4ntu0yzlb9klc7xbh7n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff4ntu0yzlb9klc7xbh7n.png" alt="Incident management with on-call process image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But once again: it's not enough to just find a capable engineer, find the reason for the incident, and fix the problem. If we don't analyze it and won't create and follow some plan to get rid of the root cause, it may happen again and again, bringing new problems to our business. That's why we use postmortems.&lt;/p&gt;

&lt;h3&gt;
  
  
  Postmortem
&lt;/h3&gt;

&lt;p&gt;After incidents, a "postmortem" review always takes place. The practice of postmortems is used to identify the root cause of the problem. It's essential to identify systemic issues in the architecture and design of services and fix them. Without this, we cannot maintain the Service Level because the number of problems will increase over time.&lt;/p&gt;

&lt;p&gt;One of the main difficulties in working with postmortems is conducting a qualitative analysis of what happened. For this, the structure of a template is essential. The template should lead us from describing facts to solving concrete decisions. Helping questions like "What helped us during the incident," "What went wrong" or "What went like clockwork" should push for deep insights. You also need general information specific to all failures: date, downtime duration, business loss in money, and affected services. General information allows you to do a meta-analysis and look at trends and tendencies.&lt;/p&gt;

&lt;p&gt;Here you can find the template of postmortem which we use at Dodo after every incident: &lt;a href="https://www.notion.so/Delivery-driver-app-doesn-t-work-Network-failure-2c315f993e324dddb9c37cd41ae1d291?pvs=21" rel="noopener noreferrer"&gt;https://www.notion.so/dodobrands/Delivery-driver-app-doesn-t-work-Network-failure-2c315f993e324dddb9c37cd41ae1d291?pvs=4&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also learn best practices of postmortem review from the authors of the practice in the SRE book from Google, just as we did: &lt;a href="https://sre.google/sre-book/postmortem-culture/" rel="noopener noreferrer"&gt;https://sre.google/sre-book/postmortem-culture/&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;As a result, stability support works in conjunction with processes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We are maintaining the Service Level of each service, fixing minor service issues.&lt;/li&gt;
&lt;li&gt;On-call duty and incident management process, during which we mitigate failures.&lt;/li&gt;
&lt;li&gt;A high-quality analysis of the causes of failures and their elimination. Sometimes fixing problems requires a lot of time and significant system changes.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Thus, we can guarantee the specified level of stability for the Dodo IS.&lt;/p&gt;

&lt;p&gt;If you have any questions on how we work with SLO, on-call, and postmortems, feel free to contact me in comments or directly: we at Dodo Engineering are always happy to share our experience!&lt;/p&gt;

&lt;p&gt;To discover more about Dodo IS and top QSR innovations in &lt;a href="https://dodobrands.io/" rel="noopener noreferrer"&gt;Dodo Brands&lt;/a&gt;, follow us on &lt;a href="https://www.linkedin.com/showcase/dodoengineering" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;, &lt;a href="https://dev.to/dodoengineering"&gt;dev.to&lt;/a&gt;, and &lt;a href="https://medium.com/dodoengineering" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>sre</category>
      <category>reliability</category>
      <category>webdev</category>
      <category>devops</category>
    </item>
    <item>
      <title>3 Cases When Accessibility Could Highlight Bugs and Save Money</title>
      <dc:creator>Mikhail Rubanov</dc:creator>
      <pubDate>Thu, 01 Jun 2023 14:26:00 +0000</pubDate>
      <link>https://dev.to/dodoengineering/3-cases-when-accessibility-could-highlight-bugs-and-save-money-58ih</link>
      <guid>https://dev.to/dodoengineering/3-cases-when-accessibility-could-highlight-bugs-and-save-money-58ih</guid>
      <description>&lt;p&gt;The first thing people ask about accessibility is whether it can bring money, because there are few users there. A popular misconception is that they mark out one group (well, how many blind people are there per million?) and don’t evaluate the big picture (&lt;a href="https://appt.org/en/stats" rel="noopener noreferrer"&gt;45% on iOS and 59% on Android&lt;/a&gt; include at least one accessibility setting).&lt;/p&gt;

&lt;p&gt;After several years of deep research in accessibility, I understood another thing – if we start adapting apps for people with special needs, we learn much more about people’s interaction with the apps and this gives us cool new tools.&lt;/p&gt;

&lt;p&gt;Today we will talk about mental accessibility problems: how strong beliefs can prevent people from placing an order, what the problem of inconsistent behavior can be and we will also search for design system boundaries. All these will be about one thing: how adaptation for the blind changes the designer’s perception, how it shows the details of the mental model in the human head and how it can highlight the errors at the early stages of development.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example 1: delivery time
&lt;/h2&gt;

&lt;p&gt;Let’s start with the brightest case when we definitely know the value in money.&lt;/p&gt;

&lt;p&gt;Several years ago, we were making a new design for order placement page: address, time, payment methods etc. One of the design solutions was to remove all the labels from the elements – the screen would become clearer, and the data itself and its forms were enough for a person to understand what was written there. The result was roughly the following: there was a title for the whole screen, but the methods of order, the address and the delivery time had no titles, only the values.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frt95m5y3ggx6921ihwik.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frt95m5y3ggx6921ihwik.png" alt="Screenshot of checkout screen with address, ASAP button and payment type"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s stop at this layout and think if everything is clear in it.&lt;/p&gt;

&lt;p&gt;The designers had a few questions about how to organize the information. For example, there was a hypothesis that people could hardly understand what the chevrons (&amp;gt;) in the right half of the lines meant. Even though they are everywhere in iOS, they strangely go together with the rest of the data, and that is why the lines do not really look like buttons. Then we decided to split it as follows: the chevron shows that a new page will open, and the “Use” button opens a modal window.&lt;/p&gt;

&lt;p&gt;That’s how we released.&lt;/p&gt;

&lt;p&gt;In a couple of years, we got feedback:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;I wanted to order a pizza, but a bit later: I ordered at 12, but wanted it to be delivered at 16.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I didn’t find a button for delivery time choice and wrote a comment to my order. The courier didn’t notice the comment and delivered the pizza in an hour, at 13. But that was too early for me, the pizza will be cold at 16.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I asked the courier how I could choose later delivery time. He showed me the delivery screen with “ASAP” button.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;But I didn’t need ASAP, I needed **later&lt;/em&gt;&lt;em&gt;!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Fix it&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What conclusion can you make from this feedback? At that time our conclusion was the following: that person did not understand that the delivery time could be changed. What was the solution? Since he did not understand how to change it, the problem was in the chevrons, and it we had to make it clearer. That’s what we had: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpv20wj13xzd14zp0lo32.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpv20wj13xzd14zp0lo32.png" alt="Screenshot of delivery time button with label ASAP and change button inside"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We started, tested, didn’t notice much difference. So it remained like that.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Mental model&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;And this is how this case looked from accessibility perspective and could influence the business.&lt;/p&gt;

&lt;p&gt;But let’s begin with some theory. Actually, we do not peer into the interface when we use it: we scan the page, roughly understand what is shown and try to complete our task. To fulfil the goal, we use the model which is already formed in our head.&lt;/p&gt;

&lt;p&gt;In our example, the person “read” the interface differently than the designer had intended. The user later referred to his interface model. Mental model is so strong that even if you understand that something is wrong, you won’t be able to quickly redesign your mental model. That’s what happened: the person knew he could choose the delivery time, but he didn’t find the button which was right in front of him.&lt;/p&gt;

&lt;p&gt;It would be nice to work not only with how people see the interface, but also with the model of how they perceive it. But how? The answer is simple – change the perception channel and then look what changes in the interface perception.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fviy4kecwcfdosz6vhgvu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fviy4kecwcfdosz6vhgvu.png" alt="Schemes shows how visual and audio perception leads to same representation in mind"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Screen Reader&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;We were working on screen reader support and needed to adapt all the labels and buttons on the screen. Basically, we had to give a name, a value and the type of element, and the smartphone would generate speech itself to describe the interface to the blind. The best thing about the screen reader is that you don’t have to change the existing graphic interface – with the right text descriptions you can easily comprehend it by ear.  And this works because we can build a mental model in the human head both visually and by ear, and text description is enough to understand how the interface works.&lt;/p&gt;

&lt;p&gt;For a simple description, three attributes are enough: a name, a value and a label. But there can be more:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frlxit0drw5u57qxux2ip.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frlxit0drw5u57qxux2ip.png" alt="Full diagram of element's description for VoiceOver. Container's name, selected, label, value, dimmed, trait, hint"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now let’s form the description of our controls. Usually, there’s nothing to add and we take the text right from the interface, but in this case it would be complete nonsense: ASAP, 15 min, button.&lt;/p&gt;

&lt;p&gt;for this UI…&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5duzka55z7mdkov74tad.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5duzka55z7mdkov74tad.png" alt="Screenshot of delivery time with ASAP label"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;…we have that description&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftyi3m19b5ouf4dm2ix1p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftyi3m19b5ouf4dm2ix1p.png" alt="Screenshot from VoiceOver Designer app that describes selected VoiceOver's settings. Label = ASAP, value = 15 min"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this stage, we can go two ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;to write a special text for the screen reader&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;to redesign the interface&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It was too late to redesign. That’s why we only made correct labels for the interface for the screen reader: &lt;em&gt;Delivery time: ASAP, ~15 min, button.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkkzt7s164x6p6toc68c5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkkzt7s164x6p6toc68c5.png" alt="Screenshot from VoiceOver Designer app that describes selected VoiceOver's settings. Label = Delivery time, value = ASAP, 15 min"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With this wording, a person gets the correct mental model and there can be no more problems like our client wrote about.&lt;/p&gt;

&lt;p&gt;Let’s have a look again at our attempt to fix the client’s problem by changing the chevron into the button: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa3g21tg7nt4y5bqbgbm1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa3g21tg7nt4y5bqbgbm1.png" alt="Screenshot where we replaced disclosure indicator on the right by change button"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Has it changed anything in mental model? No. The client clearly understood that he could press control, but the problem was that he did not understand the result of it correctly.&lt;/p&gt;

&lt;p&gt;It’s interesting to look at Apple’s standard position of the elements for this cell: the name is written to the left and large, and the value is next to the chevron. By the proximity of the chevron and the value, it becomes clear that it is the value that is changing. In this version, the interface is consistent with the description for the screen reader (and it can even correctly substitute the values in the standard control)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhneu02i2grrwfa2cbwbe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhneu02i2grrwfa2cbwbe.png" alt="Screenshot of standard layout for cell: label on the left, value on the right near disclosure indicator"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This could be the end of our case about the mental models and their persistence, but we had an unusual experiment: the designer suggested a time selection option in the form of a horizontal carousel, and the business tested it with an A/B test.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff9wy197kd6ydgqvhlrst.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff9wy197kd6ydgqvhlrst.png" alt="Redesigned element for delivery time: 4 buttons are placed in a row and is abled to press directly. Buttons: ASAP, and 3 buttons with time interval of half an hour"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Is this design better from the graphical point of view? Much better: there’s the name, you can see the current variant and the alternatives. Moreover, you can change it with one tap without changing the screen.&lt;/p&gt;

&lt;p&gt;To the blind it would sound like this: &lt;em&gt;Delivery time, ASAP, 15 min. Adjustable.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhsgyp3aro7owhs6rg19w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhsgyp3aro7owhs6rg19w.png" alt="Screenshot of VoiceOver Designer app that setup the element like adjustable control"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, as a result, the way the interface sounds to the blind and the way it looks graphically are completely consistent, which minimizes the difference between the visual representation and the mental model.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Test&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;We have tested this design on Android and have got a slight increase of conversion. On the scale of 900 pizzerias, this gives 100 thousand dollars or 100 dollars per pizzeria monthly. It's not much, but who will be against receiving 2400 dollars a year just because of the visual part of some component in an app? And the money comes out of thin air from the franchisees' perspective.  &lt;/p&gt;

&lt;p&gt;As a result, adapting the app for the blind could become a good tool for working with the mental model to highlight the difference between the visual design and how a person perceives the information. Then we could have noticed the contradiction earlier, we could have thought more thoroughly about the component’s design and we could have been earning more money for two years already.&lt;/p&gt;

&lt;p&gt;In the end, ordinary users would have made fewer mistakes, and the adaptation for the blind would have become even easier, because all the text is already in the interface, all you need is to transmit it correctly to the screen reader.&lt;/p&gt;




&lt;h2&gt;
  
  
  Example 2: bonus program and tap area**
&lt;/h2&gt;

&lt;p&gt;The second case is about trying to make it convenient for a narrow circle of people.&lt;/p&gt;

&lt;p&gt;We have a cell with a product in the menu. It is simple at first glance: the name, the description and the price.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj2ggroupltmfqm0dvzmx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj2ggroupltmfqm0dvzmx.png" alt="Screenshot of a cell with pizza image, name, description and pizza's price"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From the interactive side, everything looks simple, too: a tap on the entire cell opens a card with the product description.&lt;/p&gt;

&lt;p&gt;Then we got an idea to make it convenient for the advanced users: a tap on the button with the price learnt to add the product to the cart, without opening the product card. Wasn’t it great? It was, because it became easier to add drinks, snacks and everything that had no additional settings.&lt;/p&gt;

&lt;p&gt;The problems will be visible if you highlight interaction areas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the tap area for the price is rather small&lt;/li&gt;
&lt;li&gt;under the button, there is a place which opens the card without adding the product to the cart&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsyz90jwiih1xuzqilqe6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsyz90jwiih1xuzqilqe6.png" alt="Screenshot of a cell with pizza that shows tappable area of price button: it's very small"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What makes things worse is that we do not explain the difference in behavior in any way: I’m sure there are cases when people tap on the cell, but accidentally click the button, and “for some reason” the product is immediately added to the cart. There is no mental model for such a change in behavior.&lt;/p&gt;

&lt;p&gt;Is it possible to make this behavior one-valued? Yes, for example, in our other apps, the button is in the corner, with a bigger contrast and with a plus catching our eye.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3zujq3a0awjg4cwddlml.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3zujq3a0awjg4cwddlml.jpeg" alt="Screenshot of application with coffee catalog and plus button in cell's corner"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It was even funnier in the bonus program. We have made a screen with a choice of goods you can buy for the bonuses you have collected. The design of the cell is the same, so we decided to keep the behavior: a tap on the price adds the product to the cart, and a tap on the cell … does nothing, because it usually opens the product card, but there’s no card here. Is it logical? In general, yes, but the users still don’t know about it.&lt;/p&gt;

&lt;p&gt;As a result, we have these tiny tap areas on the screen. The problem is obvious only because I have highlighted the buttons; from a regular screenshot, you can never guess about it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu68d1q1epg1f7m31w18h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu68d1q1epg1f7m31w18h.png" alt="Screenshot of screen with a list of bonus products and small tappable areas on price buttons"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the end, a number of people can get problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;sometimes a card opens and sometimes a product is added;&lt;/li&gt;
&lt;li&gt;bonus program does not respond to taps at all, because it is not obvious that it is the button that needs to be clicked on here;&lt;/li&gt;
&lt;li&gt;some people can hardly aim at the tiny price button.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The screen reader is also broken: it focuses on the entire card and reads its description correctly, but it can’t tap on, because normally the tap goes to the center of the element, and the button is “a bit” lower.&lt;/p&gt;

&lt;p&gt;How should it be laid out?  The click area should be to the full width of the screen and as high as possible:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc9vdh6oudeti2hl4sa0c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc9vdh6oudeti2hl4sa0c.png" alt="Same screenshot of screen with a list of bonus products and tappable areas in whole area of each cell"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The behavior between screens needs to be aligned: a tap on the card should always perform the target action without unnecessary flirting with a quick adding to the cart: people don’t order pizza every day, they don’t need this high speed.&lt;/p&gt;

&lt;p&gt;Then the cells will be large enough for the blind, it will be easy for people with tremor to get into them, the behavior will be the same throughout the entire app, which will not hinder people with mental disorders. And it will be clearer for &lt;em&gt;ordinary&lt;/em&gt; people, too.&lt;/p&gt;

&lt;h3&gt;
  
  
  Screen reader
&lt;/h3&gt;

&lt;p&gt;Again, the adaptation for the screen reader shows new details. By ear, we would like to know the name and the price first, and only then to listen about the ingredients.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1vnq6dlsnpg77qkzit0k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1vnq6dlsnpg77qkzit0k.png" alt="Screenshot of VoiceOver Designer with cell's description Tonno, from 11.9 euros and description in the end"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This problem is also graphically seen, because all design tricks are here: a bold title, a faded description and a colored button are trying to change the order of how we look at the interface in order to change the order of reading. Besides, people with poor eyesight cannot read the faded text.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkv8lcg7t98obse9qmc7h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkv8lcg7t98obse9qmc7h.png" alt="Cell's screenshot that describe visual reordering of reading: title, price and description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In general, it's OK for the graphic interface to work with order this way, but trying to get rid of this problem can lead to interesting questions. For example, is the description necessary if we have made it invisible by all means? And if we go without it, can we make the pictures larger? Will it affect the conversion? Will we earn more money this way?&lt;/p&gt;




&lt;h2&gt;
  
  
  Example 3: &lt;strong&gt;the boundaries of the design system&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Once we discussed our plans for the design system and how we look at it. The result was this chain from small elements to large ones:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;colors, fonts, controls&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;cells, cards, screens&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;mood and values.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With the first point, everything is clear and everyone knows how to do it. We decided not to dive deep into the values, so the question about cells arose, from the previous examples: are product cells a part of our design system?&lt;/p&gt;

&lt;p&gt;On the one hand, they are, because the same elements are found in the menu, product search, bonus program. On the other hand, I want to have a possibility to customize something on the spot, just in case. The discussion has hit a wall, each side had its own arguments. But if you dig to the values and look from the side of accessibility, everything will become quite simple. The menu cell supports DynamicType, VoiceOver, Voice Control, Switch Control, and a whole bunch of business tasks: personal pricing, product availability, focusing on the right products, support for Arabic writing from right to left, and so on. That's 24 states at minimum, a decent amount of work:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm5xyndsoznw0yu1c247d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm5xyndsoznw0yu1c247d.png" alt="Screenshot of files in finder that represents different variants of product's cell"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, we decided to make large cells with an emphasis on goods. That's over 30 more states to make it work just as well.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd8x44vtb3ruycgdf21rj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd8x44vtb3ruycgdf21rj.png" alt="Another screenshot of files in finder with differrent layout"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From this angle, another question arose: for a sudden desire to draw a button a little differently, do we want to give up all these possibilities? Or even worse: to duplicate them in another component and then maintain this oO?&lt;/p&gt;

&lt;p&gt;In the end, my suggestion is as follows: focus on the main scenarios, invest in them, and let the additional features be additional: build them on the basic components so as not to add special support. We’d better spend the saved time on the main scenarios, for example, on adding support to the accessibility.&lt;/p&gt;

&lt;p&gt;Maintaining accessibility at the design system level is very convenient: you do it once, and the correct work is immediately ensured throughout the entire app. But in order to reach the effect, you need to move further in what we perceive as a single component. Thus, different cards, modals, pop-up toasts, and even entire scripts may have additional requirements, and the boundaries of their applicability will be dictated by accessibility requirements.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;VoiceOver Designer&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;All three cases have a common base: accessibility needs to be dealt with as early as possible. It will be able to give the designer an additional tool, a special view, a better understanding of the result, and the ability to distract from the visual.&lt;/p&gt;

&lt;p&gt;But there &lt;del&gt;are&lt;/del&gt; were no such tools. To help the designer immerse himself in the topic, I’ve written the &lt;a href="https://rubanov.dev/voice-over-designer" rel="noopener noreferrer"&gt;VoiceOver Designer app&lt;/a&gt;: it allows you to mark up the description for the screen reader on top of the screenshot, run the mockup on an iPhone and listen to the result.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkqkflttedeyi04tijjyb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkqkflttedeyi04tijjyb.png" alt="Screenshot of the application VoiceOver designer. Screenshot of screen with pizza inside the app"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Almost all properties that can be set to an element are available in the interface, which sets the restrictions and suggests what result we can get.&lt;/p&gt;

&lt;p&gt;To make it easier to dive into the topic, I have collected a dozen of examples of adaptation: you can see what settings are selected on them, how the screens are marked up and how the blind interact with them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq0gyof3l5nt734vmq3dt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq0gyof3l5nt734vmq3dt.png" alt="Screenshot of the application VoiceOver designer with samples of the screen"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can learn more about the app and examples of adaptation on the website - &lt;a href="https://rubanov.dev/voice-over-designer/ru" rel="noopener noreferrer"&gt;https://rubanov.dev/voice-over-designer&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Oh yes, I also wrote a book - &lt;a href="https://rubanov.dev/a11y-book/" rel="noopener noreferrer"&gt;About iOS Accessibility&lt;/a&gt;. The book is free. It’s in Russian, but all the code examples and illustrations can be understood without translation. To make the book accessible to anyone, we are working on translation. Follow us so as not to miss the release of the book chapters in English.&lt;/p&gt;

&lt;p&gt;To discover more about Dodo IS and top QSR innovations in Dodo Brands, follow us on &lt;a href="https://www.linkedin.com/showcase/dodoengineering" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; and &lt;a href="https://medium.com/dodoengineering" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>a11y</category>
      <category>mobile</category>
      <category>ios</category>
      <category>ui</category>
    </item>
    <item>
      <title>How We Translated the Dodo Pizza App into Arabic</title>
      <dc:creator>Kirill-Orloff</dc:creator>
      <pubDate>Wed, 17 May 2023 06:46:58 +0000</pubDate>
      <link>https://dev.to/dodoengineering/how-we-translated-the-dodo-pizza-app-into-arabic-2pki</link>
      <guid>https://dev.to/dodoengineering/how-we-translated-the-dodo-pizza-app-into-arabic-2pki</guid>
      <description>&lt;p&gt;What do you know about adding the support of right to left (RTL) languages in iOS apps? You have to use leading and trailing instead of left and right, and also… We didn’t know anything else either, but we had to puzzle it out.&lt;/p&gt;

&lt;p&gt;We are making the Dodo Pizza App ready for localization in Arabic. In this article we would like to share our findings and tell you, why we need RTL support in the app, why it is not enough just to adapt the layout in code to support RTL, why we had to redraw the illustrations, and in what way the Arabic percent sign is different from the European one. Besides, we will show a lot of screenshots and will share some tips on RTL support in code.&lt;/p&gt;

&lt;p&gt;Breaking news! Dodo has opened a &lt;a href="https://www.instagram.com/dodopizza.uae/" rel="noopener noreferrer"&gt;pizzeria in Dubai&lt;/a&gt;. For the developers it means that they have to make the app ready for launch in a new country. The major part of work here is usually for the back-end developers, and we just have to add a new language in the app.&lt;/p&gt;

&lt;p&gt;Localization has already been set up for a long time, but the launch in Dubai is very special. App localization for Dubai is different from the localization in all previous countries because in Arabic words are written from right to left. It means that people read from right to left. And all the content is perceived from right to left. Their gaze direction changes. Which means that in the app…&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F53oguzm88fgm617aka42.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F53oguzm88fgm617aka42.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  First, enable RTL
&lt;/h2&gt;

&lt;p&gt;We began &lt;del&gt;with googling how to do it&lt;/del&gt; with examining the problem and searching for possible solutions.&lt;/p&gt;

&lt;p&gt;Apple provides good material on this topic to begin with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://developer.apple.com/videos/play/wwdc2022/10034/" rel="noopener noreferrer"&gt;Design for Arabic&lt;/a&gt; WWDC22,&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.apple.com/videos/play/wwdc2022/10107/" rel="noopener noreferrer"&gt;Get it right (to left)&lt;/a&gt; WWDC22,&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.apple.com/design/human-interface-guidelines/foundations/right-to-left/" rel="noopener noreferrer"&gt;Right to left&lt;/a&gt; Apple HIG,&lt;/li&gt;
&lt;li&gt;Apple Documentation &lt;a href="https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPInternational/SupportingRight-To-LeftLanguages/SupportingRight-To-LeftLanguages.html" rel="noopener noreferrer"&gt;Supporting Right‑to‑Left Languages&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then we decided to get the feel of RTL ourselves and we began to poke our app. If you want to see what your app will look like with the enabled RTL, this is how you can do it:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0cx3d87vo6idrdmmvvdg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0cx3d87vo6idrdmmvvdg.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In Xcode go to Edit Scheme (option+click on current target) → Go to Options tab → In App Language select Right-to-Left Pseudolanguage instead of System Language → Restart the App&lt;/p&gt;

&lt;p&gt;In the Xcode dropdown menu there will be two pseudolanguages: Right-to-Left and Right-to-Left With Right-to-Left Strings.&lt;/p&gt;

&lt;p&gt;The first one will simply align all the local strings of the app to the right. The second one will reverse the letters.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj9jxgmuzisoeaub2bgcb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj9jxgmuzisoeaub2bgcb.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Please note that if you choose Right-to-Left With Right-to Left Strings, only local strings will change. The strings which come from the backend will be displayed as they are sent.&lt;/p&gt;

&lt;p&gt;It’s a bad idea to look only at your own app because you lack visual experience of RTL-apps. To develop this skill, we looked at various adapted apps and websites.&lt;/p&gt;

&lt;p&gt;After we got used to RTL a bit and studied everything in our app, we started drafting a document with screenshots of all the screens. We took two screenshots of each screen (a regular one and one with enabled RTL), and then for each screen we described what wasn’t functioning properly. When we had done it, we realized that a lot of problems appeared repeatedly from screen to screen. We grouped them together. Further we will talk about each group of problems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Surprise at Xcode work with RTL-strings
&lt;/h2&gt;

&lt;p&gt;Bonus section. Check it out, what Xcode does with RTL-strings:&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/bOIJXp7tbdg"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;On the video we are always pressing the right arrow key.&lt;/p&gt;

&lt;p&gt;For comparison, in Android Studio the way of behavior is quite different. In the studio the cursor always moves in the direction of the arrow key you press on the keyboard. Maybe this can be tuned somewhere, but we didn’t check.&lt;/p&gt;

&lt;h2&gt;
  
  
  Checking what’s broken in the app
&lt;/h2&gt;

&lt;p&gt;Let’s go over the groups of problems.&lt;/p&gt;

&lt;h3&gt;
  
  
  Layout of views and cells
&lt;/h3&gt;

&lt;p&gt;When adapting the app to RTL-languages, iOS does most of the work for us. There are screens in the app which already look the way they should when RTL is enabled.&lt;/p&gt;

&lt;p&gt;The major group of problems arouses when the views are laid out in such a way that iOS cannot reverse them correctly itself.&lt;/p&gt;

&lt;p&gt;You have to go to each of such views, clarify why the problem occurs, and fix it manually.&lt;/p&gt;

&lt;p&gt;For example, have a look at the purple widget of an active order:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F60qal92x6ruq6ryyn0jd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F60qal92x6ruq6ryyn0jd.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The title and the main text need to be aligned to the right; the picture and the main text need to be swapped around.&lt;/p&gt;

&lt;p&gt;What the mistake is: the widget of an active order is made up on the frames which do not take RTL-orientation into account. We prefer not to use the layout on frames, but in this case it was justified by the requirements to the widget.&lt;/p&gt;

&lt;p&gt;For the widget to be displayed correctly, you need to know the current orientation with the help of property view.effectiveUserInterfaceLayoutDirection, and to recalculate the frames for RTL-orientation.&lt;/p&gt;

&lt;p&gt;The views with nutrition value and the ingredients that can be excluded got completely messy:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx90v5rl40mrw80i0g4jo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx90v5rl40mrw80i0g4jo.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4l38dr2g9mftb6o5k6z1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4l38dr2g9mftb6o5k6z1.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What the mistakes are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;in the nutrition value views all the titles had left alignment, and all the values had right one. You need to take RTL into account when setting textAlignment;&lt;/li&gt;
&lt;li&gt;in the ingredients views the button “Close” had alignment = .left, and the list of ingredients was laid out on frames.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The adaptation of the app for RTL has become a good reason to take a look at all the screens and to make sure that all the used components are in line with the design system. Thus, for example, we have completely changed the dialogue of ingredients deletion.&lt;/p&gt;

&lt;p&gt;The checkout doesn’t look very good either:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F927f7auu4xxm6c038fc7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F927f7auu4xxm6c038fc7.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Where the mistake is: it seems that the screen is completely out of order, but in fact it is not so bad at all. It’s just that there was a wrong textAlignment for UILabel, and the pictures weren’t mirrored.&lt;/p&gt;

&lt;p&gt;On the list of countries the flag should be shown first, and then the name of the country. It means, that in RTL the flag should be to the right of the country.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcfo3uex9oosf262edckm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcfo3uex9oosf262edckm.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What the mistake is: flag is an emoji. In the code it was like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var nameWithFlag: String {  
    "(isoCode.emoji) (name)"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pay attention to the button “Show nearest pizzerias”:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frbyme5nqxseybn4ps9jr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frbyme5nqxseybn4ps9jr.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What the mistake is: the button had hardcoded left and right imageEdgeInsets on the storyboard. We changed them to NSDirectionalEdgeInsets, for which you can set leading and trailing insets instead of left and right.&lt;/p&gt;

&lt;p&gt;Besides that, there were lots of places with repeated errors in the code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;for UILabel it was set: textAlignment = .left or textAlignment = .right. Depending on the scenario, you have to use textAlignment = .natural or set textAlignment in accordance with the value of effectiveUserInterfaceLayoutDirection. In case you use .natural, if LTR-orientation is set for the user, the text will be aligned to the left, and if RTL – to the right;&lt;/li&gt;
&lt;li&gt;in some places constraints left and right were used instead of leading and trailing;&lt;/li&gt;
&lt;li&gt;a couple of screens were made up with the help of PinLayout and they did not support RTL.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Custom UI elements
&lt;/h3&gt;

&lt;p&gt;It happens that the developers have done everything right: they used leading and trailing so that everything works right if suddenly there is RTL. In some places of the project we have faced the bugs connected with it. This is what happened to the field of phone number input:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm1r1r86qqssxuc9tg8q0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm1r1r86qqssxuc9tg8q0.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What the mistake is: iOS functioned right – it automatically reversed the field for phone number input because we used leading and trailing constraints in the layout. But we need this field to be always displayed from left to right, because phone numbers are always written from left to right. The easiest way was to fix the fields with semanticContentAttribute = .forceLeftToRight.&lt;/p&gt;

&lt;p&gt;It’s funny how the input for entering SMS code broke. As you enter, the numbers appear in it as usual (from left to right), but the dots in the background disappear from right to left. On the screenshot, 3 numbers have been entered and one dot remains visible – under number one.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd5ott0h505s52bf0l03y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd5ott0h505s52bf0l03y.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What the mistake is: placeholder dots contained in UIStackView. The stackView automatically reverses when RTL is enabled, but you can also set up semanticContentMode = .forceLeftToRight for it.&lt;/p&gt;

&lt;p&gt;On the Half &amp;amp; Half pizza, rounded scroll indicators have been mirrored and now they are in the center of the pizza:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiqk3jwdy16vgrh6020c5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiqk3jwdy16vgrh6020c5.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What the mistake is: the scroll indicators had leading and trailing constraints. iOS inverted them. But the screen of the pizza made from halves is universal for RTL and LTR, that’s why there’s no need to reverse anything in it. We changed the constraints to left and right.&lt;/p&gt;

&lt;p&gt;In the tooltip, the arrow should move to the left:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgg9hm460uf2v3ju6yjn0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgg9hm460uf2v3ju6yjn0.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What the mistake is: sourceRect, from which the arrow is drawn, was calculated manually. Now we make different calculations for LTR and RTL.&lt;/p&gt;

&lt;p&gt;Our SegmentedControl is custom. It looks alright, but the segments in it must change places.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpil1eqx5lhbn8lalfsxs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpil1eqx5lhbn8lalfsxs.png" alt="Image description"&gt;&lt;/a&gt; &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftevqfpkvw27stfvg627p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftevqfpkvw27stfvg627p.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What the mistake is: for each segment, the frames were calculated. We added alternative calculations for RTL.&lt;/p&gt;

&lt;h3&gt;
  
  
  Collections
&lt;/h3&gt;

&lt;p&gt;Some collections, for example, toppings for the product, were not mirrored. On the screenshot, empty slots in the collection should be at the bottom left, not right.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F45kqaxhw2wwnjjw1yu8x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F45kqaxhw2wwnjjw1yu8x.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Other collections, for example, categories in the menu, were mirrored (they became aligned to the right). But the elements in them were displayed in the wrong order. On the screenshot, “Pizza” category should be the first, i.e. the rightmost.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsqncpnhu32937h123obn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsqncpnhu32937h123obn.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the screen with the products to be bought for dodocoins, the elements in the collection are at the right places, but it is the last element that is shown by default. In this collection, the first category of goods is drinks. If you scroll the categories sideways, the drinks will be at the right place.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo4r7w4yzaeott9lbpap7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo4r7w4yzaeott9lbpap7.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For all the problems with collections we had one solution – to use UICollectionViewFlowLayout which supports RTL. For UICollectionViewFlowLayout to be mirrored, you need to create a class inherited from UICollectionViewFlowLayout, and to redefine the property of flipsHorizontallyInOppositeLayoutDirection. By default, it is false, while it has to be true. Then collections with this layout will be mirrored.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class RTLSupportedCollectionViewFlowLayout: UICollectionViewFlowLayout {
    override var flipsHorizontallyInOppositeLayoutDirection: Bool {
        true
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Icons with a direction
&lt;/h3&gt;

&lt;p&gt;Another topic is pictures. Some of them have to be mirrored, and some of them don’t. It’s a science!&lt;/p&gt;

&lt;p&gt;Let’s have a look at the screen of delivery method selection. The courier on the first icon should be mirrored because the icon shows the direction of motion. That is, the courier should be going towards the user, and not away from him.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6r3zkm26tvu71ribcbmr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6r3zkm26tvu71ribcbmr.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The knife and fork don’t need to be mirrored. We have checked, in Arab countries they hold a knife in their right hand.&lt;/p&gt;

&lt;p&gt;On the next screenshot, near to the delivery address, the arrow wasn’t reversed. It needs reversing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9lhojpr25v5fyuqbqg72.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9lhojpr25v5fyuqbqg72.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The star on the widget needs reversing too, because people who choose Arabic, will be looking at the widget from right to left. And the star should meet the users’ view with its face and not with its back.&lt;/p&gt;

&lt;p&gt;There’s no need to reverse the pizzas as it is a copyrighted photo. The photographer created a composition and things like that. Such photos should be left as they are.&lt;/p&gt;

&lt;p&gt;At this stage, it is necessary to have a look at every single picture in the app and to decide if it needs reversing or not.&lt;/p&gt;

&lt;p&gt;For the icons which need inverting you can set a special setting:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let image = UIImage(named: "some-image")
imageView.image = image?.imageFlippedForRightToLeftLayoutDirection()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code checks the selected orientation and tells imageView to reverse the picture.&lt;/p&gt;

&lt;p&gt;In Apple's documentation you can find a code which mirrors the picture itself via NSAffineTransform. But we decided not to use this option.&lt;/p&gt;

&lt;p&gt;Not every picture can be automatically mirrored. For example, we have pictures with Dodo’s logo (orange letter D and a bird fitted into it). If you mirror it, the logo will be reversed – which is wrong.&lt;/p&gt;

&lt;p&gt;The pictures which cannot be automatically mirrored, have to be redrawn and put into the project. For this asset you can set up the localization:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fifxk4ffdg1ointxl7n87.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fifxk4ffdg1ointxl7n87.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Badges on the photos in the menu
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F17szjtru45m8mwcwa305.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F17szjtru45m8mwcwa305.png" alt="Image description"&gt;&lt;/a&gt; &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frwqprsywy25b94by4qbe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frwqprsywy25b94by4qbe.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Badges on the photos should be moved to the other corner. In RTL they should be located in the left upper corner of the photo.&lt;/p&gt;

&lt;p&gt;Now the badges are a part of the photo. We are planning to make them drawn in the app. Then we will be able to change their location when RTL is enabled. In the meantime, this is another reason not to reverse the photos.&lt;/p&gt;

&lt;h3&gt;
  
  
  Animations
&lt;/h3&gt;

&lt;p&gt;All animations have to be doublechecked too. We have few of them, but the ones we have function incorrectly in RTL.&lt;/p&gt;

&lt;h4&gt;
  
  
  Add to Cart Animation
&lt;/h4&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/qkj6Kuq6wWI"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;One of the things which changes its direction when RTL is enabled is UITabBar. The first tab will be located on the right, and the last one – on the left.&lt;/p&gt;

&lt;p&gt;Let’s take a look on how Add to Cart animation works. The item always goes to the rightmost tab of the tab bar. While it should go to the cart.&lt;/p&gt;

&lt;h4&gt;
  
  
  Order Status Animation
&lt;/h4&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/YCu2-ImsxCg"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;The loading animation should go the other way.&lt;/p&gt;

&lt;h3&gt;
  
  
  Third party
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz403iwonzgbfoyowqs49.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz403iwonzgbfoyowqs49.png" alt="Image description"&gt;&lt;/a&gt; &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Floj2tzaes6m98dq81yxk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Floj2tzaes6m98dq81yxk.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Don’t forget to check third-party services. This is what we have in our case.&lt;/p&gt;

&lt;p&gt;There is a text on the broadcast from Ivideon. This text is center aligned, and the text itself can be changed in the broadcast settings. So, there are no problems.&lt;/p&gt;

&lt;p&gt;But the chat and captcha are not at all adapted for RTL. We won’t be able to fix it ourselves, which means we will have to discuss potential improvements with the SDK developers.&lt;/p&gt;

&lt;h3&gt;
  
  
  WebView
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fffyilin0x90jsvozm7z6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fffyilin0x90jsvozm7z6.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We have WebViews in the project. They open links to our website, Google docs, social networks, etc.&lt;/p&gt;

&lt;p&gt;You don’t need to do anything with the WebViews as such, but you need to remember to attach links to the localized pages.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trying to understand, what is a bug, and what is a feature
&lt;/h2&gt;

&lt;p&gt;When we enabled RTL in our app for the first time, our brains broke.&lt;/p&gt;

&lt;p&gt;It is very difficult and unusual to perceive. Everything looks weird and you don’t understand if it looks bad because it is unusual or because it is broken.&lt;/p&gt;

&lt;p&gt;And something looks fine, and you don’t understand if you just got used to RTL, or if it looks OK because the element is displayed in a wrong way and it is aligned from left to right.&lt;/p&gt;

&lt;p&gt;There were a few places where we first tensed up, but then it turned out that everything was fine. In this section, we will talk about such places.&lt;/p&gt;

&lt;h3&gt;
  
  
  Input fields
&lt;/h3&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/yjb3vyydMd8"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;The first one is input fields.&lt;/p&gt;

&lt;p&gt;We switched the app to RTL and started clicking on the input fields to write something. The text appeared on the wrong side of the caret, and the caret itself didn’t move. We got upset that we would have to fix it.&lt;/p&gt;

&lt;p&gt;It turned out that if the input field is in RTL mode, and you start typing English letters, they appear to the left of the caret, while the caret itself remains in place.&lt;/p&gt;

&lt;p&gt;But if you start typing Arabic letters, they appear to the left of the caret, and the caret itself moves to the left.&lt;/p&gt;

&lt;p&gt;That’s the way it should be.&lt;/p&gt;

&lt;h3&gt;
  
  
  Promo-code input field
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhn2htdzzju44lrroestq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhn2htdzzju44lrroestq.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our promo-codes contain only English letters. English letters are spelt from left to right. This means, that the input field has to be aligned to the left.&lt;/p&gt;

&lt;h3&gt;
  
  
  Plurals (.stringsdict)
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdwj9bkqy4c6f0j2fs89w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdwj9bkqy4c6f0j2fs89w.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On top of that, all the plural strings got broken in our app.&lt;/p&gt;

&lt;p&gt;At the beginning of this article we told about two kinds of pseudolanguage in the project. It turned out that the one reversing the letters was breaking plural strings.&lt;/p&gt;

&lt;p&gt;The bug occurs only during debugging. In production with Arabic lines everything works fine.&lt;/p&gt;

&lt;h2&gt;
  
  
  We are glad it’s not all broken
&lt;/h2&gt;

&lt;p&gt;We didn’t need to modify anything in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;UINavigationBar (in Android, for instance, all “Back” arrows in the navigation bar got broken);&lt;/li&gt;
&lt;li&gt;UITabBar;&lt;/li&gt;
&lt;li&gt;UIStackView;&lt;/li&gt;
&lt;li&gt;UIPageViewController;&lt;/li&gt;
&lt;li&gt;Swipe to delete in tables;&lt;/li&gt;
&lt;li&gt;separators in tables (in our case some separators have an inset from the screen border only on one side. It is this inset that should be mirrored. On Android it didn’t work automatically);&lt;/li&gt;
&lt;li&gt;input fields (UITextField, UITextView, UISearchBar);&lt;/li&gt;
&lt;li&gt;animations of UINavigationController (push/pop) and swipe to go back.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All the above mentioned elements are reversed automatically when switching to the RTL language: changes appear in the order of tabs, stack elements, the direction of UINaviationController animations, etc.&lt;/p&gt;

&lt;p&gt;It was a nice surprise for us to find out that these didn’t require any modifications either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;stars to evaluate the order;&lt;/li&gt;
&lt;li&gt;SDK for stories.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Dealing with obscure things
&lt;/h2&gt;

&lt;p&gt;During the localization of an app into Arabic, it’s not enough to adapt the UI so that it is displayed correctly for RTL languages. It is also important to take into account some other features of the language and culture.&lt;/p&gt;

&lt;h3&gt;
  
  
  Eastern Arabic numerals
&lt;/h3&gt;

&lt;p&gt;In Arabic, Eastern Arabic numerals are used to represent numbers. They are different from what we are used to:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzf6kgphwx0ht1xy3xvmw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzf6kgphwx0ht1xy3xvmw.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are a lot of places in the app where numbers are used: prices, grams, phone numbers, etc. In almost all the places you need to use Eastern Arabic numerals, but there are exceptions. For example, in price tags and phone numbers you need to use Eastern Arabic numerals, but for bank card numbers only Western digits are used.&lt;/p&gt;

&lt;p&gt;You can convert the numbers with the help of formatters:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;extension String {

    var toLatnDigits: String? {
        let numberFormatter: NumberFormatter = NumberFormatter()
        numberFormatter.locale = Locale(identifier: "en_US")
        guard let latnNumber = numberFormatter.number(from: self) else { return nil }
        return numberFormatter.string(from: latnNumber)
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The numbers themselves are always written from left to right, including phone numbers.&lt;/p&gt;

&lt;p&gt;By the way, in some cases, iOS proactively converts Western numbers to Eastern Arabic ones. For example, if this string was in Arabic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"resendCodeInDSecWithParam" = "Resend code in %d sec";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then in the formatted string you would get the number of seconds written in Eastern Arabic numerals:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let string = String.localizedStringWithFormat(
    NSLocalizedString(
        "resendCodeInDSecWithParam",
        bundle: bundle,
        comment: "Signup screen"
    ),
    Int(self.seconds)
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember to check the input fields which require the input of numbers. In our case, for example, in the field for change at the checkout you can’t enter anything but Western digits.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7x8dqjcl3yn8p4v16f5j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7x8dqjcl3yn8p4v16f5j.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Starting to use Eastern Arabic numerals in the app is a big problem, which concerns not only the apps, but also the backend. We have decided not to support Eastern Arabic numerals in the first release of the app with Arabic language support. To fix the use of Western digits in the application, we use a special locale format: Arabic with Western digits (ar-u-nu-latn).&lt;/p&gt;

&lt;h3&gt;
  
  
  What to write on which side
&lt;/h3&gt;

&lt;p&gt;Don’t forget to check what is where: units of measurement are written to the left of the number ( ١٠٠ غ), and the currency sign is written to the right (١٠٠$).&lt;/p&gt;

&lt;p&gt;If you specify the time interval, then the end time is written on the left, and the start time on the right. For example, if a pizzeria is open from 10:00 to 18:00, it is written as follows: 18:00 - 10:00.&lt;/p&gt;

&lt;h3&gt;
  
  
  Words in another language
&lt;/h3&gt;

&lt;p&gt;If there are foreign words in the Arabic text, they do not need to be written backward. No need to reverse the names in Russian and English. For example, PayPal, Apple Pay.&lt;/p&gt;

&lt;h3&gt;
  
  
  Punctuation
&lt;/h3&gt;

&lt;p&gt;In Arabic, some punctuation marks and other symbols differ. For example, they use a different percent sign ٪. In our app, we have a picture with a percent sign, which we use on the screens with discounts and promotions. This is exactly the case when the picture cannot be just mirrored, it needs to be replaced with another one, with a different percent sign.&lt;/p&gt;

&lt;p&gt;The European sign % will be understandable, but using the Arabic one is preferable.&lt;/p&gt;

&lt;p&gt;Localization of the percent sign can be done via strings localization or using a formatter:&lt;/p&gt;

&lt;p&gt;Not like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;label.text = String(localized: "(percentComplete)% complete")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;label.text = String(localized: "(percentComplete.formatted(.percent)) complete")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also, it is not customary to use signs denoting the number (№ and #) in Arabic. We, for example, use such signs to show the number of order in the app.&lt;/p&gt;

&lt;p&gt;Familiar signs are reversed: ، ؛ ⸮.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to adapt pictures
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmr7e7ou0v1askn3c7k26.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmr7e7ou0v1askn3c7k26.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To make pictures of people work the way you expect them to, i.e. attract attention or arouse warm feeling, users should associate themselves with the characters in these pictures.&lt;/p&gt;

&lt;p&gt;If you want to achieve this effect, consider using images of Middle Eastern audiences rather than Europeans. For example, you’d better avoid using characters in winter clothes and ear-flapped hats.&lt;/p&gt;

&lt;p&gt;We are used to the idea that localization means adaptation of an app to a specific language. Recently, we have added the option of changing the language manually in the Dodo Pizza app. And while we were discussing images for the UAE, we came to the conclusion that we need to be able to show different illustrations depending on the selected country, and not on the selected language. And this is what we did for the UAE.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvis2dak16xcqjbdu6grn.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvis2dak16xcqjbdu6grn.jpeg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The code which inserts the desired image depending on the current country can be reused in other countries, too. For example, it can insert winter images where they are relevant:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgkwsgasgp2gv19kr8ozl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgkwsgasgp2gv19kr8ozl.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Deciding on how to test
&lt;/h2&gt;

&lt;p&gt;There are a lot of changes, and all of them are interface ones. We will test the RTL orientation via snapshot tests. For snapshot tests, we use the SnapshotTesting library. There you can take a snapshot by setting the desired orientation through traits:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let rtlTrait = UITraitCollection(layoutDirection: .rightToLeft)
assertSnapshot(
    matching: sut,
    as: .image(traits: rtlTrait),
    testName: QuickSpec.current.name
 )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For convenience, we have written a helper to check several snapshots for LTR and RTL with one test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;itShouldSnapshot(
    configs: [.default, .rightToLeft],
    matching: sut,
    configuration: { sut in
        let product = OrderHistoryViewModel.OrderProduct(
            name: "BBQ Wings",
            size: "8 pcs",
            imagePlaceholder: .imgPizzaGift,
            category: .pizza
        )

        var viewModel = OrderHistoryViewModel.PastOrderItem()
        viewModel.name = "BBQ Wings"
        viewModel.totalPriceString = "AED 26"
        viewModel.products = [product]

        sut.configure(viewModel: viewModel)
    },
    perceptualPrecision: precision,
    size: { sut in
        sut.sizeFitting(width: 320)
    }
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A bit later, we upgraded it to check the dynamic type and the dark mode.&lt;/p&gt;

&lt;h2&gt;
  
  
  Making conclusions
&lt;/h2&gt;

&lt;p&gt;iOS makes the process of an app localization for RTL languages much easier. We can say that all we need to adapt in the app is the technical debt which has shot.&lt;/p&gt;

&lt;p&gt;Conclusions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you make the layout correctly from the start, the rest will be done for you by iOS.&lt;/li&gt;
&lt;li&gt;The fewer custom elements you have, the better it looks in RTL.&lt;/li&gt;
&lt;li&gt;The work doesn’t end with layout and translation. There are a lot of cultural peculiarities which are important to remember, too.&lt;/li&gt;
&lt;li&gt;The direction of the text is a feature of the selected language, but there are things that depend not on the language, but on the country. For example, illustrations in the app.&lt;/li&gt;
&lt;li&gt;Not all pictures can be mirrored automatically. Something will have to be redrawn.&lt;/li&gt;
&lt;li&gt;We are very used to LTR, so it is better to show the finally adapted app to some native speakers of Arabic, so as not to miss anything.&lt;/li&gt;
&lt;li&gt;Snapshot tests speed up the development and help you make sure that you haven't broken anything along the way.&lt;/li&gt;
&lt;li&gt;RTL support is not a one-off event, but a continuous process. Every new feature has to support RTL. So, you have to tell your team what they need to pay attention to when designing, make checklists for testing and instructions for developers.&lt;/li&gt;
&lt;li&gt;The UAE is a multinational country. You can’t have the app only in Arabic, English needs to be supported as well.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To discover more about Dodo IS and top QSR innovations in Dodo Brands, follow us on &lt;a href="https://www.linkedin.com/showcase/dodoengineering" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; and &lt;a href="https://medium.com/dodoengineering" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>ios</category>
      <category>swift</category>
      <category>localization</category>
      <category>rtl</category>
    </item>
  </channel>
</rss>
