days since this article was written, please be aware of its timeliness
Preface
Due to a lack of project experience, I often make mistakes regarding the roles and responsibilities between frontend and backend development.
Main Content
For example, I needed to implement a feature where clicking a button would query data using a backend-provided API and then display it on the frontend using Handlebars. However, the queried data (returned as an array, with each item being a map type) was often quite lengthy, making it unsuitable to load and display all at once on the page. So, I designed the logic to “query data from the backend every time the button is clicked,” then sliced the retrieved data each time to the same length—i.e., the first slice would be from 0 to x, the second from x to 2x, and so on.
But here’s the problem: I wasn’t sure whether the data queried by the backend SQL was ordered using ORDER BY. If not, then each time I clicked the button, the queried data would be unordered. Without a guaranteed array order, I couldn’t ensure that the sliced data would be what I wanted. For instance, the first slice (0 to x) might include item h, but in the next query, item h might shift to position x+h, causing it to be queried again and displayed in Handlebars. This was incorrect.
Of course, I wanted to solve this problem within my capabilities, so I planned to sort the array on the frontend based on a property like uid. At this point, the frontend lead asked me what I was doing. When I explained that I needed to sort the unordered array returned by the backend, he told me:
“This is the backend’s job. If you handle it on the frontend, it’ll hurt performance.”
He then elaborated:
“Generally, the frontend uses the interfaces provided by the backend and shouldn’t reprocess the queried data. However, in templates like Handlebars, you might sometimes need to assemble or process certain properties of the data before rendering it to the page. But in your case, I can clearly tell you this is the backend’s responsibility—they should ensure the interface meets the requirements when providing it to you.”
“Your current situation is that you need to implement a pagination feature, but the backend interface can only query all the data at once, unable to fetch only what’s needed. In other words, the existing interface doesn’t meet the requirements. What to do? Two options: If time is tight, sacrifice some frontend performance and handle it directly. If time isn’t tight, ask the backend to provide a new interface—just adding start and offset parameters. This isn’t hard to implement.”
Another best practice: minimize query operations; retrieve information from the page whenever possible instead of fetching it from the database .
For example, even after the backend adds the new interface, I’d still need to perform four query operations: initialization, clicking “load more,” and tab switching. Each incurs a performance cost. Here’s my logic:
-
First: When the page initializes, query the data, slice it to a fixed length, and display it (one query). I also need to track how many times the “load more” button is clicked to determine the maximum clicks. The total data length divided by the slice length, rounded up plus one, gives the required clicks. Only after clicking that many times will all data be loaded, and the “No more data” button appears (another query). This makes sense, right?
-
Second: Clicking “load more” requires querying data, displaying the needed slice, and incrementing the click count (one query).
-
Third: Since there are two tabs—“My Community” and “My Activity”—clicking either requires a query (one query).
The most frustrating part? I actually made the content of these two tabs overlap! Every time a tab is clicked, the original content is forcibly replaced using jQuery’s $(container).html() method. Because there’s only one container (my design), switching tabs requires using html(), while “load more” uses append()!
How embarrassing.
Postscript
Later, I followed the best practice mentioned earlier. Additionally, I aimed to separate and centralize functionalities. What does this mean? For tab switching, the tab should only handle switching—not data queries (separation of concerns). The “load more” button should only handle querying data, nothing else. Even during page initialization, I used trigger to simulate a button click for querying data, rather than querying on load and then querying again on button click (centralization of functionality).
I often wish that when facing some key decisions in life, someone could tell me the best course of action so that I would not waste my precious time. Putting myself in others' shoes, I therefore write blogs often, hoping to record in this tiny corner of the vast Internet the once-in-a-lifetime experiences that matter to me, and to help those who seek help.