How do you write a good component? In this talk we’ll explore several different patterns for writing better components. We’ll look at techniques for simplifying our components, making them easier to understand, and getting more out of the components we’ve already got.
Component Design Patterns
Vue.js London 2023
♪ Thank you for that intro, that was great. It's actually really awesome to be here today because exactly one year ago I quit my job and went into doing this whole like teaching view and writing articles and creating courses and books and stuff full-time. So thank you for having me. Applause So I'd like to talk to you about clean components and in talking with different people in the community and seeing what questions are asked on Twitter and things that I get in my email inbox, I have seen two fundamental questions come up again and again. The first is that we want to know when do we create new components. Do we create smaller components or do we create bigger components? Is this component too big or too complicated? Should we pull it out into something else? And so this is something that we we deal with every single day. But once we've figured that out, we also need to figure out how we do this well. And it's not just about moving pieces of code around in your file system and doing all sorts of of things like that, but we actually want to simplify our code base and make our code easier to use. So in this talk we will cover three main things, patterns and methods for how to write cleaner components and to simplify our code. And we'll just scratch the surface of these two questions because they're pretty huge questions, but hopefully you'll come away from this with a couple things that you can apply. So we're going to cover some patterns there and at the end we're also going to cover when not to create new components. So the first set of patterns is around vips. And they're really nice because we can basically look at the different branches and most of the time we can extract the code that's in the body of each branch without needing to know much more about the code that's going on there. And we know that we can do this because of two things. The first one is that each branch of this conditional is semantically related. So the code that goes into each different branch works together for the same purpose. You might know this as cohesion, but really we're just talking about code that works together. And the second reason is similar or related to that and it's that not only does each branch work together, but each different branch is distinct. Otherwise we wouldn't have a conditional. You would just have your code run. So to see this in more detail we're going to take a look at an example. And this example is... Oh, I forgot to connect to the wi-fi here. So we will not be looking at this example. So I'll just give you a quick explanation. It's a component that shows a list of articles on my blog. So either you have an expanded view that shows like the date and the description, or you can have the collapsed version that shows at the end of the blog post all the different related articles. So this is the code for that component. And I don't expect you to read through this whole thing right now. I will have my slides available later on. So just so you know. Yeah, so you can see that at the top level we have a vif there with the two different bodies of this branch here. And they do different things. One is a collapsed version, one is an expanded version. But although they are similar, although they are different, they are sharing some code in there. So they look similar. But we can refactor that, pulling out into separate components. And not only is this code shorter, but it's much easier to read at a glance. We can easily see article collapsed and article expanded and know that's the intention of what this code does. And this is what self-documenting code is like. It tells us what it does as we read it without us having to think deeply about what's the different conditions and all the different things that are going on. And one quick pattern that I wanted to to throw in here but don't have time to go into depth is that we can take all of this v4 logic here and we can actually push it into the child component. And the reasoning behind this is similar to preferring methods like filter and map and reduce over just writing out your for loop every single time. So what do we do when the branches are, even though they're distinct, they are quite similar? Well, something that we can do with this vf here is that we can take that vf and actually push it down into the child component. So we're taking the complexity from this parent component and putting it into the child component. So in our instance here we have this parent component here with our collapsed and expanded components and respectively they look something like this. So we've got a nuxt link in each one and the expanded one also has some paragraph tags there. And if we combine it we might get something like this article display component where we have taken the code that's similar and shoved it together and made it into one component that's a little bit longer but not too bad. And of course we have to take that conditional and now move it down into the child. So we have a few different things going on here. We've got this vshow where we have to switch based on this collapse prop and then the paragraph tags at the bottom we're going to to conditionally render as well. And then we also have to compute the class because one is flexbox the other is grid. In theory you can, you know, make it a single column grid inside of flexbox but this is just the first step in our refactoring here. So in the end by shoving this vf conditional from the parent into the child our parent component now becomes kind of pointless and perhaps we could even get rid of it. But we do have a pretty big problem in my mind and so that leaves us with when not to create this component. And so we have this short component but because we've taken two components that do different things and we've combined them together we actually made this component a lot more complex. And in practicing this talk and writing out my slides after a bit I realized that there's actually a bug in this code which I didn't realize at first because it is more complex. This vshow, this collapse here, I should have removed that negation. And so at first it's easy to miss that kind of a thing because there's lots of things going on here and and to understand this code and what's going on it's a lot of thinking, a lot of, you know, step by step looking through and trying to determine what is going on here. And so this is ultimately a question of is it better to keep, is it better to remove duplicated code or not? And lots of people like to follow dry, don't repeat yourself. But actually don't repeat yourself is more about the knowledge and the intent behind the code and not the actual characters on the screen. And so although those components look the same, they actually represent very different intents and so combining them together in this case was actually a mistake. So we want to revert back to what we had before with this parent component here. And then take this, these article collapsed and article expanded components and yeah and separate them out. So we have two simple components instead of one more complex, harder to understand component. So that is the the three patterns that I wanted to cover here and so now is the end of the talk where I get to shamelessly promote myself for a little bit. And I am working on a new course which should be coming out in a couple months which talks more about these kinds of patterns and goes more into depth about how do we create new components, how do we do that well and a couple other related concepts. So if you want more information about that you can follow me on Twitter or anywhere online and I'll be talking about that. I have also an instructor for Mastering Nuxt 3 which is in partnership with vue School and if you want to learn Nuxt 3, how to do full stack development. We cover everything from the basics all the way to authentication and integrating with Stripe and all that kind of stuff with that. And then of course there is this book as well if you want to get that online. There's also an ebook version so you don't have to have the physical copy. And there are my links and information. Thank you so much. Please take a seat. There were so many good questions but right now and I love that this one is still up there with one of the most upvoted questions. And it's one of my personal questions. Have you folks noticed the Michaels t-shirt? It's pretty awesome. Where did you get it from? Because I might need to order one myself. So I had a few years ago my wife got me a vue shirt for my birthday but you know it kind of gets old and worn and so I actually designed this shirt myself and got it like custom printed one. Nice, nice. Now you've got some inspiration you can go and custom print your own vue t-shirt. We've got a few other questions in here. I'm just going to jump to the ones that are relevant to your talk. We've got one that says smaller components can often be more performance. They don't load any css or JS when it's not needed. But when does the complexity of smaller components outweigh the performance benefit? And this is kind of related to when not to create a new component. So it's a bit of a long question but there's some substance in there like finding that right time to switch over. Yeah so I don't have as much experience in performance optimization of web apps so I can't really speak to that aspect of it as much. But I think in general there is this this question of how small is too small? Because eventually you get you don't want to have 30 files open and like each file is five lines because the switching, the context switching between each of those things then is the thing that makes it hard. So maybe performance in a you know mental capacity way. Yeah definitely there's always and it's kind of like what Evan was saying as well. There is like performance and there is like how happy are you as a developer actually writing the code? Yeah developer experience. developer experience is something you want to make sure you optimize for as well. And another one which is kind of a very vue related question. For large and complex components written with the composition api how do you recommend structuring the code inside the script tag? Yeah so one thing that I really like is to like we we can create these composables and so it makes it really easy to actually extract logic out of your component. And so you can do this like with with reusable composables that you might use in multiple different components but you can also do like a one-to-one thing where maybe maybe you have one component that just is more complex and you can't there's no there's no easy way to make it smaller but you could take you know take sections of that script and pull it out into maybe you have three different composables and those composables are only used in that component but at least it lets you break out that logic in a way that's that's organized and easy to understand. Awesome and let's do one more question because I know we're running out of time. How do these patterns this one's from Edward how do these patterns translate to a more abstract component library or design system? If you're already using a component library or design system and you also have these other patterns that you want to bring to the table how would you bring them in and incorporate them? Yeah I think they're it's a pretty similar approach I would say working on a component library is there's a lot more thought that goes into the the api like Eduardo was talking about of like making it easier to use and I think that can in some ways affect how you structure your components but yeah. Nice nice thank you. Now I know you have some extra copies of the book not just for the questions that were asked so if you did ask a question your answer got read and maybe if you also just want to check out the book I would say definitely go and meet Michael upstairs after this talk as well definitely be able to answer any other questions that we weren't able to get to but Michael thank you so much give it up for Michael.