How to set up smartphones and PCs. Informational portal
  • home
  • Advice
  • Development of the server side of mobile applications. Development of the server side of mobile applications Server side of applications how it works

Development of the server side of mobile applications. Development of the server side of mobile applications Server side of applications how it works

488 Part IV. Ajax by example

bots, and calls the server, which will dynamically create response data based on the sent query string value. The first parameter to the LoaciXMLXSLTDoc () function is the URL of the PHP page that generates the XML document, concatenated with a query string referenced to the values ​​of the HTML form O field. The second parameter is the name of the XSLT © file used in the XML data transformation. The third parameter required by the LoadXMLXSLTDoc () function is the identifier for the div element in which to place the search results. The identifier is the string name of the output element, not an object reference; in this case, the string "results" is used as the identifier.

In the next step, we use DOM methods to add an indicator image to the Web page. An image © element is created and the image source attribute O is set. This created element is added to the results © div element. This way, when our function is called from the onsubmit event handler of the form, an image file is placed on the page. In general, it is important for the user to create visual feedback — a message or image — indicating that processing is in progress. This prevents the user from repeatedly clicking the handicap button thinking that nothing is happening (remember, the Ajax process is "invisible").

The last stage is a call to the LoadXMLXSLTDoc () ® function, which initiates the process of sending information to the server. The LoadXMLXSLTDoc () function, described in Section 12.4, handles the call to the ContentLoader () object, which requests documents from the server. By specifying an exit position as a parameter (rather than hard-coded the value in the LoadXMLXSLTDoc () function), we can reuse the function on the same page without requiring multiple procedures or if statements to separate the functionality. Therefore, we redirect the results of different search queries to different parts of the page. However, before we do all that, let's take a look at how to create XML and XSLT documents on the server.

12.3. Server side code: PHP

V in this section, we will create a dynamic for the project XML document using PHP - a popular open source scripting language (as you know, the Ajax framework is compatible with any server-side language or platform). The XML document is generated dynamically from the result set received in response to a client request to the database. In addition, we'll show you how to create a static XSLT document that is hosted on the server and retrieved every time a dynamic file is requested. Both of these documents are returned to the client independently when the ContentLoader object is requested in two separate requests (Listing 12.7). The XSLT code transforms our dynamic XML document on the client side and creates an HTML table that is displayed to the user.

Chapter 12 Live Search Using XSLT 489

12.3.1. Creating an XML Document

Since we are using XSLT, we need a structured XML document, which is a simple record of information so that the XSL file can perform a standard transformation. In this project, we will create a dynamic XML file when the client requests a PHP file.

XML structure development

Before we start creating the XML file, we need to create a template for it. This template should reflect the structure of the data returned by the search. In the selected problem formulation (phone book), we will return the company name, contact name, country and phone number. Listing 12.3 shows a basic XML template with four fields.

Listing 12.3. Basic XML File

Company Name Contact Name Country Name Phone Number

The first item is the phonebook. The next is an entry element containing sub-elements with all the details that are associated with all contact numbers found in the request. If we have five results, there will be five entry elements in the XML document. The company name appears in the company element. In addition, we have added the name of the contact person, country name and phone number. We are not limited to the specified fields only; fields can be added or removed depending on what information needs to be displayed.

If no results are found, instead of displaying a warning message, you can create an item that displays this information to the user. STO will make it easier for us to return the result to the user and will not require additional code in the client side of the application. The code in Listing 12.4 is almost identical to the code in Listing 12.3, but this time we're injecting text into the XML elements we want to show to the user to signal that no results were found.

Listing 12.4. XML file with no results

No Results

// О Instead of the company name, "No R e s u l t s" is displayed N / A

490 Part IV. Ajax in examples

// © "N / A" is displayed for the remaining margins

N / A

N / A

With this code, we display a single line to the user indicating that the requested information is missing. The descriptor company O displays information indicating that there are no results. Other descriptors 0 tell the user that there is no information. If we do not want to display the text "N / A" ("not available"), we can add a non-breaking space instead, which will show the cells of the table. If we hadn't added any information at all, the cells in the table would not have appeared.

As you can see, the XML format has a very simple structure. If this XML file were static, it would be relatively easy for the user to add a new subscriber to the file. Since it is generated dynamically, we need a loop that generates an XML document over the result set.

Creating a dynamic XML document

