🎞️ Videos → Objective and subjective quality of code and system
Description
Developer tends to believe that there are such things as objectively good code and system design. There are things such as best practices that can apply to every system regardless of context. This belief, while not completely false, is not completely true. In this talk, I will bring you to explore a characteristic is objectively high quality code and system. We also going to explore a characteristic of subjectively high quality code and system. And by exploring these two side of spectrum, we can see why subjectivity matters and how much does it matter to code and design. Therefore, we can understand which kind of practices need to be adjusted based on context and what kind of practices ring true to any type of software.
Chapters
- Introduction: The Quest for Objectively Good Code 0:00
- Speaker's Background and the Genesis of the Talk 0:22
- The Elusive Nature of Objectively Good Code 1:25
- Conflicting Coding Philosophies: Design Patterns vs. Duplication 2:08
- The Clean Code Movement and Its Critics 3:59
- The JavaScript Framework Frenzy and the HTMX Counter-Movement 5:10
- Defining Objectivity in Code 7:01
- Today's Agenda: Understanding and Defining Objectively Good Code 8:12
- Subjectivity vs. Objectivity: A Deeper Dive 8:38
- Identifying Your Coding Priorities: What Do You Care About? 11:53
- Objectively Good Code: Maximizing Goal Achievement 12:43
- Example 1: One Return Rule vs. Early Return Pattern 15:09
- Example 2: React's useEffect API: Simplicity vs. Clarity 19:05
- Example 3: One-Way vs. Two-Way Data Binding 25:41
- The Importance of Understanding Design Pattern Objectives 29:27
- Subjectivity Enhances Objectivity: The Key Takeaway 32:48
- Awareness Precedes Choice: A Path to Better Engineering Practices 35:46
Transcript
These community-maintained transcripts may contain inaccuracies. Please submit any corrections on GitHub.
Introduction: The Quest for Objectively Good Code0:00
Thank you everyone for coming. I'm Chris. Nice to meet you all. Here I'm talking about this topic.
Speaker's Background and the Genesis of the Talk0:22
Let's get start. I have so many things to talk about. A little bit about me. I'm working as a lead consultant at ThoughtWorks. I go into bunch of companies, try to make their software engineering practice better. I have been doing that for quite a while. I've been programming in many languages. There's some list here.
I learn a lot about different patterns, practice, how different communities thinking about different sets
of what is good, what is bad, what is qualities and what's not.
I also teach bunch of courses online, offline.
I'm follower of many programming communities, dramas, and debate.
The Elusive Nature of Objectively Good Code1:25
That's inspire me to this talk. เสียงมันนิดนึงครับ ไม่ค่อยดี
I have seen a lot of people in the programming communities and inside the companies that I work with, we are debating a lot about what is the best way to program things.
That's where this session coming from. Let's talk about a little bit of inspiration. I have been programming for 13 years now.
Conflicting Coding Philosophies: Design Patterns vs. Duplication2:08
We all know that we all must write a good code. But what is really good code? I'm pretty old compared to the audience here. In my university days, they taught me this book. This is called the Design Pattern. When I still in the university, they say that object-oriented programming is the best way. We all should learn about how to abstract things correctly. This is a book from GoF, which is actually acronym for Gang of Four. Sometimes we call them God of Four. They's like a very strong programmer. I don't know who they are. I just know their name. It used to be like a pinnacle of good coding design back in my university's day.
After I work with in the industry for few years, then I heard this talk from Sandi Metz.
She's very awesome. She's talk about how to do object-oriented programming. One topic that she talk about is the wrong abstraction is much costlier than duplication.
That also resonate with me on the experience level. Many people in the community agree with that sentiment. But now, then I realize that this is contradict of what my teacher taught me in universities because we were talking about need to abstract thing. Now we say that we shouldn't abstract thing so much.
Interesting.
The Clean Code Movement and Its Critics3:59
I think back again when I start my journey, like first few years in my programming career, we have this as a pinnacle of good code. It's called the Clean Code. Now we sometimes use the word "clean code" and
"good code" interchangeably for some reason. Come to think about it, is clean really mean good? I don't know. But something to think about. Then after that, there's a lot of article that talk
about maybe clean code is not the right thing to do anymore. I think this is article from Dan Abramov, which is a very famous person in React community. If you following the React, he's author of Redux, which is a very big state library in React. Now he's still working actively on React.
The JavaScript Framework Frenzy and the HTMX Counter-Movement5:10
Let's talk about JavaScript frontend frameworks. Boy, we have so many of them.
I think this is just five one that I can think of. I believe there's much more than five. I'm not sure even thousand at this point, but okay. And I think some of you resonate with the way that each framework do things. Some of you might enjoy Vue, Angular, Svelte, or React.
I found Solid to be super promising, but it's very hard to get a chance to work with it extensively.
So, there's so many frameworks, and I think the audience here, since this is JavaScript Bangkok, I think you have some favorite one. Maybe not in this slide, but I guess you have some favorite. And then a while, we have people who reject all the frameworks here and say that, "No, no frameworks. Let's do HTMX." And I think we have the session about this approach in the afternoon, which is interesting to see. And they say that is too complex and unnecessary.
But okay.
Well, lots of contradict opinion out there, right? Well, it seems we have so many opinions on what is the right way to build the system.
And when I see the debate, or when I even enjoy the debate myself, right,
Defining Objectivity in Code7:01
we usually arguing against if there is an objectively correct way to approach or build these things. Which is raise the question, is there such thing as
objectively good code, or is this everything is just an opinion? Or is everything is subjective and you can do whatever you prefer? And that is one sentiment that is very common that, "Oh, just choose whatever framework you like. Doesn't matter. Just choose anything that you good at. Doesn't matter." So, that's another stance that I have seen. And maybe they are right, maybe they're not, but the good question is, is everything subjective,
or is there some objectivity to it?
And my answer is yes, there is such things as objectively good code. But it is not seems like it's not like what we,
many engineer, might think about what objectivity means.
Today's Agenda: Understanding and Defining Objectively Good Code8:12
So, today agenda is I want to let's understand what objective really means. And then we're going to define what is objectively good code. And we're going to try to see some examples of heated debate in JavaScript communities and try to apply that and see how it can be applied.
Subjectivity vs. Objectivity: A Deeper Dive8:38
Okay. So, let's get start with subjectivity and
objectivity. So, I do the common first when I started talk, I do the very common thing, which is, "Hey, what exactly does it mean to be what objectivity exactly means?" And I Google it.
And honestly, I don't really like the definition because the different that come in is that objectivity means lack of favoritism and lack free from bias. And I don't know what you folks think,
but can we really define something by lack of another things? Can I really say mouse is defined by not a laptop? It's I don't know. But definition is weird, really weird. It's defined by lack of something. Oh, but true, maybe some word should be defined that way, but then what is really objective? Because if then I guess if I just walk around and chilling out, then I am being objective because I just chill and I have no favor. I just walking in the park. That's not really it.
And then so I try to do this again, just strip out objectivity. What about the objective, right? An objective is mean to have things that you aim for and you have a goal toward. And okay, this definition seems to be much clearer than lack of something.
But come get back to that a little bit. So, now I realize why people when people debate on everything, they try to put objectivity in as an adjective to everything every their opinion because objectivity seems to be defined as something good, lack of bad. So, my opinion is lack of bad quality, and I don't know. That's I don't think that's a productive way to conversation, but anyway.
So, if we take just the objective, right, then objectivity might be defined as to have an objective or to have a goal. And if we combine with the previous definition, which is lack of bias or lack of favoritism, then we might be simply define objectivity as to pursue some objective effectively with our personal bias or favoritism.
But okay. But then my question is, where does these goals coming from again?
And I'm going to answer that question with another question.
Identifying Your Coding Priorities: What Do You Care About?11:53
What do you care about when you are code?
There's many things that different people care about. Some people maybe is performance, readability, maintainability, security, longevity. Or maybe simply something like not need to wake up at night and fix the production problem. I think most of us care about that, for sure.
But I realized that these things that we care about
become the goal that we put forward.
Objectively Good Code: Maximizing Goal Achievement12:43
So, what does it mean to have an objectively good code? I think the objectively good code is the code that has highest chance of achieving the defined objective. It's simple as that. So, no favoritism, no personal bias, for sure. We have one goal and one objective. The objectively good code is the code that helps you achieve that effectively.
And now, let's raise the question about where does the objective come from? I think it comes from what we really care about. Maybe you care so much about performance, which is fine. And if you define that you care about performance, then you can have two systems and objectively compare those systems. Just look at how much time and resource is consumed. And now you can become objective about the system design itself. Or how much do you care about quick iteration? Maybe you care about being productive. We need to launch product quick. We need to fix things quick and make the software progress quick. And after you have that goal in mind, then you can be objective about it.
You can evaluate based on all stats and data. You can evaluate based on the time that you measure, so on and so forth. But once you have objective inside, once you know what you care about, then we can truly be objective about system evaluation.
And I think this is very important when we look into
different design patterns and architecture. It's very important to understand what we really care about and what the pattern cares about, and we can compare that. And that can lead into much better understanding of
how each pattern can benefit our work.
Example 1: One Return Rule vs. Early Return Pattern15:09
So, let's go through the example. I'm gonna start with a very simple one. Since I've been programming quite long, I'm not sure if new programmers have heard of this pattern. In the past, there's a pattern called one return rule. Basically, in programming languages where you still need to do resource cleanup such as C,
it is advised that you should have just one return.
So, you need to make sure that you clean up all the memories, connections and everything before exit. So, it was advisable in the past that you have one single return.
Today, I think we are more on the right side, which is the early return pattern where you try to
organize all edge cases and unhappy paths on top and return immediately just to make it cleaner to look. And if we ask which pattern is better,
I think it is very hard to evaluate on its own.
Maybe you think that the right feels right, the left feels right, I don't know. But once we put the objective into this pattern, such as if objective is to make sure that all code has proper resource cleanup, then it is pretty clear that the pattern on the right
is much better than pattern on the left. And on the opposite side, if we want to make sure the code is easy to follow,
it is pretty clear that code on the left is better than the right.
So it boils down to the question of what you care about when you code. And I'm going to repeat this message about three times during this talk and you will understand the importance of this question.
And I kid you not because I work as a consultant, right? And I go in a lot of companies and I have seen some people still advocate for single return in modern programming languages where you actually have garbage collection. So sometimes we just follow the pattern without
understanding the objective of the pattern itself. And that's really one thing that shows that the awareness of objective of the design patterns makes you more logical and thinking things very true.
And if you don't know the objective of the pattern, I don't say don't know, if you're not aware of that, then you become like, "Hey, I have been doing this for 20 years. This feels right to me and therefore everyone should do this." Which is I don't think it's a productive stance to learn programming at all.
So only after you decide what you care about, only after that, then you can be objective about which code or design pattern is actually better.
Example 2: React's useEffect API: Simplicity vs. Clarity19:05
Okay, the next one is a little bit relatable and heated, which is the React 𝚞𝚜𝚎𝙴𝚏𝚏𝚎𝚌𝚝 API.
I have been using React since many years ago when there were still class components. And I think if you are new to React, then you might see the hooks and 𝚞𝚜𝚎𝙴𝚏𝚏𝚎𝚌𝚝 as a de facto standard and natural way of doing React. But I would say it is not. Before that, we had things called class components and we turned it into hooks. And 𝚞𝚜𝚎𝙴𝚏𝚏𝚎𝚌𝚝 is one of very controversial hooks and until today, I think David has talked about this
in the past year or two years ago, I can't remember. But the point is until this day, 𝚞𝚜𝚎𝙴𝚏𝚏𝚎𝚌𝚝 is still very hard to use and very confusing to many programmers. And the data actually shows that as well. If you - I don't have the pure statistics to prove it,
but based on what I have seen and community sentiment, I think it's pretty clear that a significant
proportion of React developers, even the senior ones, still find 𝚞𝚜𝚎𝙴𝚏𝚏𝚎𝚌𝚝 very confusing.
Okay, so let's get back to when we still tried to introduce hooks and compare hooks, 𝚞𝚜𝚎𝙴𝚏𝚏𝚎𝚌𝚝 especially - not the hook or pattern, but 𝚞𝚜𝚎𝙴𝚏𝚏𝚎𝚌𝚝 and the lifecycle component, right? If I just put it side by side here, which one is
better? I think there's going to be a lot of opinions on which is better, right? But I think if once we put the objective into
evaluation, then I think it is going to be easier to understand.
And okay, so if the objective is to reduce the mental model required, one good thing about useEffect, which React team also advocate for this, to the point and I think that Dan or someone,
maybe people in the React core contributor wrote about why useEffect is awesome. Honestly, and in my personal opinion, to the point that sometimes I feel like they are gaslighting me to like useEffect, but I don't know.
But if you think about it, right, if the way that they advocate that hey, if you useEffect is just the way to think about useEffect is you try to synchronize external side effect into the component. You try to synchronize something from the external world into the component based on the dependency that you put in. So that and if you think of it that way, right, is one single mental model that can cover all of
the lifecycle hooks.
So if the objective is try to reduce the number of mental model that you need to know and cover everything, I think it's like seven lifecycle hooks, I can't remember. Then it's sure, on the left side is much better. It's just one single mental model. With a caveat, but honestly, there's a caveat that I don't know why, because when you try to say sync nothing from the outside world, then there's two way to do nothing, which is empty array, and it's mean that you sync one time. And there's another type of nothing which is undefined, which mean you sync everything. But I think that really lead to confusion because
there's two type of sync nothing. So you need to know this really secret of useEffect, and I think that create a lot of confusion. And if I get to do this, I might try to make it more explicit that there's two type of nothing, which is behave differently. But now they try to hey, there's two type of nothing that you need to know, empty array and nothing.
But anyway, if the objective is to reduce the number of mental model required, then sure, useEffect, you just need to remember one thing, apply to every lifecycle, nice.
But if the objective is to make API clear and easy to follow for public audience,
as again, I don't have the real statistic to prove that, but I think it's pretty clear that significant proportion of React dev still confusing about useEffect until this day. So I would say that it fail objective, this objective.
And when we have two people talk and when we have two sides, right, then one might say that hey, you remember just one thing, you can do everything, it's so simple. But then on the other side, we have but wait, I just want to load the data into component, and now I just want to do that. And now I need to learn that there's a synchronization mechanism,
and when you put this thing, then it do what I do instead of I writing componentDidMount. That's is so complex.
It's I think it can be asked on either side. It's simple in one objective, but it's complex in another objective, right?
So it gets back to: only after you decide what you care about,
then you can be objective about which code or system design is better.
Example 3: One-Way vs. Two-Way Data Binding25:41
And the next one is one and two-way bindings.
I think in JavaScript frontend frameworks, there are maybe two main ways to think about state. And one is more on the side of two-way binding where you have just variable. And when you change the variable directly, the reactivity just goes back. Like the example is a count. I think it comes from Svelte 4 because I just learned that Svelte 5 you need to put $state(…) in the morning, but anyway. And on the right side, there's an advocate for one-way binding where it advocates for "Hey, you should not change the state directly. You should do it via another function or event."
And it's one-way binding because you cannot change the state. It needs to go through the event, and if it flux then it dispatch and then get back, and then the data flow is one-way data flow. And this one you can change directly.
So on the right side, if your objective is to
try to see everything at once and try quick development,
then yeah, the right side here is much better. Because if you do it in the left pattern, then you just want to pass count by one when people click the button. And now you need to do it indirectly, need to define the new event call increase function, call increase count and go back. And now it's another layer of indirection. I want to read everything directly. I don't want to look into this unnecessary indirection.
So you can ask for that. And if your objective is to try to see everything at once, sure, the right is better. But if you want to make sure that you have meaningful description of why state changes, then the left side is much better because it tries to enforce you, "Hey, when you want to change the state, don't change it directly, create an event, name it properly, and then we can track all the state change based on those names." And that's the power of one-way binding which is good on one thing, good on that objective, but not good on another objective.
And maybe some of you might ask, "But hey, Chris, on the right side then you can actually wrap it in a function and you can achieve the one-way binding as well." And I say, "Yes, it's true, you can do that. But then that means that you prefer
having more options than less options, right?" And that's not the sentiment that everyone shares. And to be honest, there are languages such as Go or Python where they say, "Strip all the options, just do the same things, right?" So even though having more options might seem to be something objectively more valuable to you, but when you drill down to it, it might not be. And sometimes it's much better to don't have options. And I cannot ask whether it's better or worse. It's up to what is your—gets back to the same question again: what do you care about?
Yep.
The Importance of Understanding Design Pattern Objectives29:27
And I think one-way binding and two-way binding comes down to many of us working in form-based
application, right? Even our sponsors such as Agoda, Fastwork, right? Complicated app, but then it boils down to hotel booking, then you have a form, then you submit it, right? And when you have this kind of form, then you will ask, "Hey, I just have a form and I want to submit it, then why do I need to have all the event setName, setTitle, setOccupation to bind the data into the state to do some business logic inside for the state?" It's why can't I just bind it and that's more simple,
right? In this kind of context.
Back in the day, I used to work on a project management app where there's a task you create and there's a bunch of notification on the top.
And one thing that we want to do is when there's new urgent task, whether it's coming from other people or coming from ourselves, we should alert that, "Hey, new urgent task, check out." And if I only have the bunch of state, which is bunch of task inside my state, and I need to try to diff it to see whether there is new urgent task coming in every time change. Wow. Oh my god, that is so complex, right?
But why can't I simply have the event, maybe urgentTaskCreate event? But now I need to go look into the state change, diff it, and see that, "Hey, new things new urgent task coming. I need to put the notification." Now, in this context, seems like the complexity and simplicity just turns on the opposite side.
Because if you don't name properly when the task is
being tagged urgent, and then you don't have the event to track. And all you can do is try to diff the task themselves.
Right? And as we become more aware of the power of one-way
binding, right? This is because you can see, "Hey, this goes against the objective of one-way binding where you try to use just set only and you don't name the event of the state change properly." And, yeah. Then you can see that as you become aware of objective of each design pattern, then you can see what goes against it much better.
I think I can go on with so many examples as I said, I work with many programming languages and I can go on with many examples in software engineering history. There's so many examples of this.
Subjectivity Enhances Objectivity: The Key Takeaway32:48
But the takeaway that I want to say here today is not about everything being trade-off, which is true, but
that's not what I want to say today.
Know what you care about. You need to care about something subjectively in order to be objective.
And I think the biggest misconception in the engineering community is subjectivity actually enhances
the objectivity. And when I see people debate on what is the best practice, they try to remove their subjective preference or what they care about out of the equation. With the impression that it makes their argument much more objective and logical. I would say no. I would say the opposite. Awareness of what you care about actually enhances the objective quality and your objective logical evaluation of the system. 𝚞𝚜𝚎𝙴𝚏𝚏𝚎𝚌𝚝 can be good or bad API. It's based on what is your objective and audience,
right?
And once you know that, then that sentiment nowadays, why do we need more than simple HTML, CSS, JavaScript, right? And I think there's a lot of people on the internet saying that, "Hey, JavaScript programmers, you invent new frameworks every day just to keep your job."
And I say that kind is not productive to both them and
us. I think when you say something is worthless and unnecessarily complex, what you should start from is being aware of what you care about. Accept the subjectivity nature of it. Then after that, you can absorb different values, absorb something that you might not care about. And once you understand that, "Hey, I don't like this pattern because they care about something that I don't give a shit about."
Then you can learn the value of that pattern.
And this is how you grow to be more versatile engineer.
Awareness Precedes Choice: A Path to Better Engineering Practices35:46
And I want to end this talk from the quote in leadership and psychotherapy. And by the way, I am really into psychology and psychotherapy, which is another topic, not for today, but, yeah. The good quote here is that "Awareness precedes choice and choice precedes changes," which comes from Robin S. Sharma.
And I can say that as a consultant who needs to go and improve many engineering practices, when I'm aware of what I care about and I accept the nature of that, and I start to absorb what people in their organization care about, and I start to empathize with that, that's when I can really make change to their organization and the way they build software. I cannot make change if I don't accept what they care about. So, but it starts from being aware of what I care.
So, yes, thank you for today.
Okay. Thank you, P'Chris.