What skills are needed to create an iOS application? Yandex Report

A mobile developer needs to have a clear set of skills. You need to talk about them in the context of specific tasks that arise during the creation and publication of the application. Arthur Antonov works as an iOS developer in the Yandex machine translation department. In his report for students and beginners, Arthur explained what a developer must be able to do to create modern mobile software.


- There are two mobile applications in our department: Yandex.Translate and Yandex.Keyboard. In Translator we have a lot of sophisticated technologies, for example voice input, text recognition by photo, text translation using neural networks. A separate challenge is maintaining this functionality offline. That is, this functionality will work for you even without the Internet.



The keyboard is a separate class of applications; there are separate requirements for its speed and the quality of the application itself. Auto-correct in Russian works for us: it helps the user, but does not bother him. Voice input, swipe input.





A separate cool feature is the dynamic grid: it tries to predict the next letter and, depending on this, changes the tabson. That is, it is easier to get into a more likely letter.



At school I was engaged in sports programming. But when I entered the university, it seemed to me that it was a little boring, I wanted to develop programs for ordinary people, and it is desirable that they be available always and everywhere. So I decided to choose mobile development. But mobile applications are multifaceted, and the biggest question that has arisen before me is where to start.

The Internet is now full of online courses, tutorials, books on various topics, and the head just explodes. It is not clear where to start. Therefore, in my report, I would like to help you build your learning path to become a mobile developer. What is worth studying at the beginning, the study of what can be postponed.



After analyzing my work over several years, I identified several key skills that are necessary to solve most problems. These are fundamental skills and so-called toolbox skills. They are not required when developing mobile applications, but if you possess them, then your life will become easier, and the quality of your applications will be much better.

Since a theory without practice is dead, we will study skills using the example of a simplified version of Yandex.Translator. When you have done the project, all you see is a white screen.

Let's revive our application using the UI.





There are two classic ways to create an interface - a graphical editor and code. This is one of their hollywood topics in mobile development. There are adherents of development in a graphical editor, and someone does not recognize anything except code. But I advise you to try both methods. You will certainly come across them, and in addition, no one forbids you to combine approaches, for example, simple things to do in a graphical editor, and complex ones already in the code.



And recently, iOS developers have a new SwiftUI framework that is trying to combine these two approaches. That is, when changing in a graphical editor, your code changes and vice versa. Perhaps when this framework becomes widespread, all disputes will go into oblivion.

Unfortunately, SwiftUI is only available starting with iOS 13, so it cannot be used in large projects so far.



The graphical editor has a very simple interface. We take ready-made components, drag them onto a virtual screen and immediately see what we get. For this reason, it is very fast to create simple UI components. We can also resize the virtual screen for different devices and test our interface without launching the application.





On the other hand, we have an interface design in the code. When developing an interface in your code, the UIKit library will come in handy, and you will use small building blocks from it called UIView. UIView objects roughly correspond to what components you have displayed on the screen. And just like in a graphical editor, you have ready-made subclasses for commonly used components, such as buttons and text.

When developing in code, it is very important to understand that other UIViews can create UIView within themselves, that is, you can build interfaces of any complexity. As a result, you get the so-called tree. It is easier to modify from code. That is, if you have a very dynamic user interface, then it may be worth writing it in code and it will be easier for you to modify it later.



Let's see what code can be written for our translator.

First we set the background color to yellow. Then we add an input field where the user enters the text in English. Next, we add a separator for beauty and, finally, add an output field, while prohibiting the user from editing it.

We have a user interface ready, but the application is still rather useless. It does not solve the main task of the user - translation of the text.

Let's add this functionality. The capabilities of the SDK platform will help us.



Platform SDKs are a set of tools and libraries for creating mobile applications that are provided to us by Apple and, accordingly, Google.

Currently, the SDK has a lot of low-level libraries for interacting with the operating system, and you can implement almost any idea of ​​a mobile application without much effort.

Which libraries you will use depends on the specifics of your application. For example, if we want to make a camera, then most likely you will need two libraries: AVFoundation for working with the camera and CoreImage for image processing.

Therefore, at this stage it is not necessary to memorize all libraries, it is simply impossible. More important is the ability to find the right tools. And unfortunately, official documentation does not always fully document features. Sometimes you find some interesting things, for example, on a blog or on the twitter of another developer. It is worth following the information field.