As always, we create an XML document on the server. Adhering to the policy of using different server-side examples in the examples, the server-side code for this chapter is written in PHP. As a reminder, the Ajax infrastructure can be built using any server-side language, and we will only describe how the server-side code is implemented without going into details. So Listing 12.5 shows the code for the back end of the application. The code takes a query string parameter and generates many database query results. We then walk through the set of results, creating an XML element using the template in Listing 12.4 for each phone number received in response to a request.

Listing 12.5. PhoneXML.php Script: Generate XML Document on Server

// O Declare MIME Type header ("Content-type: text / xml"); echo ("\ n ");

// © Connect to database

$ db = mysql__connect ("localhost", "ajax", "action"); rnysql_select_db ("ajax", $ db);

$ result = mysql_query ("SELECT *

FROM Contacts WHERE ContactName like "%". // © Fill in the request

$ _GET ["q"]. "%" ", $ Db);?>

// О Check results

if ($ myrow = mysgl_fetch_array ($ result)) (do (

// © Go through multiple results

Chapter 12. Live Search with XSLT 491

001">

) while ($ myrow - mysql_fetch_array ($ result)); ) else (

12.3.2. Creating an XSLT Document

Using XSLT, our XML file can be converted into a beautiful HTML table with a couple of lines of code. The XSLT document allows pattern matching if it is needed to display the data in any required format. When matched against a template, the template structure is used to display the data. In this case, we go through the nodes of the tree

492 Part IV. Ajax by example

wa source using XSLT. An XSLT document takes a structured XML file and converts it into a format that is easy to view, update, and modify. In our case, the XSLT document is defined statically.

XSLT structure

An XSLT transformation contains rules for translating a source tree into a destination tree. The entire XSLT process is structured pattern matching. When the elements of the source tree match the given structure, the target tree is created according to the document template.

The structure of the target tree does not have to be related to the structure of the source tree. Therefore, the original XML file can be converted to any format you want. It is not necessary to use only the tabular view of the dataset.

The XSLT transformation is called a stylesheet because it defines the styling of the destination tree. The style sheet contains two-part template rules. The first part is a pattern structure against which the nodes of the source tree are compared. Once it finds a match, the XSLT processor uses the second part, the template containing the descriptors to build the source tree.

Creating an XSLT document

It is relatively easy to generate an XSLT transformation for this project. Since we are going to get a table, no fancy pattern matching is required; we will simply step through all the element nodes of the source tree sequentially. Below we will develop a template that forms an HTML table with four columns. The corresponding XSLT file for this project is shown in Listing 12.6.

i Listing 12.6. XSLT file

"ISO-8859-l"?>

// О Set XML version and encoding

// © Set XSLT Namespace"http://www.w3.org/1999/XSL/Transform">

// © Set template rules

// O Add table element

// © Create title line

Chapter 12 Live Search Using XSLT 493

// 0 Sequentially go through the elements of the phone book

select = "phonebook / entry"> // © Format the output

Company Contact Country Phone

When you create an XSLT transformation, you must specify the encoding and XML version O, and specify the XSLT © namespace. The namespace defines the rules and specifications that a document must comply with. Elements in the XML namespace are recognized in the source document, but not recognized in the result document. All of our elements in the XSLT namespace are prefixed with xsl. Next, you can set a template rule - look for a structure / © that matches the entire document.

Now we can start creating a template for the table that displays our results. We add a table O descriptor that maps to the table identifier. The table header row (C) is then entered, containing the column names that indicate to the user what information the table contains.

Sequentially passing through the set of nodes of the source tree, we get the rest of the table rows. In this case, a for-each © loop is used, in the process of processing entries, it outputs the nodes located in the phonebook / entry.

Since we are sequentially walking through the document tree, we need to select the values ​​of the columns. To select values ​​from nodes, the value-of operator is used to retrieve the value of the XML element and add it to the transformation output stream. To specify the XML element whose text we want to retrieve, we use the select attribute with the element name. Now that you have completed your XSLT file and generated the code to dynamically generate an XML document, you can complete your JavaScript code and see how combining an XSLT transformation with a structured XML file creates an easy-to-view table.

In the next step, we are back to the client side of retrieving the files we just created with the HTTP response.

Much of the modern applications for mobile platforms(iOS, Android, etc.) works in tandem with a server. An application with outdated data loses its usefulness. Therefore, it is important to ensure that data from the server to the device is kept up to date. This applies to offline applications that should work without the Internet. For completely online applications that do not work (or are useless) without the Internet (for example, Foursquare, Facebook) there are specificities that are beyond the scope of this article.

Using the example of one of our offline applications, I will tell you what approaches we used to synchronize data. In the first versions we have developed simple algorithms and, in the future, with experience, we improved them. A similar sequence is presented in the article - from simple obvious practices to more complex ones.

It should be clarified that the article deals with data transfer only in one direction: from the server to the device. Here the server is the data source.

General provisions for all approaches

As an example, we will consider transferring a directory of dishes (“dishes”) to the device. We will assume that the device makes a request for the url “/ service / dishes / update”, the exchange is carried out via the http protocol in the JSON format ( www.json.org). The server has a table “dishes” with the following fields: id (record identifier), name (name of the dish), updated (the moment the dish was updated, it is better to do timezone support right away, “YYYY-MM-DDThh: mm: ssTZD”, for example, “1997 -07-16T19: 20: 30 + 01: 00 ”), is_deleted (sign of deleted record).

Remark regarding the presence of the last field. By default, its value is 0. In an application where entities are synchronized between the client and the server, it is not recommended to physically delete data from the server (to avoid errors). Therefore, is_deleted = 1 is set for deleted dishes. When an entity with is_deleted = 1 arrives at the device, it is deleted from the device.

With any approach, which will be considered below, the server returns an array of objects to JSON devices (may be empty):

[
(id: , name: , updated: , isDeleted: },…
]

Server response example:

[
(id: 5625, name: "Bread", updated: "2013-01-06 06:23:12", isDeleted: 0),
(id: 23, name: "Cooked semolina", updated: "2013-02-01 14:44:21", isDeleted: 0), (

name: "Fish-soup",

updated: "2013-08-02 07:05:19",

Principles of updating data on a device

  1. If an element that is on the device came and isDeleted = 0, then it is updated
  2. If an element has arrived that is not on the device, and isDeleted = 0, then it is added
  3. If an element that is on the device came and isDeleted = 1, then it is deleted
  4. If an element has arrived that is not on the device, and isDeleted = 1, then nothing is done

Approach 1: Everything is always in sync

This is the easiest method. The device requests a list of dishes from the server and the server sends the entire list. Every time the whole list comes. Not sorted.

Example request: null, or “()”

Advantages:

  • the logic on the server is simple - we always give everything
  • the logic on the device is simple - we always overwrite everything

Disadvantages:

  • if you request the list often (every 10 minutes), then there will be a lot of Internet traffic
  • if you rarely request the list (once a day), then the relevance of the data will be violated

Application area:

  • for low traffic applications
  • transmission of very rarely changing data (list of cities, categories)
  • transfer of application settings
  • at the beginning of the project for the very first prototype of a mobile application

Approach 2: only sync the updated

The device requests a list of dishes, updated from the previous sync. The list comes sorted by "updated" in ascending order (optional, but convenient). The device stores the value “updated” for the most recently sent dish and, on the next request, sends it to the server in the “lastUpdated” parameter. The server sends a list of dishes that are newer than “lastUpdated” (updated> lastUpdated). At the first request to the server “lastUpdated” = null.

Example request: (lastUpdated: “2013-01-01 00:00:00”)

In the diagram: “last_updated” is the value that is stored on the device. Usually, a separate table is created on the device to store these “last_updated” values ​​for each entity (dish, city, organization, etc.)

This approach is suitable for synchronizing simple linear lists where the arrival rules are the same for all devices. For more selective synchronization, see “Approach 5: Synchronize with knowledge of what's already on the device”.

This approach usually covers most needs. Only new data comes to the device, you can synchronize at least every minute - the traffic will be small. However, there are problems associated with the limitations of mobile devices. These are memory and processor.

Approach 3: Synchronize in batches

Mobile devices are low on RAM. If there are 3000 dishes in the directory, then parsing a large json string from the server into objects on the device may cause a lack of memory. In this case, the application will either crash or not save these 3000 dishes. But even if the device was able to digest such a string, then the performance of the application at the moments of synchronization in the background will be low (interface lags, not smooth scrolling, etc.) Therefore, it is necessary to request the list in smaller portions.

To do this, the device passes one more parameter (“amount”), which determines the size of the portion. The list must be sent sorted by the "updated" field in ascending order. The device, similar to the previous approach, remembers the “updated” value of the last sent entity and passes it to the “lastUpdated” field. If the server has sent exactly the same number of entities, then the device continues synchronizing and makes a request again, but with the updated “lastUpdated”. If the server has sent fewer entities, this means that it does not have more new data, and the synchronization ends.

In the diagram: “last_updated” and “amount” are the values ​​that are stored in mobile application... “Last_item” - the last entity (dish) sent from the server. It is newer than this value that the next list will be requested.

Example request: (lastUpdated: “2013-01-01 00:00:00”, amount: 100)

Advantages:

  • The device receives as much data as it is able to process at one time. Serving size is determined by practical tests. Simple entities can be synchronized 1000 at a time. But it also happens that entities with a large number of fields and complex storage processing logic are synchronized normally no more than 5 pieces.

Disadvantages:

  • If there are 250 dishes with the same updated, then with amount = 100, the last 150 will not be sent to devices. This situation is quite real and is described in the following approach.

Approach 4: Correct batch timing

In the previous approach, it is possible that if the table contains 250 dishes with the same "updated" (for example, "2013-01-10 12:34:56") and the portion size is 100, then only the first 100 records will come. The remaining 150 will be hard-clipped (updated> lastUpdated). Why is this going to happen? When the first 100 records are requested, lastUpdated will be set to “2013-01-10 12:34:56” and the next request will have the condition (updated> “2013-01-10 12:34:56”). Even softening the condition (updated> = “2013-01-10 12:34:56”) will not help, because the device will then endlessly request the first 100 records.

The situation with the same "updated" is not so rare. For example, when importing data from a text file, the “updated” field was set to NOW (). It can take less than a second to import a file with thousands of lines. It may also happen that the entire directory will have the same "updated".

To fix this, you need to use some dish field that would be unique at least within one moment (“updated”). The “id” field is unique throughout the entire table, so you should additionally use it in synchronization.

So, the implementation of this approach looks like this. The server returns the list sorted by “updated” and “id”, and devices request data using “lastUpdated” and the new parameter “lastId“. At the server, the selection condition is more complicated: ((updated> lastUpdated) OR (updated = lastUpdated and id> lastId)).

In the diagram: “last_updated”, “last_id” and “amount” are the values ​​that are stored in the mobile application. “Last_item” - the last entity (dish) sent from the server. It is newer than this value that the next list will be requested.

Approach 5: Synchronize with knowledge of what is already on the device

Previous approaches do not take into account the fact that the server does not really know how successfully the data was saved on the device. The device could simply not save some of the data due to unexplained errors. Therefore, it would be nice to receive confirmation from the device that all (or not all) of the dishes have been preserved.

In addition, the user of the application can configure the application in such a way that he only needs a part of the data. For example, a user wants to synchronize dishes from only 2 cities out of 10. This cannot be achieved using the synchronizations described above.

The idea behind the approach is as follows. The server stores (in a separate table “stored_item_list”) information about what dishes are on the device. It could just be a list of “id - updated” pairs. This table contains all lists of “id - updated” dish pairs for all devices.

The device sends information about the dishes available on the device (the list of “id - updated“ pairs) to the server along with a request for synchronization. When requested, the server checks which dishes should be on the device and which are now. The difference is then sent to the device.

How does the server determine which dishes should be on the device? In the simplest case, the server makes a request that will return a list of “id - updated” pairs of all dishes (for example, SELECT id, updated FROM dishes). In the diagram, this is done by the “WhatShouldBeOnDeviceMethod ()” method. This is the disadvantage of the approach - the server has to calculate (sometimes making heavy sql queries) what should be on the device.

How does the server determine which dishes are on the device? It makes a query to the “stored_item_list” table for this device and gets a list of “id - updated” pairs.

By analyzing these two lists, the server decides what should be sent to the device and what should be deleted. In the diagram, this is “delta_item_list”. Therefore, the request does not contain “lastUpdated” and “lastId”, their task is performed by the pairs “id - updated”.

How does the server know about the dishes available on the device? In the request to the server, a new parameter “items” is added, which contains a list of the id of dishes that were sent to the device in the last synchronization (“device_last_stored_item_list”). Of course, you can send a list of the id of all the dishes that are on the device, and not complicate the algorithm. But if there are 3000 dishes on the device and they are all sent every time, then the traffic costs will be very high. In the vast majority of synchronizations, the “items” parameter will be empty.

The server must constantly update the “stored_item_list” with the data that came from the device in the “items” parameter.

You should implement a mechanism for clearing server data in stored_item_list. For example, after reinstalling an application on a device, the server will assume that the device is still up-to-date. Therefore, when installing the application, the device must somehow inform the server so that it clears the stored_item_list for this device. In our application, we send an additional parameter “clearCache” = 1 in this case.

Conclusion

A summary table of the characteristics of these approaches:

An approach Traffic volume(5 - large) Labor intensity of development(5 - high) Device memory usage(5 - high) Correctness of data on the device(5 - high) You can select a specific device
1 Everything is always synchronized 5 1 5 5 No
2 Only the updated 1 2 5 3 No
3 Synchronization in batches 1 3 1 3 No
4 Correct synchronization in batches 1 3 1 3 No
5 Synchronization with knowledge of what is already on the device 2 5 2 5 Yes

“Correctness of data on device” is the probability that the device contains all the data that was sent by the server. In the case of approaches # 1 and # 5, there is 100% certainty that the device has all the data it needs. In other cases, there is no such guarantee. This does not mean that other approaches cannot be used. It's just that if part of the data is lost on the device, then it will not be possible to fix it from the server (and even more so to find out about it on the server side).

Perhaps, in the presence of unlimited Internet tariffs and free wifi, the problem of limiting traffic generated by a mobile application will become less relevant. But while you have to go to all sorts of tricks, come up with smarter approaches that can reduce network costs and increase application performance. It doesn't always work. Sometimes it is “the simpler, the better”, depending on the situation. Hopefully, from this article, you can pick an approach that comes in handy.

There are surprisingly few descriptions of server synchronization on the Internet and mobile devices... Moreover, there are many applications that work according to this scheme. For those interested, a couple of links.

BACKUP

Why do you need backups on a mobile platform

Experts know how sometimes unreliable mobile applications on 1C are: errors may occur at any time, due to which the user base will simply collapse. At the same time, we are faced with the unreliability of the devices themselves: they can be broken, lost, they can be stolen, and users want to keep their data. And up to version 8.3.9 we did not have a platform mechanism for saving a backup.

Since users did not previously have a "save a copy" button, the developers of the Boss application had to make their own backups. How did we do it?

We save the database data in the form of XML.

It is advisable to offer the user several options for storing copies - first of all, it is convenient for customers, they can choose the best option for themselves: upload to the cloud, send to their mail, save on the device.

Thus, the developers additionally insure themselves. If something went wrong, and the mechanism for creating copies on Google Drive or Yandex Drive suddenly broke down, you can always tell the user that the developer is currently dealing with an error, but for now he can save the data in an alternative way. And users are satisfied because they can rest assured about their data.

Necessarily need to focus on cloud services, because if the device is lost or broken, and the user saved a copy on the same device, then the data will be lost.

Also we be sure to remind the user of the need to create backups.

How to keep copies if the configuration changes?

When we talk about a mass solution, about an application that is constantly changing, evolving and refined, customer behavior must be taken into account. The user may want to restore a backup saved in an old version of the application, which did not have any details. And then the task arises: to read the data, then fill in the data according to the update logic from the old version of the application. How to do it? In addition to the data, save the data structure itself so that later you know how to read it.

There are several options for storing this data structure, including it can be stored in the configuration itself. That is, every time a new version is released, keep the metadata structure of the previous version in a layout in the configuration.

Do not forget that in a mobile application, the configuration should not grow just like that, we should value the place in it, we should make it as compact as possible. But the application is developing, and there will be many such layouts, and over time they will become more and more.

Therefore, in the case of a mobile application, another way is preferable - save the metadata structure directly in the data file... At the output, we get such a file, where we first store some auxiliary data - the configuration version, the configuration scheme, the sequence boundaries, and after that we write the user data in XML format. Moreover, in the "Auxiliary data" section of the file, you can also store other important data that, for some reason, could not be written into XML.

We take the data schema that we have saved to the file, and on its basis we build the XDTO package for reading the file. We create a similar object in the database, fill it in, perform refill processing when updating, and save the already finished object to the database.

Below in the picture you can see a hint on how to write the XDTO model of these configurations beautifully. The company that released the Boss application experimented with this, found several ways, but settled on this option for recording the metadata schema. When you open the data file itself, you can see the usual structured XML, readable, which lists all the application metadata.

// Write the configuration scheme ModelXDTO = FactoryXDTO.ExportModelsXDTO ("http://v8.1c.ru/8.1/data/enterprise/current-config"); XDTO Factory.WriteXML (UploadFile, XDTO Model); // Reading the configuration schema Model XDTO = Factory XDTO. Read XML (Read XML, Factory XDTO. Type ("http://v8.1c.ru/8.1/xdto", "Model")); UnloadFactory = New XDTOFactory (XDTOModel);

To protect the user, it is imperative to ask him again whether he needs to restore the backup. Maybe he was just experimenting and clicking on all the buttons in the application :) And now the current data may be lost. Therefore, when performing potentially "dangerous" actions, we always specify whether he really wants this, and how it should be done. The user must be aware of their actions.

There must be a mechanism for creating backups when we are talking about an autonomous solution, when the user has all data stored exclusively on a mobile device: the user can lose his device, and then the data will be lost. And, it would seem, if the application does not work autonomously, but is connected to a central server, then the user should not have such a problem, because if the device is lost, he will connect to the server, receive all his data from the server again, and everything will be ok.

However, users do not always use backups the way we expect them to :) They very often use them to simply "roll back" data back. This is really a very strange behavior, but users of mobile applications are too lazy to figure out where they could make a mistake when entering data, and they simply roll back the data and re-enter the data for the current day. After analyzing the statistics of working with the Boss application, we realized that this is a normal practice and this user behavior is more common than we might have expected.

And if you are using synchronization with other devices, then you have to handle it. There are several solutions here:

  • break the connection with the server, specifying that the data on it will remain as it was, and the copy will be restored only on the user's device;
  • it is better for the user to let him restore a copy at once on all devices, having previously prescribed such mechanisms.

There is one more thing here. Until now, we saved the backups ourselves, controlled the entire process, caught the user's actions right in the code when he pressed the "save a copy" button. All this can be processed later. In the 8.3.9 platform, it became possible to save backups exactly by means of the platform. And the user does this without our knowledge. If synchronization with a central database is used, then such a scenario must be handled. We must somehow find out on our server that the user has restored a previously saved copy and must give him some kind of solution. We cannot afford to have data out of sync.

EXCHANGE

When we talk about a private solution on a mobile platform, we usually have a customer who, for example, wants to use a mobile platform for their sales agents, and so that they exchange data with a central database. Everything is simple here: one database, several devices, you raise the server, set up communication with it. So the problem of exchange between devices is easy to solve.

But if we are talking about a mass application, where there are many databases, each of which has a very large number of users, the situation becomes more complicated. Users have downloaded the app from the market and they want to sync with each other. For example, a husband downloaded an application for accounting for personal finances, and now he wants his wife to connect too, and they work together in the same application. There are many users, the application is developing, growing, and there is a need for a large, large number of databases. How to organize all this? Users will not personally contact developers to create a separate database for them and enable synchronization. They want to push a button and make it work right away. At the same moment.

How to proceed? This is where the data sharing mechanism comes to the rescue. It allows you to organize a single database, where there is one common configuration, but at the same time, an unlimited number of user bases are stored within one common database.

The best part is that you can add users dynamically, programmatically, without our participation. In reality, users simply click on the "register on the server" button, and everything happens by itself: a personal database is created for him on the server, and he can immediately start working in it.

How to do it? The first and simplest solution is to write your own server base with this mechanism. When our company started making the Boss application and exchanges in it, in the first version we did just that: we wrote a server database with a data sharing mechanism. Everything worked, especially since there was nothing complicated - the base separator is a common props.

But then we realized that we were reinventing the wheel :) In fact, there is a ready-made solution, and it has already taken into account the points that we had not even thought about yet. This is 1C: Fresh.

The scalability of the service is thought out here: what to do when there will be a lot of data and databases, how to grow with all this. There is a point about creating backup copies of data areas: that is, we do not just backup one common database, we make copies of a specific user. Moreover, the mechanism there is such that copies are made only when they are really needed. If a user has not entered the database for a week, then we do not make copies of him, because nothing has changed there. Another Fresh feature is that the service implements a mechanism to reduce the load on the server, which is very important when you have a lot of databases.

In general, Fresh for us is something new and interesting. Little by little we are trying to figure it out, but for the most part we are just happy with its work.

Data transfer. How to implement it for exchange between devices

The platform provides two mechanisms - SOAP and http services. There are nuances of how to access these services when the data sharing mechanism is involved. In particular, you need to add parameters that indicate the specific number of the area you are accessing, because the platform cannot determine which database to access by the username. In addition, one and the same user can work with several databases within a single database (see the picture).

As for services, the Boss app implements instant exchange: one user enters data, and the other receives it. Users of mobile applications are accustomed to the fact that everything happens instantly, so we thought about which service is better to use - SOAP or http. Connection speed played a key role. In http, the connection speed is much higher, and when connecting via SOAP, we get a description of the service, which is heavy and takes a long time to load. The platform has a way to store a description of a service, but because of the parameters we add dynamically, we cannot use WS references. In addition, accessing http services is more convenient and flexible in our experience.

So, our goal is to implement the exchange in real time. That is, we try not to make the user have to go somewhere, click on a button, think about how relevant his data is, whether he should update it ... The data should always be relevant for users. They are so used to working in instant messengers - one sent the data, the other immediately received it. Everything happens instantly. The same applies to applications related to business: one seller has issued a sale, the other must immediately see the current situation without taking any action.

Therefore, the Boss app uses background jobs for exchanges. After each data is written to the database, a background job is started, which initiates the exchange. The first part is to send data to the server. Then other devices need to know that there is new data. For this we use PUSH notifications. This scheme is already working and it works fast enough.

But we wanted it even faster, because we work in real time and we usually have little data. We have small XML, but at the same time we send a message with this data from the first device to the server, the server sends PUSH to another device, and then the second device, after receiving PUSH, initiates an exchange from its side, addresses the server and requests data, receives this data and then sends a response that the data has been received. This is a long time, but the data itself was very small.

We thought about how this process can be accelerated.

To do this, we figured out what PUSH contains, how it can still be used. It turned out that PUSH contains fields such as data and text. The iOS and Android documentation contains restrictions on the size of PUSH messages, but this seemed not enough to us and we wanted to figure it out empirically. And we checked that the sum of valid characters is 981 characters for iOS, and 3832 characters for Android. In the latter case, it is quite possible to use the restriction; one or several base objects can be crammed into such a volume. And then the developers of the company changed the scheme a little. When there is not much data, we send it from one device, receive it on the server, pack it in PUSH there and send it directly to another device in it. The scheme became shorter, and the exchange began to occur even faster :)

