Craft a bullet proof components library
Video Transcription
Thank you everyone for um attending this talk. Um I'm gonna first introduce myself. My name is Susanna. Uh I'm Italian. I live in Spain and um I'm very excited on being here today participating to this event as a speaker. It's a big honor to me.Um I'm a software developer. I started in 2006. Uh So now it's about 15 years coding. Um Currently I work at playtech as stack lead of a product called the games marketplace. And I love problem solving. And uh I like even more developing beautiful code solutions, elegant, flexible so that they can adapt to product requirement changes. And last the, the standard of time um when I'm not working, I enjoy south of staying outdoors and practicing sports. Uh Also I have a dog which is uh appearing in the left side corner of this light. Uh What I do for a living is basically coding. Uh My main language is javascript, uh mostly familiar with ecmascript six version and I build services on top of aws as in infrastructure and uh using no Js frameworks like happy uh to build restful API S and uh non relational D BS like Mongo Redis for stored database in form of bison objects.
And uh on the front end, I mostly use React Redox as well as core web analogies. Of course, my team and I we build a single page web application. Uh You can see a few screenshots in there. I enjoy pretty much all the aspects of building it. And one of those I pay more attention to is the U I. So behind these user interfaces, there is a lot of work. Um uh I can see the moderate the moderator talking. Oh God, one second. All right. Let me check the screen settings. Sorry. Uh There must be sorry. OK. Got, got it. One second guys. Sorry for this sharing. Yeah, apologies for that. As I said, not familiar with uh this application. So we are gonna go back to the first light and start over. Well, you've already um OK. Can someone confirm these lights can be seen? OK. All right. Thank you, Christina. I apologize. Well, as I was saying, uh you've uh you've already heard what are the technologies are I'm more familiar with? And um these are a few screenshots of the uh user interface I built with my team. And as I was saying before Christina kindly reminded me um I was not sharing screen uh behind this U I, there is a lot of work in this chain. I sit more or less where the magician is and basically my work as a developer is to deliver components that are easy to maintain, flexible so that the product can adapt quickly to requirement changes and also scale.
Um This sounds simple, but it is actually one of the hardest thing to achieve in software development. And um in order to, to explain this, I'll, I'll put you a simple example. Uh this is kind of a personal experience. Um in our product, we have a drop down component which uh which has been betwee between us since the beginning of the, the product. And uh well as you can see, uh this is kind of a component representation of the actual visual component. Um People that's familiar with uh it and code and development, we usually represent systems or components using boxes. So imagine this is our selectable drop down this box in here. And what the arrows on the left side represent is the input that the component needs in order to function properly and in order to render a result. So for this example, as I was saying, we had this drop down, we had uh which had the three inputs parameter, which were an array of items. Uh Boolean data type for determining whether the search had to be advisable or not. And a third parameter called multi, which would determine if the drop down is multi selection or not. And uh well, one day at planning, someone asked us to provide an estimate for something that apparently seemed to be a small task.
This component was buggy and uh we had to implement few tiny small changes on it. So as a developer, when I saw initially what the task was about, uh I was feeling like really confident on how to fix it. And I think uh so were my colleagues as well. And so we confidently say, yes, sure we can do this in less time. That's what it takes to describe the issue and guess what happened next. So the sprint started and one developer can't remember who was it? Probably it was myself uh when, when the task was approached, this is what we realized. Well, first of all, obviously, the drop-down component was buggy, which is not a surprise uh developers, we are human and bugs are kind of expected and it's fine as far as you know, where to fix the issue and you can do it quickly. And uh secondly, the drop down was um obviously used in many views of the application, which is also a good thing because one of the main purposes behind component is that is the ability to reuse them. So that part was fine as well. What was not so fine is that um and what made this task such an epic thing was that uh every view where the drop-down component was included, had implemented its own fixes to kind of deal with the issue that were part of the original component So basically everyone knew there was a problem with it and everyone decided to look somewhere else.
And so the day we were actually uh ready to fix it for real, what we find out was that there was a lot of duplicated code everywhere and there were, there was not a single place where we could actually fix the issue. So essentially, we weren't really able to apply the changes required just by fixing understanding one single component. And instead we had to go basically view by view, remove code factor that into the component and the number of view was not small. So as a developer, what I've just described is probably one of the worst situation where you can see yourself. And it's really sad, there are a few reasons for it. Well, first of all, you have to somehow explain your boss why a task that's apparently simple, takes days, like instead of minutes or hours, then you'll find yourself fixing the same thing over and over like a robot, which is probably the most demotivating thing that can happen to you as a developer.
Um Then probably at some point you start feeling under pressure because you gave an estimate for the task and you're running out of time. And that's a very bad place where to be eventually, once you get your task, hopefully deployed somewhere Q A probably will push it back because the more places you have to touch to actually fix fix something higher are the chances you might introduce accidentally another defect elsewhere and so on.
So what's the takeaway from this story? Well, to me, it's pretty clear when a component is not well designed uh as a component, then scaling and adapting the uh to product changes becomes really difficult or even almost impossible task. So as a developer that actually loves her job and wants to keep it, what can I do to prevent this kind of bad situation from happening? And this is what I think about it. These are the three pillars, I find out to help myself to make sure I develop bulletproof U I components and more importantly to be happy and be productive at work. So we are gonna go through each one of these pillars. Next, the first pillar is components driven um many years ago when I was building a website for first time. Um probably one of the first things I've learned is that a website or an application, most of the time is just a composition of many pieces and repeating patterns. This term component driven development, I think it was used for the first time in 2017. And that was the moment where most of the major javascript frameworks uh adopted the component construct, few of them, which are pretty popular as an example, angular amber react, they are all based on components.
And uh this component driven development refers to the practice of building user interfaces with modular components from the bottom up. So this means you start building basic components first and then you progressively combine them to create more complex ones. And that's kind of uh what the pyramid on the left side of this light represents. One important thing to observe in here is that the y axis represents time. So in this pyramid, you can clearly see the layer where you should put more of your effort in development is the base components. Those that brings you flexibility to build more complex pieces. Um There are five simple words to describe qualities of good component. And this is kind of a definition I grabbed from um one of the very smart guys that I follow on Twitter and linkedin. And uh the definition is that a good component should be focused, independent reusable, small and testable. The guy that defined this kind of rule. It's uh Adios man and he is um a performance software engineer at Google and it has a very nice article about this and I highly recommend to have a look at it. There are many benefits in being component driven as a developer, I can tell. Definitely it has a positive impact on development which becomes faster. It also helps to maintain more easier uh the application and of course it helps in having reusable uh components. Um OK, I see a message on the Skype.
Oh Sorry on the chat that you can see All right, that's fine. So my advice, if you find difficult to schedule your frontal application, then review what is the methodology you're using and embrace component driven if you are not doing so yet. So this is the theory, but uh you know, between theory and fact there is a huge gap and that's where people like me sit uh in making things happen. So how do you actually get to build focused independent reusable small testable components? Well, there are many tools in the market for this now, one that I discovered a couple of years ago and I really love it is called storybook. Um This tool helps developers to focus at component level. It is basically a U I component explorer as you can see in the GIF running on the slide and it has a lot of features. The mains one are it allows developers to construct component in isolation, as I said before first and most important then it helps you to simulate different states of the component. As you can see in the right side of this GIF. There is something that looks like a form. Well, that's the interface that allows you to feed your component with specific property values. As you can see here in the right side, there is uh still this uh component representation of the visual component.
So that form basically helps you to test how the component looks in reality by interacting through uh it has many other features like the ability to switch between different viewpoints and orientation. It has many add ons you can add to your particular setup. A very useful one for developers, for example, which you also can see in here is what is called the story source and story source. It's basically once you've set up uh the particular state for the component under their test, then the story source will generate the code for it. And so if you are a new on boarding member of a product that is built with components that are exposed in storybook, this is fantastic because you don't need to go to the actual component implementation, do reverse engineering to understand how it is built in order to know how it, how it works, you just go to your storybook, you set up the state, you see how the component plays and then you copy and paste the paste the code in whatever is the view you're working on.
So that's a fantastic one. Um What else? Well, this tool is also compatible with pretty much every modern framework like VLT angular react amber web components. And it lives alongside the application. You can, you can deploy it to the same environment where your application lives.
It's also really easy to install and hopefully we'll talk a little bit more about it uh towards the end of the session, right, the second pillar that really help uh and I try to stick to, to build, bulletproof your components is solid. Solid are five software design principles uh intended to make software more understandable, flexible, maintainable. And they have been in the history in the industry. Uh even before I was born, probably since seventies when the C plus C++ and other new programming languages, object oriented were kind of exploding react is not object oriented by nature. But what I can tell is that many of the ideas behind this principle can be used to write better code and will help you to achieve more reusable and solid components. So we are gonna go next each um through each one of them. The S letter in the solid word stands for single responsibility principle. Historically, this principle was described as a class or a module should only have one reason to change this principle. What it tells us is to separate methods into different classes if they change for different reasons at components level. This principle is similarly known as common closure and it says something like group in the same component classes that change at the same time and for the same reasons.
So pretty much the same thing react is component based. And the way I understand this principle in react is that components should have a specific purpose and therefore we should use small presentational components and we are gonna see this through a practical example, right?
So in this light, you can see there are two views and uh both of them have highlighted in a blue circle, a component which is the drop-down we were previously talking about in the first view. Uh This drop-down is used to show a list of gain types. While in the second one, it simply shows a list of gains. So in the context of object oriented design, we could see this drop down as an object that is in instantiated by both views because of its features, coding a drop down that show a list of game. It's easy, fairly easy. Here's an example. So this is a piece of react code. Uh by the way, this talk was initially planned to be 20 minutes. But since it magically doubled the time, I think I can even even explain this piece of code a little bit more than what I was intended to to to do. So as you can see, it's a functional component that deals with an internal state. When the component mounts, it performs an http to a particular end point. And then once the effect of that code is actually captured, it renders the list of options. As you can see, it has a return value which corresponds to the rendering function. And then on top of that, it also has a hardcoded unchanged event that gets executed whenever the user select a particular option. So this component works and uh it has no syntax error.
You can build it using web pack, it will work the problem is this component design is not OK because it has too many responsibilities to achieve single responsibility. What we would need to do is to design a component that is a presentational one and receives data and the unchanged callback as property only provided by the parent component. What we are just describing now by words, the way it can be represented with a diagram is like this. You see we are using the same kind of the same diagram thing in the we were using in the previous light, you can see the property the input of the component and the expected output on the right. That is a good design for this component. And uh once we know what the good design is, we can actually go ahead with our javascript react angular whatever is the framework you're using and implementing it. And for instance, in react this would look something like this. As you can see there are clear differences between the previous implementation. So as you can see in this functional uh component, you receive data as an array of objects which shape it's defined at the bottom ID and name and the unchanged callback.
And this component does honor the single responsibility principle. Uh Just a short mention when this rule is not followed, usually you'll find a lot of duplicated code and you fall into a lot of uh merge conflicts when creating for requests next. Uh By the way, I hope the moderator can flag me from time to time on how much time I have left. Because um when sometimes when I talk too much, I kind of lose notion of time. So moving forward, open, close, this stands for open close principle and originally was described as a software artifact should be open to extension. But close for modification, this principle tells us to design the component in a way it is possible to add new functionality without changing the existing code. And the way I understand this and react and the way I apply it is that components should be extendable using render crops or composition. Again, let's let's see this through an example. So we have this view on the left side and it uses the drop down which we defined and designed and developed in the previous light.
And uh now the product owner comes and says, hey look, Susanna, I want this drop down on this particular view to display the game type icon next to the actual game name. And again, to achieve this code wise, it's a simple task here it is. Uh so as you can see in this piece of code, there are a few changes compared with the previous version. Uh Essentially there is a map that links the game type with a particular icon and then the breaking change. It's in the render method based on the game type, we either display the icon and the name or just the name So what's the problem with this? Uh Well, this change modifies the component behavior in a way we don't want to, we wanted to extend the component to achieve new functionality without breaking the previous use cases. And this would be a better approach, we can achieve open, close by defining a render probe to pass the rendering component for the actual item option down into the drop down from the parent. And uh this design, it is solid and the way we achieve it and react, it's like this. As you can see in the functional component signature, there is a third parameter which is item render, which is just simply another react component.
And uh yes, we still have a condition in the render, but this element is not mandatory. So in all the views that were previously using this component to render the drop down, the behavior is still kept and only those which actually passed the item render property into the drop down will fit the new requirement. Next list of stat institution. Whenever I read this principle, after a long period of time, I get scared because the original definition sounds like a nightmare. The L letter stands for Liskov, which is the name of the, the surname of the author that invented this principle. And um it sounds really long and complicated in reality. The idea is is quite simple, what this principle says is that an object of type S should be replaceable. With an object of type T as long as they share the same super type in object oriented design. This is subclasses should be substitutable by super classes. But what it means this when we work and react, this means components should abide by some kind of contract. This principle refers to design components by contracts and I'll expose next to this with a very, very visual example what this looks like, right? So in the previous examples, we've defined the set of properties for the drop down.
And if we extract these properties into a separate object, it would look like pretty much what I have here at the top right corner, which is a selectable type. As you can see, it has data on change and item render, which are the property we've been designing for this component. Uh So basically, in short, we can say drop down implements selectable type. Now, if we have another component implementing this same prop type schema for instance radio group, then we can easily replace drop-down usage in this view by radio group uh without altering expe expecting behavior as the user will be equally able to select one single item out of a list of items.
Uh pretty amazing by the way to be able to achieve this with less than one line code change, isn't it? That is what uh solid principle uh makes to your code. Um Next, the next principle is uh interface segregation and um it's simple and clear. It says something like classes should not be forced to implement methods they they don't use. And uh at components level, this principle is similarly known as common closure principle. In react I apply this principle by specifying the smallest set of data required by a component or a function as an example. So let's say we are asked to develop this view. As you can see, there's a lot of stuff in there and there is a generic scope which refers to the game. There's a lot of game information on this page. Uh We could, we could describe everything we see in this page. But in short, we have uh we have a game banner, we have a game selector, we have a couple of buttons, we have a list that shows stuff and then we have big icons that display some more game information in in a visual form. So if I were going to implement this view, probably the first step I would have to follow if I am a developer that follows component driven approach would be to break, to break out this view concept conceptually in many, in many small different pieces.
And each one of those, those pieces must have a specific purpose. And then because I'm only one person and I have only one brain and two hands, then I would probably start by one single component which is game banner. Um So we could say game banner receives game as a property and renders the game banner something like this, right? Well, this is a violation of the interface segregation principle because you don't need the whole game uh object for the game banner to be able to actually render the game banner. All the component really needs to know about is is three or four simple properties uh which are uh yeah, the source of the image, the game title, the game type. And maybe there's some more text information over there which I might have overlooked. Um So based on the second design, um that would be this is an error. This is what we don't have to do and this is what we have to do. Um One of the benefits as well of honoring this principle while working in react is that if you look at at the previous uh at the previous example, code, this one thanks God, the components name are meaningful.
But if you look at the, let's say the signature, the way the component is used in the code, just by looking at the interface, you would be not able to tell what the component actually needs to do its job because all the components have the same interface. So how do you know what, how can you eventually guess what each component does? You can't, you have to open the actual component and look at the implementation details. So following this principle helps a lot as well making your code more readable and having clearer interfaces. Um Right.
The last principle is dependency inversion. And um it does to depends on abstractions and not on concretions in object oriented programming. This means that a particular class should not depend directly on another class, but instead relying on an abstraction uh let's call it interface class.
Uh Sometimes uh this principle uh leads to over engineering. Um But we are gonna see a practical example of a good case on how to implement this in react. Um Well, the way I understand this principle in react is um we should um we should specify parameters of function or values rather than hard coding them into the actual component. Let's see a practical example. So once more, uh we will use the game profile view to show the principle in action. Um This component as we saw before shows game information. And obviously, this information must come from somewhere uh data in um in a single page application is usually retrieved through uh restful API. And uh this means basically there must be a back and API deployed somewhere and your front end application will create an HTTP request and then back and will reply back and we'll we'll tell the front end here, here's your piece of Jason do whatever you want to do with it. So the actual part of connecting from your client application to the back end uh in javascript uh can be done in different ways.
And for instance, a very popular library for handling this is fetch the the the whole thing of dealing with the http connection, hand handshake um reading data parsing data. And all of that is abstracted into the fetch library. So it is pretty straightforward to include few lines of code in your view, component, uh fetch game data and then deconstruct the response and pass each property value into each uh respective component based on the components need. For example, this and this implementation does exactly what I've just described. And from components perspective, this is how it looks like. And this component design is obviously not following dependency inversion principle. As game profile view directly depends on fetch library, which is nothing else but a solution that solves a particular problem. And the problem with this is that as an example, let's say tomorrow uh N PM flags or bans fetch because there is a critical vulnerability. By the way, this is very unlikely to happen, it's just an hypothetical case. So if you had all the components in your application built, breaking this rule in this way, you are gonna see yourself in a pretty bad situation because the only way to fix it is gonna is gonna be going through every single one of the components and replace one by one, all the usages of fetch by another library that hopefully doesn't have critical vulnerability.
So following the penicil version principle, we should be able to achieve something more like this, which in terms of the game profile component could look like this. As you can see what we've done in here was obstructing the fetch operation into a separate function. Uh Let's call it that game. Uh It could be an API service with more logic for now we call it just get that game. And uh this functionality is passed down into the component from the parent and implementing this solution in react uh could be something similar like this, right? So we've gone through the solid principle. I hope the example were quite self-explanatory. The third pillar to build bullet, bulletproof U I components is test if we design by contract as we should be because we know what is the expected behavior of each one of our components way before we put down even a single line of code, we should clearly have few test cases defined.
For instance, in the case of the drop down, probably the most obvious one is it should display a list of elements, right? But then as the application grows, the product grows and the requirements becomes more and more. You probably end up having another use case, something like it should be optionally able to display a search box for instance, or you should be able to mark and a batch, the number of selected items or you should. Well, you should also have probably the very first use case it should render no matter what, that's my favorite one. Every single one of these use cases. It's a clear example of component state because the only difference between each use case or test case is simply a different set of property values passed down into the component as you can see in uh in those pieces of highlighted code in the slide. So in storybook, each one of these states is a component story and writing stories for a javascript developer is a cute game. Believe me, this is what a storybook story look like. So maybe some of you in the audience will be thinking right now or wondering if it's so simple, why it's so hard to put in place?
Well, it is so hard to put in place because the difficult part is not the testing, the difficult part is to be able to design a component that is solid and therefore it's easy to test. And what you can see now on the right side of this light is how the catalog of stories for your component look like. So basically, once you have your stories defined, you can see those through the storybook Q I and you can easily select one of them and see what's the generated output for that particular use case last but not least I cannot end this talk without mentioning one of the most useful features that storybook brings us is an easy way to automate visual regression using the service that uh best fits our need.
That can be a cloud service or can be a library deployed somewhere in your C I environment. I highly recommend trying Persia which of offers uh visual regression as a service and plays really, really well with storybook. So that basically you will be able to use each component story to generate JP G snapshots and validate them on subsequent builds. One last final tip, if you actually get to the point where your amazing team is able to develop components in isolation, then the next logical step is to share those so that you can reduce them in multiple projects. And there is a fantastic tool that can help you to maintain in one single repo every one of your components, keeping a separate versioning so that you can publish them separately and also developers of course, can import them without having to include the whole library in their project.
And the tool name is learner and I highly recommend its usage for managing components libraries. These are a few keynotes from the session and feel free to throw any question through the chat now or later on. Uh sending an email to my address. Any question, I see. No questions. All right. So if there are no questions. All right. Oh OK. Amy. Well, it OK, nice to hear that. I'm glad that you enjoyed the talk. All right. Oh Someone missed the first part. All right. So I'll take OK, I'll export the presentation and I'll send you the slides over you Savita. So that or maybe we can even, yeah, we can even have a talk later on. Fantastic. We'll do that. All right. Thank you, Peter. All right. So, well, um I think I can probably stop uh screen sharing and if there are no question. All right, how does automation fit in dynamic components? Uh All right. Uh I'm not sure what you mean by dynamic component because what I was showing were actually dynamic components. I'm not sure if you managed to see in uh one of the first slides I was showing storybook in action and one of the add ons that you have available in there is called controls. So controls, basically what it does is it expose an interface for you so that you can interactively feed your component uh so dynamically with the values you want and um regarding automation uh well, uh well, all you can do with the storybook and Percy is that uh you can set up as many use cases as you want.
And um and of course, you can link the execution of the visual regression with your continuous integration pipeline. So it fits uh pretty well in because it keeps changing. So Q A automation is always challenging person is good. I agree. But from Q A perspective and to MQ A automation gets challenging. Right. Uh Right. Right. Of course. Well, in this talk, I was focusing on the uh components library thing and components library is supposed to be a collection of components that you can later on reuse in different projects. And therefore it's kind of atomic stuff. Um There is something called um atomic design uh which defines the hierarchy uh within your component structure that goes from eight from atoms through molecules to organisms to templates, to pages. So the way I see end to end automation for an actual whole application is not through percy because this tool becomes really, really valuable and uh useful for those elements in the hierarchy that stays at the bottom. So it's basically your your your uh basic component library and maybe molecules and organisms. But for pages and for the actual whole application, I would go with the different testing approach.
So thank you everyone and feel free to get in touch if you want to know more about Solid React storybook or Percy. Bye Mike.