How to organize work on a library of common components

If your company makes several products in the same style, one day you will come up with the idea of ​​creating a library with a common code. For example, with UI components, an authorization service, or for working with third-party APIs. You might be wondering: who should support this code? How to communicate changes to users? After all, how do you get them to use your library at all?



Since 2015, I have been working in Tinkoff in the business services department. During this time, our team has grown from 3 to 60+ developers, and the Tinkoff Business ecosystem has grown from 3 to 50 web applications. At different stages of our development, we approached working with common code in different ways, and I want to talk about this in this article.



image



Foundation: cheap and cheerful



So, fast forward to 2015. We have only three web applications: cash management services, payroll project and control panel. And as many developers.



The application interfaces are made in the same style, and the general code is moved to the Foundation library in a separate repository. The library does not compile - and, strictly speaking, there is nothing to compile there, all the code on ES5 - and is not published in npm, but is connected by the name of the branch in package.json. Separate Foundation release branches were created for product releases to fix the status. If we forgot to fix the Foundation branch, with the hotfix it turned out that the Foundation had changed and the hotfix version was simply not going to.



This is what the Foundation connection in package.json looked like:



"dependencies": { ... "sme-foundation": "git+https://stash_url/sme-foundation.git#develop" ... },
      
      





The main principle of the library at this time is general code ownership.



If a product feature required a revision of the Foundation, the feature developer did it himself. And if they were incompatible with the previous version, then he also rules the use of this code in all projects. The same was true for large-scale refactoring: if you want to refactor a component and change its API - please, but at the same time go through all the uses.



If you want to reuse in one project what is already in another - also not a problem, just take it to the library.



Fortunately, there was not much code. This approach worked great for three, four, five projects ... and had a number of advantages:





At this point, we had a minimum of documentation: some JSDoc and unit tests. For the UI components, there was not enough visual storefront, and we saw a cheap and fast solution - Demo UI. In fact, it was an angular application, on the pages of which the components themselves and the corresponding markup were inserted.



demo ui



In 2019, you are unlikely to do the same. But here is what can be learned from this story:





As time went on, the Tinkoff Business ecosystem and development team grew. When there were more than a dozen projects, this approach stopped working.



Changing common components has become too expensive. The developer of one project was no longer familiar with all other projects, the search for component use and making changes became more complicated. The time to implement new features affecting the Foundation grew.



New developers did not have a complete picture of what was done and how it was used. Changing the API of the component was scary, because of this, Frankenstein components appeared with a large number of input parameters.



Sometimes this led to inconsistency in the UX . Details such as working with the keyboard, working with focus, were implemented differently in different components. And somewhere, they were not implemented at all, because the developers were focused on business features.



Other Angular projects appeared in the company, and we suggested that they also use our library. At first, they even agreed ... But as soon as improvements were needed, we found ourselves in a difficult situation: all our developers are busy with their projects, and our colleagues have no motivation to deal with someone else's library. Everyone was responsible for the Foundation and no one in particular, and this did not suit colleagues.



UI Kit and a new approach to work organization



When it came to 2017 about the redesign and the new UI Kit, we started developing new components in a different way. To begin with, we have a dedicated team.



Team



We selected three people from product teams and said: “Now these guys are making UI components for other projects.”



What did the dedicated team give?





If the expertise in components is concentrated in one team, then how to teach others to use these components? For this we have done excellent documentation.



Documentation



The idea of ​​redesigning our demo stand has been in the air for a long time, and the development of a new library has made it possible.



Then the Storybook for Angular has not yet been released, so we went our own way. It’s for the best: our own implementation did not limit our imagination, we could do absolutely everything we wanted.



And here is what we did:



  1. Added information about the library as a whole: a step-by-step description of how it connects, and a list of supported browsers.

    getting started
  2. We prepared a detailed description of each component: why it is needed, how it connects, what input-output parameters it supports (with the ability to poke them, a la Storybook), examples of typical use, a list of similar components.

    components docs demo



    code examples

  3. Added a list of projects in which this component is used.

    usage

  4. We began to collect statistics on the use of the whale in different projects: which projects are connected, which version, how many components are used, which version of the angular and whale in each project - this information is used to plan incompatible changes and refuse to support old versions of the framework. The description of the tool that collects these statistics deserves a separate article.

    statistics

  5. Added versioning: view documentation for each previously released version of the UI Kit.

    versions



Of course, all this did not appear immediately, but evolved.



Within our department, a dedicated team and documentation would be quite enough. Colleagues are accustomed to using common code, they know the developers of the UI Kit, and are generally very loyal.



But the UI Kit design itself was positioned as common for all the company's products, which means that dozens of teams needed the same components - from internal HR projects to WebOffice, a working system for tens of thousands of remote employees. Therefore, the whale team faced a broader task: to create a high-quality internal product that all Angular teams will use.



In general, colleagues from other departments were positive, but still they had some doubts: whether the features they needed would be developed quickly enough, whether they would be of high quality ... Someone had already started making components by himself.