An important point of using PUSH is not to annoy users.

It is very easy to get rid of this situation: just do not send a lot of PUSH messages to the user :) If he is working in the application now, you can send a lot of messages. When the platform is running, the user does not see PUSH, everything happens automatically for him. But when the application is closed, the client has a lot of unread messages. Therefore, in no case should the next PUSH be sent until a response is received from the device that the application is running, active, and the previous PUSH has already been processed.

Another nuance of the exchange is work via the web. We need to make the most of asynchrony. You cannot work as usual - write the code - call the function - wait for it to execute - get the answer - and everything is ok. If you work over the web, you will still face certain limitations, for example, unstable Internet, triggered timeouts when performing long-term operations. Therefore, it is necessary to think over the architecture in advance.

Let's look at an example of registering a device, what happens in an application when a user wants to register. He keeps records for a while, he entered a lot of data, but then he wants the seller to work with this database too. The user clicks on the "register" button. At first everything was very simple: they took his data, recorded it on the server, and, please, you can work and connect users. But then we ran into a situation where for some users the databases on the device by the time of registration had already grown greatly. And this scheme did not work any more, since while the entire database was being recorded on the server, the connection timeout was triggered or the Internet was simply cut off. Therefore, we replaced one synchronous call with many short ones. Now the data is being shared rather than being transmitted all at once. We do not wait in any way for the server to process and record data. We sent data, received a response that the data was received, closed the connection. Periodically, you need to poll the server, what is happening there and how, and in the meantime, a background job is running on the server, which records the received data. This way we get a lot of server calls, but we have a guarantee that everything will go well. And neither timeouts nor instability of the Internet will prevent you from uploading all the data to the server.

