Components, 
Patterns and Stuff 
It's Hard to Deal with

Marco Cedaro speaking at London CSS in February, 2017
51Views
 
Great talks, fired to your inbox 👌
No junk, no spam, just great talks. Unsubscribe any time.

About this talk

A brief run through a few ways of handling flexibility when it comes to patterns and components: modular architectures are hard and defined patterns need to express the right level of flexibility not to defy the point of a pattern library at all.


Transcript


Before we start, just a quick question. Is anyone of you actually working with a Pattern library in your job? Okay. Is anyone wishing to work with a Pattern library but can't for many reasons? Okay. Is there anyone using CSS modules? Okay. Cool, because CSS modules might solve most of the problems I'm going to present here. So the fact that you don't know about it much is good. So, again, this is a talk about modular architecture. My name is Marco Cedaro. I'm a Javascript engineer at Kahoot. Yes, you're going to get a Javascript engineer talking about CSS. Yay. Everyone is upbeat. And, again, this was a talk I created for an internal meetup at Kahoot. We were trying to figure out how we could sort our modular architecture and the problem we were facing with it. We have a Pattern library. It's not super truly maintained, but we try to do our best to keep up. So again, modular architecture. Even though, again, maybe it's more classes and components sort of thing. It's not really the modular architecture, but, yeah, then I thought about it, and it's really is components and modifiers maybe, or even components modifier and containers, or component modifier, containers, and overrides. And I was really confused at this point. I was trying to frame in my mind what was the problem that we were facing with our structure. So I came up with this, which is components, patterns and shit it's hard to deal with. And it's good, it sounds like. So that was the title. And considering all the talk we developed, I felt this was great for a movie reference, and so this is...or how I came up with a good use, of course, from <i>Lost in Translation.</i> Who saw the movie <i>Lost</i> <i>in Translation</i>? Okay, quite a few. Did you get the sense at the end where you were like, "What did I just see? I just lost two hours of my life?" Sort of thing. Did you get it? I did. I did. So I hope that the talk doesn't go in the exactly the same direction, but I think it opens the same amount of open questions that that movie gave. You might get to the end with more questions than when you started hopefully. So, again, framing the issue, what the issue we are facing and what the question I'm trying to face. I think there is a lot of text in this presentation just for you to know. So, like, how do we get to reuse our pattern libraries' items, you know, and how do we manage to get them in our code in a way that is not a problem to do it. Or in a better way to face it in a better way, how do we reuse our patterns in slightly different use cases and how we handle that in the code? And that is my reaction to the thing, like I wish I could slip that. I don't want to the deal with that. So, again, let's give it some frame. It's not about a specific task...stock, sorry. It's not about React because I've been told that it could...like, it look like it was React. The examples are in React because it was easier for me to just make an example out of it, but it's not about it. It's about modularity, and I've been facing these same exact issues working in an environment in which Mustache was a template engine, so you can have the same problems in very diverse stacks. And it's mainly about maintainability and use of the pattern libraries and how to build modular architecture. So what I've been seeing in the past ways we add to actually reuse our patterns, our components, our blocks, elements, and modifiers, and to make them flexible. I'm going through a few examples of what we did and try to figure out why it worked and what didn't work, and hopefully that will trigger some conversation about it. And then I'm going to present some suggestion of how we could do it in a better way maybe. And then I'm going to ask you if you ever tried the same and how it worked for you. That's pretty much how this talk is going to line up. So the first thing I've seen quite often is class name injection, and this... I want to go the bar when I see that. So you can see something like that. So we have an icon button, which has its own class name, domain, and whatever. And then we inject this content action button. This content action button is a class name that is on a completely different name space. It's the content action domain and file. And so we get content actions that contains the content action. And then we get the button that does some rows for the button in that context, and some states for over focused inductive. Has anyone of you ever written code like that? Sort of? Okay, one. That's good, because I hate it. And I've done that in the past. I'm not judging. So the main problem with this that they see is that these rules are going to interact with the base button. And the thing is, you never know how they're going to do it. And if you're going to refactor the base button at some point in the life cycle of your app, you're going to end up with a side effect here. Maybe, maybe not, but maybe yes. And the problem is that if you are using this technique, you'll never know because you don't know what other developers could have already done, extended, or changed in the modified class names and different domain and spaces because when you change the button .scss, you're not going to know that this file has different class name. But moving on from that, even these two, which seems quite inoffensive, are sort of a problem conceptually if you're using a pattern library because what does these two different overstate mean in a context of which you defined what a button is? The button should have its own over focus inductive. Why are you overriding it here? It kind of defies the point of BAM at all because you're applying a specific style in a context, and BAM works the other way around. BAM defines component that you can actually reuse as they are everywhere. So it does work. It's kind of cutting the corner, but it does work because you can extend the button in any way you want. Again, do we really want to do that? The button gets extended in ways you don't know. The code leaves in different files. It's really, really hard to keep track of the side effects we get if you refactor the original component. And then we are creating many variants of the original pattern that are not tracked anywhere. And good luck doing visual regression. And so, all in all, there is no other technique that offers the same flexibility, but do we care? Open question. Another way is ad hoc BAM- like modifiers, something to solve this kind of problem here. Too tall. Did anyone tell you you're too small? So you might end up adding components that are well-defined like a dialogue. And then you have this specific dialogue user intent, which sounds really like an ID more than a class name, right? But it follows the BAM pattern, sort of thing, like it's the modifier, so inject the class name, but it's the same name space. So this is kind of good because you got the dialogue in CSS, and then you got this modifier within the dialogue, which makes it much, much better in terms of maintenance, but it kind of, again, defies a little bit of the point of BAM, like you are using basically an ID, let's be honest here. And how many modifiers are we going to need if we start going down that path? And when we get to this point...this is real code, by the way. I'm not making anything up like this is actually code in our code base. How many of these are we going to end up with? And if we refactor the dialogue, how many of these do we need to take care of? Does this affect my productivity at all? Like, in this one, only the height changed. Like it's kind of weird, isn't it? Anyone wrote code like this with specific modifiers? Okay, so you have a problem you could [inaudible]. And I do as well, apparently. So, again, the practice gives a lot of flexibility because we can actually create modifiers for whatever use case we want it, and it gives a reasonable control. So it's much better than the previous one because everything is the same space, is the same name space, and we know what it is. Again, it gives the generic dialogue specific knowledge. Sorry, the knowledge of a specific implementation of the dialogue itself, and the file size may be affected by a lot of dialogue version that I'm not using in that page specifically because it might be across the app, but not there. So do we really want to ship around a huge file for something that should be really, really basic? Maybe not. And again, do we need that flexibility? Should we really have so many variants of the same dialogue? Is that the case [inaudible]? We just walk and talk to the designer to get some sort of ratio about how we should use the dialogue maybe? Again, open question. And then another pattern that they saw quite often, which is I believe much better, is predefined modifiers. So these are special components, and this sort of thing. So you have a class name dialogue prompt, which is not a specific implementation of the dialogue. It can be used in many parts of your website, and it's actually probably used in many parts of website. So this class name gets injected. You get a very specific implementation of it, which again, is not used once. It's like is recurring in your app. And even though it looks like the previous one, the semantic reasoning about this is completely different because, again, it's not...it's a predefined favor of the dialogue. It's not something made up on the spot for something specific that we didn't know where to fit. So here we kind of revert the dependency. So the pattern goes back to the center. We predefine stuff. We make it easy to define the responsibility, and to refactor the base component because we know that there is only that thing or those two things, etc. The only problem I see with it, and I saw that many times, is that sometime you get plenty of obstruction. So you create patterns for everything while they don't actually exist. And, again, maybe take a walk and talk with your designer to figure out if that is actually a pattern or if it is an exception, because if you are creating a pattern for something you used once just because you think it might be reused, I'm not sure it's the right obstruction. But it's definitely a better practice because we identified the variants of the components even though I would move to something like that without injecting the class names. Like if we have a set of types that are defining the CSS, probably the API that your template engine should provide, should reflect that amount of types rather than giving freedom to inject anything. Anything like that wrote by anyone? You. Okay, cool. Do you work at Kahoot? Okay. Then at some point, thinking about that and working around, I realized that I was looking at it from a completely different angle, like it was the completely wrong angle. Also, this slide is, as an inner joke, because this quote is not from the movie, so it's wrong [inaudible] of the slide. It's my mind was exploding. So I went back, and then tried again to think about the issue. So the issue is still this. How do we reuse our patterns in slightly different use case? But maybe the problem is actually what are we trying to solve doing that? Like, why do we need to do that? What is specifically...what are these use cases we need to work around to make our pattern fit in those boxes? I don't want to feel like the kid that tries to smash a circle in a triangle, you know? It's like we need to find the reasons why we're trying to do that. So I did something that is very JavaScript problem solution. And that's the good part. Does it get easier? No. But at least we know where to start. So I made a list of a few examples of stuff I experienced myself that is something we were facing when trying to create modifiers, injecting class, create types or whatever. And I tried to find alternative solutions, which might be worse. I'm not saying they're better, but the alternative solution to the patterns identified before just as an exercise to see if there were other ways. So the first thing, one that is recurring quite a bit, is how to arrange a component in its parent space, right? So you have a button, and the button floats in a, I don't know, anything around it. How do you position this button around in that parent? One potential solution, instead of injecting the class name, is to drop the element with the parent dev if that's the class name you want. So the button is basically...sorry, the dialogue is untouched and is flexible, and the constraints of the space are given by the parent container. This kind of makes sense because every single file has its own level of responsibility. So the parent again is just adopting to the constraints and the children. Sorry, the children is adopting to the constraints of the parent is giving constraints, which kind of work also for humans. So that's good. Again, the responsibility are neat and very specific clearly. When you open a file, you see what's happening. That's incredibly good. And, again, this is way different because it doesn't affect...sorry, it doesn't affect the dialogue itself. It just drops it. That comes with the cost of slightly heavier HTML though, the [inaudible] or how they call it. So this is your real problem. Anyone done anything like that? Okay, three, okay, which end up little more. Do anyone else have to deal with these problems? Okay, no. Maybe you have a lot of answer I didn't think of. That's good. We can have a chat in the pub afterward. No, good. Usually, I'm rushing. Last time I gave 83 slides in 15 minutes, so I need to... Okay, so, another thing is the arrangement in relation to other components. Maybe you want margin, paddings, and space definition across different components within the same space, and you don't really want to create droppers for everything because, again, the HTML would explode and the DOM as well. So something we could come up with, and again, I'm not endorsing this, but could be, some upper classes, which could be genetic classes available to any component that would modify only a small set of properties. In this way, these upper classes are expected, right? So the component knows that it has potentially to face them and would adopt accordingly. Yeah, so there is one great benefit to this. You don't have to come up with new names for the classes or modifier or whatever. You don't have to obstruct anything. These are generic and very low level on specific functionalities, which is great. And it also lets you go back and think about the spacing of your pattern library, which is something that sometimes we forget to think about. Sometimes we talk about buttons, dialogues, whatever, but we don't think about them in relationship when we build something. But, again, it might not work because these classes could explode and you can get stuff like this, which is disgusting to be fair. But, again, it's up to you what level of [inaudible] you might want to get to. But still, it brings back the attention on the pattern library, which I think is good. And then theming. Theming is another thing that sometimes we need to do. And one technique that...so, yeah, for example, this icon here needs to be a certain dimension and not the standard one, like within this context. And this is not something we can get away with because sometimes we have elements that needs to adopt to different space, and icons are the best example, I think. So one way we could solve that is to use mixins in SaaS, for example, so we can have the icon of CSS to expose a mixin that is available for defining icons, and the question content block would use that mixin to define how the icon shows in its space. This way, we can get...sorry, this way we can get the icon to define a sort of API that can be used by any other component to resize itself, and the order of...the responsibilities are pretty clear. The icon defines how the icon behaves, and the question content block consumes it. I think it's good because you are in control of what to expose. So when you write the icon, you know that the icon might need to be bigger, might need to be, I don't know, white or alternative contrast and whatever, and you can expose that functionality through a mixin. Even though on the counterside, the SaaS logic might get a little more complicated. Did anyone use mixin this way? Okay, a few. What else? So I think, again, that the problem goes back to the pattern library. When we're facing these problems, I think the reason is because we didn't think enough about the patterns we're using, and we're trying to reuse stuff that is not supposed to be reused. We're obstructing it too much or too early, and we get stuck in this...oh, I need to reuse that because it's there, right? And maybe it's a completely different functionality, but it just looks the same, and we think it's the same thing. So I think that the more you know where you are and what you want, the less you let things upset you. This is a great takeaway, if you have anything to take away from this talk. So that's all, and you're not hopeless. So what's the sense of <i>Lost in Translation</i>, sort of what did I just say? Okay, quite a few. That was me after the movie. - So I think the CSS module, as a technology, as a technique, is helping a lot getting away from these things because you end up having to use that pattern and you don't overthink other stuff. The CSS module basically sandbox the component style to that, and so most of it is taken away from you in a certain way. Like some of this stuff you can't do with the CSS modules. The worst and the worrying one at the beginning, like the class injections, stuff like that. At least as far as I know. I don't use them in production. I just played with it a bit. And even style component does the same approach of isolating, completing the component side, right? So probably if you are using CSS modules, some of these problems are taken away from you, and you're proposed with a much leaner way of doing these things. - Yeah. So this is why I'd like...that's why I mentioned that. If you used, they probably this tool doesn't make any sense. But from my experience, a lot of people is not using them. Yeah, mainly because while there are many reasons, one is the I will never write CSS and Javascript, and others are more trivial, like my text doc does not integrate with [inaudible] and I need to wait until they... - No, no, I know, I know, I know. I'm not saying it's a reasonable objection. I'm saying this is one of the objections. - [male] Great. Yeah. - Thank you, Christiano, [sp] I'll remember that. - This is a specific implementation of...that we need a dialogue, right? We need one dialogue that is specific to certain sizing, and they mention blah blah blah. And like either...instead of creating a modifier, I would rather create a specific component that's rough that. - [inaudible] right? Because... - Yeah, yeah. It's definite. I think it comes up to the...like if we think in terms of atoms, molecules, blah blah blah, this is...sorry, this is more atom or a molecule depending on what you see in there. And this is more of probably a template. Yeah, probably a template. Not even an organism because it's not reusable really. It's really something up. Let's say that if I want a pattern library that is shared across different projects, this would be the hardest. It wouldn't, kind of...depending on what, like... - Well, unless this is a... - [inaudible]. - Unless this is a specific sizing. - [inaudible]. No, I don't allow this [inaudible]. - Okay, fair enough. - Now, our case, [inaudible] we have icons. We fix its sizes. - Okay, fair enough, fair enough. - Wait, for this API though, like I control what to expose. That's the thing. Like, again, fair enough. I made an example with the width and the height. It could be the feel of [inaudible] of the icon. It could be...like, if we try to abstract this pattern from the width and the height and tried to relay that to anything that makes sense to you, I think the concept here is I bring this back to the icon. So this thing that I offer, the other developers to change and play with, is in the space of the icon, and when I changed the icon, I see that there is a modifier. So the icon will know that, like when it modified the icon, I'll know that these two things could be changed by an external file. And I'll develop my icon either knowing about it or knowing that I need to search for this and fix it. Sorry, for this and fix it. - Well, not really, but because it...like if you need to change this, yes, but if you like...when it comes to atoms, for example, you don't often change stuff. But even, like if you have an [inaudible] API in JavaScript, for example, you don't go there and play with API every single day, right? And if you do that, you'll version there is. So why can't we do the same with...that's still a way to control what you expose and let change. You're a little stricter and you're just specifying what you actually want, and that's a good thing probably because it give it a [inaudible] at the pattern library level. You want the icon only these sizes. But if that thought is not there yet and you need this kind of flexibility, like...and again, it might be that we're solving the problem in the wrong place. I'm not saying no. I'm saying, if you got to the point in which you have stuff like this, if you got to this point, probably is better stop a second and think why you got this name space in this file because for me this is quite dismal, and is going to bit you in the ass when you have to refactor the icon, and it's going to be a problem. So this thing solves it a bit. It gives you back control a little bit. Again, it's not perfect. I don't have a solution that they prefer in this presentation. Like it's more of triggering a conversation and see what people thinks or do or... To the pub! No, sorry. - [Male] To the pub then, almost. But first of all, thank you very much, Marco. - All right.