So, what do we need from the SDK for our translator?



Our translator is a classic client-server application: we make a request to the server and get a response. Then we somehow transform it and show it to the user. The Foundation framework will help us for this task. It contains convenient abstractions for solving everyday tasks.

We will take the URLSession class from it, this is the class for working with the server using the http protocol, and JSONSerialization, this is the class that helps us convert objects from the JSON format.



So, let's see what code we need to write for this functionality. On the left is a method that is executed each time user input is changed. We first create a URL with the address of the translator server and make a request. Further, after we received the answer, we parse it from the JSON format, we get the desired text from it, that is, the translation text. And the last step - we say that in the input field you need to set the received answer.

Let's see what we got. The user enters hello and “hello” appears:



But "hello" appeared somehow for a long time, it did not seem like network lags. For reliability, let's compare with the older brother:

Open GIF

In both applications, we enter the text hello and see that the translation has already appeared several times on the real translator. On our translator, the translation appears with a big hang.

To fix this problem, we need to get acquainted with the multithreading model in mobile applications.



Just like desktop, mobile applications run in a multi-threaded environment. But there is an important limitation. A mobile application has a main thread or a so-called UI thread. And any operation with the UI, any change in the UI must occur in this main thread. If you want to change the color of the button or move it - everything should be in the UI stream.

On the other hand, all user interactions also come to us on the main thread. That is, the user clicked a button - we received a message in the main thread. Changed the text, as in our case - we also got it in the main thread. Since there is only one stream and all actions with the UI take place in it, it is very important to take care of it and do as little computation on it as possible, otherwise you run the risk of being in a situation where you are processing a user action for a long time and you have a queue from other user actions. Then everything starts to freeze.

For this reason, many system libraries by default run on a background stream. For example, a trip to the network takes an average of 100 to 500 milliseconds. This is quite an expensive operation for the main stream, so all interaction with the network takes place on the background stream.

And again, this creates problems for us, because if we inadvertently use the result obtained from the server immediately to change the user interface, this can lead to a crash or crashes.

Recall our last line:

self.textOutputView.text = translation

In it, we took the result of the server and set it in the output field. Thus, we violated the first rule - we changed the UI not from the main thread. The standard library Grand Central Dispatch will help to fix this. It quite easily helps us switch to the main thread and perform this action on the main thread.

DispatchQueue.main.async {
  self.textOutputView.text = translation
}

Let's see what we got with the application in the end.



The user enters text, and we see that the translation occurs almost instantly. Hooray! We defeated this problem. But, before releasing the application, let's talk about another important topic - architecture.

Unfortunately, on the current project I will not be able to demonstrate the importance of architecture to you, it is still very small.



But, I assure you, architecture did not arise from a better life, not from the fact that developers have nothing to do and they write abstractions so that they are not fired. Architecture is the answer to the challenges of mobile development.

The main of these problems is scalability. When your application gets too big and it has different functionality, it is important that it is easy to understand, expand, debug. Otherwise, any addition of features will change all the old ones. And the risk of us having bugs increases.

Do not wait until your application grows. Already at the initial stage, you can learn the basic practices of building software that also work for mobile applications, such as SOLID, gang patterns of four.

The architecture of mobile applications has its own specifics: their global or large components are built according to architectural patterns that say at a high level which objects should belong to which layer. The most popular are MVC, MVP, and MVVM.

And let's not forget that in reality architecture is not a silver bullet. It is necessary to take into account the specifics of the project. If you are pulling some kind of architecture onto your project with tears in your eyes, perhaps something went wrong.

When you study theory, it will seem terribly complicated to you. But in fact, when you work in a project with good architecture, you will be happy because it has become easier for you to write code. You know what and where to add so that you have a feature. Therefore, at this stage, in order to get to know the architecture well, I advise you to work or intern in a large project. If you don’t have such an opportunity, then now many companies put their projects into open source: Wikipedia, Firefox. And no one forbids you to go to GitHub and see there.

So, our application is ready. Let's put it in the public domain so that users can download it.



In most cases, users get apps from Google Play and the App Store. But before adding the application to the Store, we must sign it. This is due to the fact that operating systems run applications only from trusted developers. Thus, on mobile platforms we have much less malicious applications and viruses, because only trusted developers get access to work on mobile devices.