UPDATES

Exchange between devices with different versions of the application

Since we are talking about a mass application that is released to the markets, we must take into account some of the features of the update and data exchange process.

If you have released an application for one enterprise and decided to update it, then usually you just give a command so that all employees will install the new application together. This cannot be done with users who downloaded the application from the market. You can't tell them what to do at all. For example, they are working in an application and do not want to update it either now or ever. They do not have auto-update, so it is quite common situation when several devices are connected to the central base, and they are all with different versions. Another reason for this phenomenon is the publication time in the markets: it is different for iOS and Android. We often implement key things, for example, fix critical bugs, and do not want to wait for iOS to check a new version for two weeks, we want at least only for Android, but we want to release an update right now.

We have no right to command users. If they want, they are updated, and if not, they do nothing. The picture shows the ratio of Boss app installs by versions in GooglePlay, as well as statistics from our server - the real ratio of app versions that are installed on devices that have exchanged data with the server during the last week. Here's a set to work with. These are different versions and different metadata. And we need to organize a normal exchange at the same time :)

The developers are faced with the following tasks:

  • All this needs to work. Users shouldn't feel discomfort that they forgot to upgrade. They shouldn't notice it at all. Updated - it's better, well and good.
  • We must ensure the safety of the data. For example, one user has a directory and a new props, while another does not yet. Moreover, if a user who has no new details changes something on his device, then the data on other devices should not be lost.
  • We need to ensure that the data is updated when we upgrade to a new version. When the user decides that he is ready to update, he should automatically have all the new information that he did not have just because he had an old version.