To resolve these doubts, we organized the work as transparent as possible.



Transparency



If you take out only one thought from this article, then let it be the following idea: to make a library successful, it’s not enough to make good components. You should be as transparent and customer-oriented as possible. In this case, customers are end-product developers.



You must, by all possible means, convey to your colleagues what you are doing, why, and how to use it.



What tools did we use?



Regular releases and demos. The first demo took place two weeks after the start of development and then was held weekly - on the day of the next release. Sometimes there were many new features, and sometimes only bug fixes. We did a demo no matter what.



Looking ahead, I’ll say that the main work has now been completed, the API has stabilized and the team has switched to the alternation of releases - one release with features, one with edits and improvements - and the demo is carried out only on releases with new features.



Changelog . We introduced conventional commits and generation of a changelog from them, which greatly simplified the transition to new versions for teams.



changelog



“Responsive” team . Like all teams, we have our own channel in Slack, this is nothing new. In fact, we even have two channels: one for communication within the team and one for users - answers to questions, announcements, surveys, conducting demos and other activities.



It is important that incoming questions are really resolved. Some of the questions are complicated in the case, some pointed to the gaps in the documentation (or let us know that not everyone reads it). And sometimes newcomers to Angular wrote about their difficulties. The whale team with equal readiness helped everyone, not being lazy to phone up if the issue is not resolved in the chat, or even download someone else’s code to themselves. Naturally, such communications waste developers time, but this is part of the work on the library.



Now there are more than 200 users in the whale channel, and many questions are resolved without the participation of the whale developers: colleagues share their experiences and answer each other's questions.



Newsletters with a list of changes after the release. Their target audience is developers, managers and product designers. In the newsletters, the changes were described simply and readily - which is not always possible in Changelog - and contained "was / became" pictures. I'm still sure that this is a great tool, but it was hard to prepare high-quality and clear digests every week. After some time, we stopped sending them, but perhaps we will return to this practice.



email



User surveys provide an outside view and reveal weaknesses. For example, according to the results of the next survey, we learned that most colleagues fully agree that the developers of the UI Kit are ready to help, which means that we are doing everything right in this direction. But the statement “New components are being developed quickly” agreed to a smaller number of respondents. What to do with such results? On the one hand, bring to the attention of all team members and work on weak points. On the other hand, work with users. If speed matters, pay more attention to the explanation of where such terms come from.



feedback



The polls included open-ended questions like “What can we improve?” I must say that our colleagues gave us some valuable tips: for example, to make the Copy button next to sample code or to teach our classes for dates to work with unixtime.



Team role



Above, I already wrote about the “responsive team”, which decides a lot for the success of the library throughout the company. I want to once again emphasize this idea and talk about two related practices.



Duty . At some point, communication with colleagues became so much that the introduction of duty seemed inevitable. This is how many service teams in Tinkoff work. Once a day, two days, a week one of the team members is on duty. He monitors the channel, answers questions and takes on most of the communications, while his teammates are not distracted by support.



We have not reached this point, and over time the need has disappeared. However, other teams on duty help.



Audit No one knows the components of a whale better than the team developing them. And over two years of development, the guys have also accumulated excellent expertise in Angular. Now we are introducing the practice of “audits from the whale team”. The guys connect to the review of product projects, as well as view the final products and their code. Their goal is to identify misuse, refine documentation, and make a list of good and bad practices. We’ll talk about what happens next time.



Challenges and Compromises



Like any process with a large number of stakeholders, the development of a common library forces us to seek compromises.



It was not easy for us to find a balance between code quality and API stability. On the one hand, the design changed at the beginning of the work: new components or new states of old components appeared; something, on the contrary, was obsolete and sawn out. On the other hand, the developers' vision of the correct component API was changing. All this inevitably led to breaking changes. But the number of library users grew, and our breaking changes caused them great inconvenience.



We found a compromise: making breaking changes no more often than every fifth release, that is, once every five weeks. For example, such changes could call in releases 0.50, 0.55, 0.60. But the transition from 0.50 to 0.51 did not require any effort. This continued until the release of stable version 1.0.0. Now the API is stable, and all large-scale changes are postponed to 2.0.0 in the indefinite future.



Several times, switching to a new version required a lot of routine work: renaming prefixes, changing icon imports, and the like. For such cases, we have implemented migration scripts.



findings



This article describes our four years of experience working with shared code libraries. What conclusions did we draw?



  1. Even a small team should not put up with code duplication. Removing code into the library is a solution accessible to everyone.
  2. Joint ownership of common code works well for small teams, up to 10 projects are users of the library.
  3. With the growing number of projects or developers involved, it is more convenient to highlight a team with a focus on common code.
  4. An important part of the work of a dedicated team is communication with users: demos, training, help, documentation.
  5. Do not be afraid to think wider and invest time in tools. In our case, this is a convenient showcase with documentation and an analyzer for using components.



All Articles