What I learned while working on my first large-scale project

Eight months ago, I started writing an application on Electron. To master this task, I had to develop three separate sub-applications that run in different environments. Below I will talk about what I made for myself along the way.



Binder in its original form

Context


Before delving into the details, I will begin by providing some general information necessary to understand the situation. At the beginning of 2019, I began to search for an internship, as required by the co-op program for my degree. By April, I sent out dozens of resumes, each of which was tailored to a specific employer, and in total received exactly zero answers. You can imagine how I reacted to this - my hands fell, it seemed that I was not fit for anything and was not worth any work at all. But instead of letting these feelings prevail, I decided to prove to myself that I still know something and I can apply for some posts. In the end, I found out that in fact I know less than I expected.

I began to revise my projects in search of one that could be turned into something large-scale and complex, which could spur me on. Finally, I opted for Binder - at that time a simple web application that allowed you to manage files from Onedrive, Google Drive and Dropbox at the same time. The goal was to develop a backup service comparable in functionality to this trinity, minus the ability to transfer files to other users.

The beginning of the way


Probably, I would not have completed the project at all if I had not set myself some delusional goals from the very beginning. The first milestone that I determined for myself was the creation of a working alpha version for my birthday, which I celebrate in mid-July. I started work immediately. By the beginning of May, I created a Binder clone and began to disassemble it into parts, throwing away many functions that I no longer needed. In general, I took a completely decent application and turned it into a plain piece of code somewhere at the tutorial level.

I settled on the fact that I will write four separate applications. The first is a client that will natively work on the user's computer. The second is an API with a backend, it will facilitate the sending of secure requests. Third, the cloud service, which is responsible for the integrity of all the data that is stored on it. And finally, a “marketing” web page, because a product can’t do without a shimmering website.

And now the fun begins


Well, well, well, I admit: everything that I have said so far has nothing to do with Electron, much less the development of large-scale applications. But I needed to clarify the context so that you understand where I got my knowledge from. Here are five key lessons I learned for myself:

# 1 Be sure to use traditional structures for the frontend and backend, because interprocess communication is a stupid thing

More often than I would like, I freaked out because of how primitive interprocess communication is implemented in Electron (and now again to psycho). Yes, interprocess communication is generally not designed to carry out data abstraction in the spirit of Javascript, with the representation of functions as objects and all sorts of other things. But how much easier it would be! And so, instead of making a minimalistic client application, while the main array of code would be located in the main process, I was forced to clearly separate what will interact with the user and what will not. The criterion by which I determined what would go to the main process, and what to the render process, was formulated as a simple question: does this code serve anything? The fragment size did not matter. If he served other pieces of code,then went to the main process. The only exception was the endpoint of the Stripe payment system - for security reasons, I wanted it to be located as close to the user as possible.

№2 Making data maintain integrity is very, very difficult.

Until I started working on Binder, I did not understand how hard it was to get all the data coming from an arbitrary and impressive number of users to always remain correct and accessible. And just to provide safe storage for them is not an easy task, but now you still want me to validate everything and make sure that there are no contradictions with other data, without any idea what the data is ?!

Of course, I exaggerate a little here, but the essence of the problem is not distorted. Validation should occur as early as possible at the earliest stages and then be repeated (on a more modest scale) as the data stream advances. Maintaining consistency becomes easier if you use a transactional model every time you change the data. To tell you the truth, along with the data itself, there is also a mass of metadata, which is not much easier to manage. It always seemed like a great idea to write a function that reads user data and then performs integrity checks. But after much deliberation, I came to the conclusion that the secret entrances are no different from the front doors - the whole difference is who uses them.

No. 3 Interfaces - like shoes that are sewn to order



A great way to make a beautiful, well-functioning interface is to look at it as a pair of individual tailoring shoes (or a suit tailored to the shape, it does not matter). The first question I asked myself when I started design for Binder: who will look at the application interface? Note: I did not talk about who will use the interface. This should be the second question, because everything is tied precisely to the appearance. In the past, I conducted many projects and I can tell you with full confidence: people wanted to spit on your application if it does not look as it should.



I started by making small drafts in a notebook (with a ballpoint pen, because I have a habit of constantly doubting my ideas). In the first drafts, the emphasis was on the general structure of the interface, and only then, drawing further, I detailed in detail how each of the “pages” should look. In my opinion, the information presented is not so important as its readability.

No. 4 There is no much fault tolerance

I don’t know about you, but me from the thought that the API will crash after I accepted the payment, a cold sweat breaks through. Starting to work on the payment system, I said to myself: "Now you can not afford to miss a single mistake." I made sure to implement security mechanisms throughout the process: from the moment the API receives a request to purchase a service package, and until Stripe passes the payment information to the event notification system and the package is activated. This kind of paranoia, of course, slows down the development process, but I do not regret anything. But I always have complete information about when the payment arrived, what is its purpose and what is the status of the actions that should follow it.

No. 5 Not perfect? Not scary

I am a perfectionist, and my attempts to create something stunning often get out of hand and turn endless nitpicking to every line of code and doubts whether they have a right to exist. I have to endure battles with myself over and over about what is still more important - efficiency or readability. In the first few months, I had not yet received my sight and didn’t understand that much of what I wasted my energy on had no practical benefit - the point is to make a product that can be used with a calm mind, and not hurt for some prestigious award. It's funny that my fifth lesson partly goes against the fourth, but it's even good. The fourth lesson reminds me of caution and attention to user expectations, and the fifth sets boundaries so that I don't get stuck,improving one function endlessly.

Before we say goodbye


You read my article to the end and you may have noticed (well, or not) that Binder is not yet fully operational. At the time of writing, I was just releasing the first public version (beta 4). I am not particularly inclined to turn Binder into a full-fledged product, but nevertheless developed it so that it functions as a normal application - suddenly ambitions will take over from me. An iridescent web page can be admired here .

Everything that I thought was safe for open access was posted on the project page on GitHub. There I will post updates (and there you can download the client so that it updates itself). Ah, well, here are the statistics that I compiled on four sub-applications to flatter my vanity:

binder-local (client on Electron)



binder-web (prettiness web page)



In the remaining two, I did not start counting lines of code automatically for security reasons.

binder api

  • JavaScript: 21 files, 4117 lines
  • Other files: ~ 150 lines

binder-mongo (service for checking integrity)

  • JavaScript: 16 files, 2374 lines
  • Other files: ~ 140 lines

Total number of lines of code: 30,015

All Articles