To do this, you need to issue a developer certificate. This is actually a small bureaucracy and, fortunately, it is automated in the latest versions of Xcode.

Also you need to take screenshots for your application and description. The last two steps should not be neglected, because the page of your application is its advertisement. If it is not bright, then most likely all of our development was in vain, because no one will download the application.

The application has been uploaded, let's now talk about some additional skills that can simplify your life and improve the quality of applications.

The skill you will use most often is debugging.



The main debugging method is the good old console.log or printf. It has a lot of names, but the meaning is the same. When something goes wrong, we add logging, print variables. But unfortunately, this method also has critical drawbacks.

The first of the drawbacks is changing the source code. There are bugs that disappear when you add printf. And you remove printf - arise again. These bugs even have a separate name - heisenbug.

The second consequence is that you need to recompile your application and run it again. In large projects, this can take minutes, and if you need to wait a minute when adding each new log, then in total you will spend a lot of time.

And the last, most critical drawback of printf - unfortunately, it doesn’t help for all bugs.

An example from personal practice. When developing keyboard onboarding, the following happened:



In the system keyboard below, instead of system globe and microphone icons, some identifiers appeared. Debugging this bug, I felt like this:



How can an application break a system keyboard ?! It turned out that it could.



When investigating the bug, the debugger knowledge helped me a lot. In particular, setting breakpoint to call certain functions. View Debugger, where we can look at our user interface and see who has which class and what state.

When I took advantage of these first two points, it turned out that the problem was in the UIKit library. iOS developers are familiar with it and know that it does not have open source code. But when you know assembler, any library becomes open source for you, so small basics of assembler may come in handy.

There is also the so-called skill of reverse engineering. Sometimes it can be quite boring, sometimes it’s interesting - a detective story where you investigate how one component is connected to another, how it is all done inside the library. As a result, it turned out that the problem was in the Objective-C language runtime.

The next important skill is optimizing our applications.



Mobile devices have limited resources, so there is often a performance problem. When developing, we need to think about things like CPU consumption. Most often, this is the complexity of the code you write. Rendering speed, memory, and network traffic, because most users are more likely to use your application on mobile traffic. Let's respect the users and maybe it will be mutual.

The fifth point is the battery, it follows from the first four.

The most important thing when optimizing applications is to identify problem areas. If you rely only on your assumptions, then it is likely that you will lose a lot of time, and you will not get too much profit. This will help the platform tools. They include a profiler - a program that shows you where in your code the program spends the most time. That is, you will see the method in which your program most often hangs, and most likely you will find the reason for the freeze.

Knowing the algorithms and data structures will help you find a more efficient solution. Also, multithreading knowledge can help here. There are multi-core processors on mobile devices now, and by parallelizing the problem across multiple threads, you get a slight n-fold increase in performance.

Sometimes it happens that the first two points, unfortunately, do not help. Then you will be helped by understanding how the operating system works, and knowledge of system calls, such as memory map (mmap). In our case, third-party iOS keyboards have a limitation on RAM consumption - 52 megabytes. That is, we want to add features, make a beautiful user interface, but are limited to 52 megabytes. What to do with this is not clear.

When adding another feature, this happened. We often began to exceed this limit and did not know what to do with it. As a result, the memory map system call came to the rescue. We took a file with a dictionary, from where we get all the hints, and began to call the memory map. Thus, we work with part of the file without loading it completely into RAM.

The last frequently encountered problem is the start time. Here I can advise you to read what happens before your code starts working. In particular, about static and dynamic linking.



The last useful skill is Continuous Integration or automation of boring tasks.

Nobody likes to do boring tasks, so we just automate them. Most often, the simplest thing is to build the application for each commit you make, and the more often you build the application, the faster you can find the problem. If you have tests, run them too.

As I said, the publication is associated with a small bureaucracy, so it is also very automated, and you can release the assembly into the beta store for each pool request so that testers can test it. You can also automate the generation of screenshots for the App Store, so as not to do them manually.

For all the listed skills, I collected useful materials.that will help in their study. It also contains the source code for a simplified version of the Translator. Thank you for your attention, I hope you have a little clearer what to study in order to begin your journey.

Source: https://habr.com/ru/post/undefined/


All Articles