📜 ⬆️ ⬇️

Honest realtime on React and Redux, as the basis of auto auction



In our first article about the software infrastructure of the CarPrice service, - if you haven’t read it, we recommend reading it , - you mentioned the site for dealers. What it is and how it works, we asked to tell one of its developers, Nikita Lebedev.

Nikita, please tell us what is being discussed.

For those who do not know, - CarPrice has created an auction service for individuals selling their used cars to auto dealers. The owner of the car arrives at one of our many branches, our employee conducts an inspection of his car, makes a card that is put up for auction dealership. Dealers bargain for this car for half an hour, gradually increasing the price. At the end of the auction, the owner decides whether the proposed amount suits him, and either leaves with the money or calmly refuses the sale.
')
Recently, we have released a new version of the site, which hosts auctions for dealers. The user can view offers, simultaneously bargain for several cars, betting on different lots, as if moving between gaming tables - therefore, inside our company, the informal name Poker Stars has firmly established itself on this project.

What has changed in the new release?

Previously, everything was scattered across individual tabs, users had to switch between them all the time. Now this is a full-fledged one-page web application, all blocks of information are placed on one screen.

Clicking on any of the auctions opens the car card:



Here, in a compact and visual form, all information about the car, entered by our inspector during the inspection, is displayed. A schematic scan of the body is shown, in which the state of certain elements is shown in different colors. It indicates which parts are painted, damaged or badly damaged. In the gallery there are general photos of the car, photos of damage, videos on which you can listen to the sound of the starter and the engine running. Next comes the most detailed form with all kinds of characteristics of the machine.









We also use several third-party services and databases that help us to find out if the car was used in a taxi, what its real mileage is, and other information that will help you make a decision when buying.

Tell me more about the technical side of the project.

This is a web application written in React / Redux and corresponding to the paradigm of this technology: it consists of separate functional components. Even the user interface is assembled from individual component cards. In fact, each card is a separate application that works by itself. It can be painlessly removed and pasted elsewhere in the common application. That is, something like microservice architecture, only in the client part and at the level of the user interface.

All this works completely independently of the server side. That is, the auction application consists of static files that are collected by the WebPack and then distributed to Nginx.

What is the scheme of interaction between the frontend and the backend of the application? What modules communicate with which systems, what data do they transmit?

We use an integrated approach, in the application we have both communication via HTTP REST API, and full real-time communication via WebSocket (pub / sub template). This is due to both historical factors (the application worked this way initially) and functional requirements (we have places where real time and the transfer of events from the server are not needed, and vice versa). It was very important for us to implement honest real-time, since this is an auction, and we have intensive trading, especially in the last minutes. We abandoned the schemes, when updates are transmitted from the server once in a while (for example, per second, as is often done in messengers), our client receives updates from the server as quickly as possible. It was very important to preserve the convenience of the interface: when active trading begins for the car, events fly very quickly and the user no longer has time to enter a new bid manually. Fields and buttons (we have the opportunity to bid from different places in the application, and the type of bid is different) they update the information themselves when receiving events from the server, or, for example, they may become inactive if the dealer does not have rights to continue trading further. This greatly simplifies the work with the interface, but it was not so easy to implement, because under such scenarios the connectivity of the components greatly increases.

Tell me more about the tools used in the development.

We deliberately abandoned the "bike" in favor of the most popular solutions for web applications that are now on the market. As a framework, the ideology and foundation is used by React / Redux. The project is built using Webpack, we use Yarn as a dependency manager, NodeJS and Express for the dev / mock server. In production, statics are distributed by a docked Nginx.

This is not to say that this stack is completely free from flaws, but without the advantages that it gives out of the box (reactivity, flexible debugging, good encapsulation and reuse of components), it is difficult to build an application that meets modern standards and requirements (rich interactive interface with lots of information on one screen and the possibility of real-time updates).

Were the components of the previous application used, or was the new one created from scratch?

Initially, we had one large monolithic application, we are gradually rewriting critical and strongly expanding modules out of it. Now in production both the monolithic application, and new services and frontends work in conjunction. As for the interface, it changes greatly in the process of redesign, and the interaction of old and new pages is always a difficult task, each time requiring a unique solution.

Were any technologies or tools that were considered unsuitable for use in the application?

Our architecture allows quite flexible working with different tools without violating the main principles of the application. For example, we experimented with CSS modules and BEM naming of CSS classes using LESS. As a result, we chose the first as a more convenient option. The same thing happened with the implementation of the hot reboot on the dev server, the technology was still not completely settled, and we tried several implementation options.
What was the most difficult in the implementation of this application?

