 co, hello and welcome. thanks for coming. My name is piotr google i i I'm gonna tell you more about our Android development practices at jobbox. The agenda for today's talk is pretty straightforward. The numbers on the right are minels dedicated to each subject. Now a little bit about myself. I'm native to Kraków Poland and I also received my Ph.D. Jestem ingeniolem software z Dropbox w ciągu miesiąc. Przed Dropbox byłem ingeniolem mobile w EL, robił głównie dźwięk i dźwięk, a poza dźwięków dźwięków. Ja też stworzyłem startup, który zazwyczaj robił bardzo dobrze, ale zauważył tracją. Fakt fajny z mną jest, że skończyłem 7 zespołów w total, i to jest właściwie to, jak mój angielski historie zaczęło. Byliśmy w 2009 roku z jednej ręce Android wskazane na marketach. Chciałem teraz zapytać, jak wiele oficjalistów DrobBox jest. O, jestem zadowolony, żeby zobaczyć to. To, co robimy, nie jest tylko klucz na dół dla swoich samochodów. Jesteśmy robiąc najmłodsze, najmłodsze, najszybciej kolaboracje platformy. DrobBox zaczął, zazwyczaj, na prostą drogę połączyć ludzi do swoich devices. i wytworzyliśmy się w zespołu, które zbierają ludzi do najważniejszych informacji, aplikacji i kolegów. Wydaje nam już 500 milionów ludzi, którzy używają drogów, wokół globy. Jedną rzecz, którą możecie nie znać, jest, że wszystkie tych ludzi zbierają drogów w 8 milionów biznesów. Naszymi zainteresowani złożyli ponad 3 milionów zespołów. Więc, jak wiele z tymi drogów masz na Androidach? O, tak! I jak wiele z tymi drogów zbierają drogów? Okej, możemy rozmawiać o tym później. Jak w tej grupie jest już złożyło ponad 1,5 milionów zespołów i jest wskazywana na 30 languów. To jest okręgło różnych Android-dźwięków, które są przyjemne na marketach. Wydaje nam się, że to może być bardzo zespołowe, ponieważ niektórzy uważają, że jest już ponad 20,000. Quite different than iOS, isn't it? Even during my few days here in India, I've spotted so many Android devices that I've never seen before. Each of these devices can have completely different characteristics of features such as architecture, GPU support, neon support, OS version, OS modifications, etc. To oczywiście oznacza wiele trudności. Teraz chciałbym zazwyczaj skończyć na naszej sklepie w DrabBox. Nie mamy niczego jak jedna wielka Androida. To może działać dla małych aplikacji, które skończą tylko jedną rzecz, ale tu jest dużo skalabilitacji i problemów z priorytizacją, kiedy jest to nikt ważnych specydentów, które pracują. To jest dlatego, że mamy kluczne platformy, feature-orientowane teamy i kluczne platformy mobile-infrastructure team. Co z tym pomoże? Są wiele, ale pewnie najważniejsze są produkty fokuse, komunikacji i konsystencji. Natomiast to jest zawsze sklepem. Kolejna platforma, czy zrozumiałek, distributowała akurat feature-team, to jest okazja, że nie ma konsystencji technicznej, a nie ma doplikacji. Inny potencjalny problem poszukiwania, które nie są związane z żadnych akurat feature-team. Tak, że oni mogą się wydarzyć bez przyjaciół. Co z tym pomoże? Jak słyszałem na przednią slajdę, niektóre klienty platformy specyficzne, są akurat dilutowane akurat feature-team i mają potencjalny pomysł. To jest dlatego, że tworzyliśmy GILS, które są po prostu grupy ludzi w drodze, które pracują, czy są interesujące w technologii. Przedmiarów są Android-naginera lub Windows-client-naginera. Po prostu, by ci podjąć idea o co mogą być responsiby do tego, GILS potenuje platformy specyficzne, zamiast komunikacji, GILS potenuje dokumentację, ale mogą też pomóc z klientami platformy specyficznych czy tworząc i podjąć reżysersy, które mogą zorganizować konferencje internalne, po prostu wszystko, które pomożą zainteresowanie. Byliśmy również w życiu tak zwanej kwalitnej rotacji. To jest tak, że inżynierów na drużynie spędząc 1 tygodnie eksklusywnie na jednej z odpowiednich responsibilitów. Pierwsza priorytja to wszystko, w przyszłym tygodniu. Światowe SLA to 2 godziny. Priorytja to znaczy, że nie tylko sądzono priorytje, ale także projekty, i aplikowane. Pierwsza responsibilitja jest protektować twojej drużynie, w sposób, w jaki się skończą i zainteresowanie. To zwanej kwalitnej komunikacji, e-mail alia, szlak channelu, etc. W tym sposób, wszyscy inni mogą pozostawić się na regularnych projekty. Niestety, aby zrobić any progress on someone's normal project, any breaks in action can be used as a discretionary time to improve the state of the world by fixing high priority bugs, polishing UI components, adding prototyping, analytics, vlogging, whatever you think makes the most impact. Ok, so now what happens when a new issue is reported and how can we make sure it's gonna reach the right team. The mobile platform team is responsible for monitoring incoming mobile issues and routing them to the future team. Whoever is doing quality rotation on the future team in a given week will take it from there. A very important part for a new engineer at Dropbox is our onboarding process. It's called residency program and includes many talks and training that concerns various areas of the company. But on the technical side new hires are usually able to come up with a first commit on the first day. We keep a special pool of easy tasks that are used to teach people about the code base and the workflow. Usually no more than a few lines of codes are needed to resolve them. Fixing bugs is generally speaking a great way of learning as it requires a lot of reading and understanding, but not much code. After such warm-up a new engineer is given a residency task. This is a bigger self-contained project that allows to become familiar with the code base and create something substantial. New hires have also the mentors assigned who are there to help in case of any questions or difficulties. Now I'm gonna tell you about our actual development process. We have a single repository for both iOS and Android Clients. This approach promotes code use and consistency and this is especially important when there is native code involved and many scripts and tools. That can be sure. For design docs, retrospectives and generally speaking collaboration we use our in-house project called paper. Anyone heard of it? Oh nice. I highly encourage you to check it out and compare to other solutions. I personally love it and it does syntax coloring. We also make heavy use of Slack. Not only for communication but also to nag people about outstanding tasks and to set reminders. Slack bots are simple to write and powerful so it's a really good way of automation. Another tool we use for collaboration is Fabrikator. It used to be an internal tool at Facebook and now it's available under Apache license so everyone can use it. Fabrikator integrates with Git, Mercurial and subversion. Fabrikator has a command line interface called Arcanist. I've listed a few most frequently used commands which can be represented on top of either SVN, Mercurial or Git. The descriptions I've listed concern Git repository. To keep our UI consistent we've created our own pattern live for components like buttons, selection controls, text fields, spinners, snack bar, dialogues, menus etc. This is cool for both engineers who can copy and paste XML without much thinking but also for designers who can drag and drop an asset into a mock-up easily. There's also a very useful Android Studio plugin called Android Material Design Icons Generator. It's so simple to use that I think it doesn't require any further explanation than a screenshot. One very useful developer option is showing layout boundaries which is helpful not only for debugging but also for cleaning up layouts and the code. We all know emulators are helpful. No need to carry multiple test devices in order to simulate different conditions etc. But it's worth to remember that sometimes emulator behaves in a much different way than the actual device. For instance, even if you disable camera in the emulator hardware profile for some reason the following code will still return true. This is why it's very important to keep an array of diverse devices not just the shiny new flagship ones. If something in the code or app behavior looks suspicious we want to flag it as soon as possible. As this way, it's much easier to identify the cause. This is why we use static analysis and preconditions checks. One great thing about static analysis is that it helps to detect mistakes at a super early stage. Before you even try compiling the code before anyone else gets involved. So we make heavy use of it. We use both lint, non-null and check-for-null annotations extensively. Lint is especially useful for the cases when you should do something either always or never. Here's a super simple example of these two annotations I mentioned in the code which we use for both fields, patterns and return types. And this is how you actually can perform and lint check from Android Studio for single file module and the whole project. One class of member fields that are tricky to annotate references to the UI component. Well, they obviously can't be null with respect to the object lifecycle. They can't be initialized to the constructor. We can't make them final. But they are non-null with respect to the activity lifecycle. Using MVP can help here a bit. Android resource IDs use integers to identify both strings, graphics, colors and all other resource types. So it can be pretty confusing because at the end it's still an int. Using resource type annotations we can specify whether a given integer should be interpreted as a layout ID, string ID, gerable ID or something completely else. The example lint failure that I've pasted is quite interesting as the code will compile and it will even somewhat work except that the color will be slightly weird. Depending on what integer r.color.myblue ends up to be. Guess what? For me the color turns out to be blueish. So without lint it would be very difficult to tell the code was completely wrong. Another very useful annotation is called super. It requires every overriding method of the annotating method to call the annotated method as well. Which is super helpful super useful for life cycle methods such as on destroy. That may need to release some native resources. Since lint rules are easy to add once you make some mistake you can often add a rule and protect others from making it. Similarly when we add a new abstraction we can add a lint rule to protect others from the use of the older fraction. We check against a number of conditions listed here. So let's say you auto-imported some precondition class that's not quite from Guava. This is something honestly quite easy to do by accident but well lint's gonna complain which is good. Here's another list of conditions, sample conditions we check again. One important and useful one is detecting the use of buggy code say in support lib. So as an example fragment transitions in the v23 support lib had a bug where they crashed on software render emulators. So we added a lint rule that won't again use of that buggy code. And this is the code adding a sample custom lint rule. This is the one that protects us against mistaken import. Well it's pretty straightforward and simple so it doesn't take much time to do it. Using assertions consistently also helps a lot with debugging. On top of standard assertions from Guava we've developed our in-house assertions that failure when they detect things like blank string incorrect class casting running given code not in the main thread etc. Using such assertions allows us also for neat assignments like the one in the bottom. Well this one seems obvious as it's Android 101 but if you play with a few random apps from play store it will become less obvious. Well according to Stack Overflow adding Android config changes like is a glorious solution or even better log display in the portrait mode. In fact one time I had nothing to do on the plane so I tried launching all the mobile apps that I've had installed and checking which are of them rotate and which are of them are logged in portrait. I was so surprised people do this that often. In rotation it's not the only config change to remember about especially now having multi window mode. Handling config changes yourself it's still a legitimate solution as long as you really know what you're doing instead of facing the first solution you find on the internet. Now look at the following example. Is it a mysterious device specific problem? Nope It does Android config changes line in action. Most of the time this is the right way of handling the configuration change. There is one inconvenience though that prevents people from doing it. If you want to save an object that is not passelable this requires extra boilerplate code. Bundles are also not designed to carry large objects such as bitmaps. This is when the headless fragments come to the rescue. Headless fragments are fragments without user interface. Because of that they have one very useful feature. Namely they can be retained by the fragment manager across the configuration change and then restored after it happens. This means they can carry a stateful object to the new instance of your activity. There is one caveat though because very often this leads to leaking the context when people try to put too much. Mobile code once released is going to live forever. If something goes wrong rolling out an update takes a lot of time compared to the web development and not everyone is going to install the update anyway. This is why we need a way to control features from the backend. We get almost all of our features and enabling new features is completely decoupled from the release process. This way everything can live happily in master and we avoid the cost of integrating feature branches. We have an in-house product called Stormco. For those of you who like Florida of the Rings Stormco is yet another name for Gandalf. In our case Stormco allows for a fine-grained control of a population and it consists of three components. Feature is the basic object of Stormco. Typically it is a product feature let's say select all menu option. That you want to expose to the users or hide for some and variants add variations of this product feature. This can be some V1, V2, V3 for an A-B test or simply on and off if it's just for gating and not A-B testing. And finally a population is a collection of entities such as users with the specific up-version install, team devices so on that you expose features to. And this is a sample usage in the code so it's really simple tool. English is quite concise language which means the strings you add will probably look much longer when translated. This is why we always want translators when the space is limited and caption or label should be made short. We put that one in the comments like please keep short. The obvious rule is also to always use placeholders for numbers in the strings even if they are located at the very end. As in some languages they may need to appear at the beginning. It's also a mindful and widely practice to put an explanation of the broader context in the comments to avoid ambiguity and awkward translations that I see daily in some Android apps. Sometimes there are also small details in the strings that often get ignored by translators, like one UTF character for triple dots being replaced with three individual dots in the translation. Moreover, American date format won't be looking very natural in Europe. This is why it's usually a good idea not only to pass the local parameter when formatting date but also to use one of the predefined formats whenever possible as they are guaranteed to be localized correctly. Keeping the code base clean is a part of our DNA and therefore we have a few important rules. No code can sneak into master without passing a code review. Also means no code violating link will be add out. We don't need to worry about code formatting conventions as the code will be auto-formatted when submitting D4CR. There is one obvious goal of code reviews which is to find bugs as soon as possible. But there are lots of other often very subtle benefits such as promoting openness in the organization as everyone can go through code reviews, chime in, commands, help. It also raises team standards and boost teamwork. Besides, it's a wonderful way of learning because it's highly contextual. As I mentioned earlier, every single change needs to be reviewed, no exception. You can select as your reviewer either a specific person or a group. So the flow is pretty straight forward. I check out a new branch master for my new feature. Whenever I'm ready I do git commit and active. If I'm lucky and I pass all the link checks, it ends up in the code reviewing system in the differential that's part of the indicator. Whenever there is some feedback and usually reviewers do have feedback I introduce changes, I use ArcDeep again to submit updated this and whenever I get my deep accepted I type ArcLand and the change ends up in the commit queue. So if everything is fine it's gonna end up in MasterToon. Landing 2 even perfect non-confliktic divs at the same time can still end up in breaking the build. This is why we introduced commit queues so that landing changes happen sequentially and tests are being run against the most scanned versions each time. And this is how we achieved Evergreen Master. Seriously, I don't remember the last time when the build was broken. Now a little bit about testing. We are pretty standard here as we do both unit test and UI test. I was just wondering how many of you are using Espresso? Oh, that's quite significant number. And how many of you don't have any flaky test? That's what I thought. On top of automated testing we do also a first of manual testing using a number of test devices and test accounts. For unit test there are two helpful annotations. UI test denotes that the annotator test should only be called on the UI thread. And visible for testing one that visibility has been increased for the sole purpose of testing. Well, it will take another presentation in the workshop to cover Espresso testing. Actually it was covered in the previous presentation but I printed some sample codes. I guess there's no need to comment on it. One aspect that is quite easy to forget about is making the app accessible to the users who have visual or age related limitations. The good news is Android already has a number of options to offer to improve the experience for such users. However it remains developer's responsibility to make sure the app plays nicely with all of these accessibility settings. Sometimes a few small changes in the app can make a really big difference for some users. This is why I really encourage you to go to the accessibility settings page and audit your apps. So now a little bit about how we ship the code. We do database releases so it's always known and clear when the next release is and when code phase is happening. It makes the life easier for everyone. Dogfooding is a very important part of the process. We ship the last green build from master internally on daily basis which goes through the place of alpha channel. This means getting initial feedback for developers within 24 hours of landing to change. Pretty cool. Many issues are there for code and fix before the public ever sees them. The next year our weekly releases to all users that check get early releases box in the app settings and finally every two weeks we release to play store. Understandably we do stage rollouts when we start with a very small percentage of users like half percent and if everything looks smooth we bump it gradually. There are a few constraints regarding alpha and beta channels. Firstly user needs a google account to join a test. Understandably also alpha and beta apps cannot be reviewed. Also version number needs to make sense. We maintain a dedicated flag channel that posts updates about events such as branch cuts, office releases, place to release, percentage change and so on. So it's a one-stop shopping for learning all stages. Once the release candidate branches cut generally speaking no cherry picks are allowed. This is a benefit of frequent releases. You can always wait with your change for the next train. If something turns out to be broken really badly on the release branch the default option we have is to reverse the offending commit instead of applying any forward fixes even if it appears to be one line or one character fixed. When the app gets released we monitor a number of metrics such as user feelings and complaints in play store and those send through our feedback channels. We also check analytics for any abnormal jobs in feature usage. That may indicate some technical problems users have. Each release is evaluated so that we can improve the next time. Since adding new features is the coupled from the release process and we don't use release as the features get rolled out as gated features get rolled out gradually we are using in-app channels to inform users contextually about what is new. Another benefit of contextual onboarding is its much better effectiveness. That was it. Thanks for having me up here. I'm happy to take any questions if you have them. Here. You said even if you have a small fix you instead roll back instead of doing that fix could you explain why? Well, because it sometimes is very deceitful something that looks like a super simple fix can break things even worse. I would say the primary reason is we don't want to delay the release and even applying such small fix i nie ma czasu na otwierać testy, więc jedna z zamiarów nie będzie, gdy nie ma sensu, że wytrzymają się na całym komitach. Więc tak, jeśli to jest łatwe do powrotu i jest extremnie trudne do wyciągania komitów, to będziemy do powrotu. klasy, ale to jeszcze nie jest wystarczająco dla nas, więc mamy nasz klas DBX asynktaski, który pozwala ci z sukcesu kontekstu w dźwięku latach. Więc to, co ma to zrobić, to wytrzymać wszystkie parametry w konstrukcji, więc nie jest bardziej genericzne. I to wytrzymało ci z decydującym DBX asynktaski, czyli innego klasu, więc to nie nie jest poważnie brak, więc nie otworzycie kontekstu klasu. Więc to wytrzymało. Przede wszystkim można użyć klasy, ale w tej razie jest jeszcze nie zrozumieć, że musisz użyć asynktaski, żeby podróżować tych zrębnych sytuacji. Hej, więc wy rozmawiałeś z komit, Kiu. Czy to coś, co jest częścią fabrykatora, czy to coś, co znalazłeś w domu? Vałka jest w porządku, więc bądź kolegówilipertę, że to jest nagrywanie, to jest dziewczynna. Więcensible jest jedna część tej pory? You can integrate it with our肈. Ok, You can enable it. Co about your releases and how frequent do you follow Agile or print? Jak się wytrzymać, jak się na to sklepuje w pewien sposób? Pytasz, jak na to sklepuje sprawa? Tak. Jak się sklepuje? Tak, jak sprawa? Tak, jak sklepuje? Tak, tak, tak, tak. Jak to sklepuje? Tak, jak sprawa? Tak, jak sprawa. Przed chwilą. Cześć. Chciałem zrozumieć trochę bardziej o jak się zrozumieć o dźwiękach. Cześć. Chciałem zrozumieć trochę bardziej o jak się zrozumieć o dźwiękach. Powiedziałeś o dźwiękach. Tak, tak. Więc o dźwiękach na dźwiękach. Tak, tak. Bądź, że jakaś dźwiękka jest przyzwyczajena na dźwiękach, to też przyzwyczajemy pewne problemy, czy to, czy to, czy o dźwiękach. Tak, tak. Chcielibyśmy zrobić to jak na dźwiękach. Ale jakaś dźwiękka nie jest jedna opcja, to możemy jeszcze wyjściać na dźwiękach. To właściwie przyzwyczajesz na dźwiękach o dźwiękach. I tak, możemy jeszcze wyjściać na dźwiękach, które są na podstawie informacji, czy to, czy to już jest odbywane, czy nie, to powinien być wyjściało. Więc to jest bardzo łatwo. Okej, a ten dźwięk jest, jak, to jest kontrolna na dźwiękach, jak i na dźwiękach. Wsze z nią, tak? Tak, bo, bo, musimy opuścić na dźwiękach, żeby użyć nas opuścić na dźwiękach, bo musimy na pewność, że wyjście na dźwiękach, który jest kompletny, więc nie możemy po prostu wyjście na dźwiękach, który jest zakończony, bo wszystko żyje w Master, więc będzie część opuścić na dźwiękach. Więc to musi być wyjściało na dźwiękach. Tak. Kiedy wyjścisz na dźwiękach, to nie, dźwięk na dźwiękach nie wyjście na dźwiękach, tak? No, nie wyjście na dźwiękach. Bo, to jest extremnie trudne, do wyjścia na dźwiękach, kiedy masz wyjście na dźwiękach, bo to, co mówisz, że jeśli jesteś zadowolony, to widzisz to wyjście na dźwiękach. Tak. Tak, 10% z wyjścia na dźwiękach będzie mogli zrobić to, a 10% może będzie zadowolony, ale tylko wyjście na dźwiękach do wyjścia na dźwiękach będzie całkowalne. Ja tylko mam jedyna kwestia. Użyłeś opuścić na dźwiękach. Użyłeś opuścić na dźwiękach? Tak, użyjemy opuścić na dźwiękach. Jak to jest różnie z dźwiękami? Czy to jest podobne do dźwięków? No, to jest całkowalne. Więc opuścić na dźwiękach pokazuje opuścić na dźwiękach od dźwiękach do wyjścia na dźwiękach, a opuścić na dźwiękach jest używane po co masz opuścić na dźwiękach, a opuścić na dźwiękach na dźwiękach a opuścić na dźwiękach opuścić na dźwiękach na dźwiękach opuścić na dźwiękach, a może być konfigurowany na dźwiękach na dźwiękach. Jakieś pytania?