How did we do it?

1. We use 2 exchange plans on the server. The first is for sharing between devices and the second is for updates. For example, we sent a manual to a user, but he does not have units of measurement, that is, incomplete data. We must remember this. And when he is updated, we must send him all the information that he did not have. This is what the second exchange plan is for.

2. To write and read objects, we use the same mechanism that is used for backups, that is, we save the version of the metadata. In this case, we are working with the server, and we can afford to add anything we want directly to the configuration, so we simply add metadata schemas to the configuration in the form of layouts as the application develops.

How to monitor massive errors during exchange and on the server

First, you need to control the availability of the server itself. This happens to servers - they fall. We did not invent anything special for monitoring, but simply found a bot in the telegram that screams if something is wrong. Every minute he checks the server's performance, and if the server is suddenly unavailable, he starts screaming, the admins see it and bring up the server.

We also collect the error log from the log. Also nothing supernatural - we just collect a log of errors every three hours, send them to the mail, and periodically review them. This helps to see common problems and some kind of exceptional situations. It's not hard to read your mail, track down and quickly fix errors. But this allows you to quickly identify and solve problems that can grow with the growth of databases.

Another important point - be sure to give the user the opportunity to "complain". It improves our status in their eyes and saves us. There are users, as we call them, "hysterics" who, at the slightest mistake, begin to send us a bunch of messages by mail that nothing works, the database does not load, everything is terribly bad. But sometimes they really save us, because sometimes they find such bugs that others miraculously haven't found, serious bugs.