The application implemented quite a lot of behavioral logic, often nontrivial. Our task was to competently decompose it into modules, provide for all user interactions, think over all use cases. When all components are strongly interconnected and very actively interact with each other, it is important to foresee what each user (or other users) conducts to, what effect it has on the application. In the client part, the Redux-architecture helped us a lot. Our auction is a real time-ecosystem, and it was important that those events that arrive from other users do not conflict with those generated by the user.

As I understand it, the main advantage of the new application is its modular interface. Could you tell us more about its development?

Today, there are two popular approaches to splitting an application into modules:


In our auction application, we use the second approach. Our typical module is a React view, CSS file, Redux action, Redux reducer + static files. We do not separate containers and components , the component itself becomes a container if it has a need for action and reducer.

What is the difference between a container and a component, why did you ignore this pattern?

A container is a component that works directly with stor, makes requests to the server, and so on. And just a component can only receive data from the parent and render to a certain place. Often they are divided into different folders at the application level. Such an approach seemed to us redundant, I think, a flat list of components - this is what the whole front-end development has been going to for the past five years. The developer himself understands that the component becomes complicated (becomes a container), and this can be seen when the input point of the component is opened, since for this you need to implement several Redux methods.

I heard that Redux uses functional programming practices to build an application, is that so? What about OOP?

Yes, Redux was written under the influence of functional languages, approaches and ideas. For example, all reducer's are pure functions, and store is an immutable object. All sets of action'ov and reducer'ov - just functions that we import to the input points of the component, there are practically no classes, there are practically no instances (only in React'e and self-written modules). OOP approaches do well with constantly swelling logic, but in this case, the application can be kept compact, despite the fact that it has a lot of functionality.

Component reuse and insulation is one of the main advantages of this approach.

New versions of JavaScript, which support is actively added to browsers and NodeJS, help a lot with this. It is still not a fully functional language, and probably never will be. But innovations, sugar, and general multi-paradigm of the language make it possible to greatly reduce the pain when writing frontends and create platforms such as React / Redux.

What tools are used in the work?

Redux DevTools and React Developer Tools are added to standard Chrome Developer Tools . The first one is a very powerful debugging tool that allows you to browse the store, roll back actions and, accordingly, what was done in the application over time (this is called a time machine). The second allows you to work with an XML-like React-component tree, similar to what we write in JSX, and not with the usual DOM. This allows you to operate on larger parts of the application than simple HTML elements. We also use ESLint with a standard, slightly modified AirBnb-config to bring the code of different developers to approximately the same form.

What path does the application take from developing some new functionality to its release to users?

The developer deploys the application locally, runs the Webpack Dev server and server with mocks on different ports (or configures configs for production or staging environments) and starts working. After passing the code review, the tester in the CI collects a Docker container with the necessary branch and checks it. Then Drone is launched (we will soon tell about it in a separate post), CI collects the container for production and runs it on the combat server. In the future, we plan to build one container for testing and deployment.

How has the approach to the development of the frontend and backend changed in the last 2-3 years? What ideas / concepts, previously considered normal practice, do you consider today as obsolete, and what has come to their place? What techniques have you adopted, and, perhaps, used to create this application?

I would cover a larger period. Over the past 4-6 years, the requirements for interfaces on the web have seriously increased, in most new complex products, the basic version is made for the browser, some of the old ones have also migrated. Applications have become much more complicated, and the monolithic architecture, which previously prevailed, gives way to microservices on the backend and components on the frontend. Beckend and frontend in a typical large project were first separated from each other, reducing complexity and entropy, and then they began to divide the areas of responsibility within themselves. If earlier, even going to a popular visited site, it was possible to understand that a simple HTML string template engine, a database, a web server and a bit of logic linking all this work inside, but now, under the hood, there is often a system of numerous components. , with a clever system of communication and a stack of various technologies.

And the last question. Buying a car is a pretty crucial step, even for people who do it professionally. How did dealers respond to the new interface?

Even a successful redesign is always, to some extent, a pain for users, who are accustomed to the usual patterns of behavior, even if they can be greatly simplified and have bugs. We gradually introduced new pages and groups connected users to the updated interface. We have a feedback system, and our managers analyzed the wishes and feedback of users. We consider that we have coped quite successfully with this difficult task.

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


All Articles