The user cannot be frightened. Not scary messages, nothing else. They need to explain everything beautifully and offer to complain. And we promise to solve everything. Then the users are happy, because they see that they are taken care of, and immediately believe that they will be helped :)

This article was written based on the results of the report read at the INFOSTART EVENT 2016 DEVELOPER conference. More articles can be read.

In 2020, we invite everyone to take part in 7 regional meetups, as well as the anniversary INFOSTART EVENT 2020 in Moscow.

Offline in the past, being Online today is a must. At least for the modern business world. Presentations of brand products and services, online ordering and delivery, maintaining a customer base, communicating with customers, and much more - all this is simply impossible without an Internet presence. If you need an application, you must have both Front-end (web interface) and Back-End (back-end of your application). And if you want to be able to edit the content of your application without the involvement of developers, you need a good admin panel.

While the front-end in the mobile app space is built using technologies such as X-Code and Java, the Back-end, where the database and all the application logic will be stored, requires professional knowledge of a server-side programming language. A good example is PHP, which is arguably the most popular programming language used for almost any server side development. This is the undisputed leader.

There are many uses for PHP: static and dynamic websites + custom content management systems, social media, specialized CRM systems, e-commerce software, and more. Of course, there are free or cheap server parts and control panels. However, in many cases they do not provide the required level of convenience, customization, and upgradeability.

Our programmers work with technologies to implement a wide range of solutions for different business goals, needs and requirements. We analyze the system requirements for each project individually and use various specialized server software for optimal performance of your mobile application.

If you're looking for a team that can lead you to the smartest and most cost-effective solution for building an app from scratch, or rebuilding an existing one for a perfect user experience, you don't need to search anymore. Appsmob is ready to help you find the best solution for you.

Top related articles