Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Vue.js 3 Design Patterns and Best Practices

You're reading from   Vue.js 3 Design Patterns and Best Practices Develop scalable and robust applications with Vite, Pinia, and Vue Router

Arrow left icon
Product type Paperback
Published in May 2023
Publisher Packt
ISBN-13 9781803238074
Length 296 pages
Edition 1st Edition
Languages
Tools
Arrow right icon
Author (1):
Arrow left icon
Pablo David Garaguso Pablo David Garaguso
Author Profile Icon Pablo David Garaguso
Pablo David Garaguso
Arrow right icon
View More author details
Toc

Table of Contents (16) Chapters Close

Preface 1. Chapter 1: The Vue 3 Framework 2. Chapter 2: Software Design Principles and Patterns FREE CHAPTER 3. Chapter 3: Setting Up a Working Project 4. Chapter 4: User Interface Composition with Components 5. Chapter 5: Single-Page Applications 6. Chapter 6: Progressive Web Applications 7. Chapter 7: Data Flow Management 8. Chapter 8: Multithreading with Web Workers 9. Chapter 9: Testing and Source Control 10. Chapter 10: Deploying Your Application 11. Chapter 11: Bonus Chapter - UX Patterns 12. Final words 13. Index 14. Other Books You May Enjoy Appendix: Migrating from Vue 2

A non-exclusive list of design principles

Design principles vary somewhat depending on the context, domain, and even the team one may be part of at the time. The principles included in this chapter are, therefore, non-exclusive.

Separation of concerns

This is perhaps the most important principle in software engineering. Separation of concerns implies that a system must be divided into subsystems of elements grouped by their function or service (the concern). For example, we can consider the human body as a system composed of many subsystems (respiratory, circulatory, digestive, etc.). These, in turn, are integrated by different organs, which are made of tissues, and so forth, down to the smallest cell. Following the same idea in software, an application can be divided into elements grouped by concerns, from the large architecture all the way down to the last function. Without this breakdown of complexity into manageable parts, creating a functional system would be much harder, if not impossible.

In general, the application of this principle starts with the big picture of what the system should be, looks into what it should do to accomplish that, and then breaks it down into manageable working parts.

As an example, here is a crude graphical representation of separation of concerns for a web application. Each box in this diagram identifies a different concern that, in turn, can be detailed into smaller functional parts. Even better, you can see how this principle allows you to identify the integrating parts of a system.

Figure 2.1 – A simple architectural view of a web application showing separation of concerns

Figure 2.1 – A simple architectural view of a web application showing separation of concerns

If we were to drill down into any of these small boxes within their respective domains, we could still find more concerns to subdivide until we reach an indivisible atomic element (a component or function, for example). This principle has much to do with and benefits from other principles, such as abstraction and single responsibility. We will review them further down the line in this same chapter.

Composition over inheritance

The principle of composition over inheritance comes directly from Object-Oriented Programming (OOP). It states that an object should attempt to use other objects’ functionality when needed, by referencing or instantiating them instead of creating a large and complex inheritance family tree of classes to add such functionality. Now, JavaScript is fundamentally a functional language, even though it supports multiple paradigms, including features from OOP, so this principle applies as well. There is one note of warning for those migrating from OOP into JavaScript, and that is to avoid the temptation to treat JavaScript as a pure OOP language. Doing so could create unnecessary complexity instead of benefiting from the virtues of the language.

In Vue 3, there is no extension or inheritance of components. When we need shared or inherited functionality, we have a nice toolset of options to replace the inheritance paradigm. We will see later how we can comply with this principle by using composable components in Chapter 4, User Interface Composition with Components.

Single responsibility principle

This principle can be found in OOP as well as in functional programming. Simply put, it states that a class, method, function, or component should deal with only one responsibility or functionality. If you have worked in other disciplines and languages, this comes naturally. Multipurpose functions are hard to maintain and tend to grow out of control, especially in a language such as JavaScript, which is loosely typed and highly dynamic. The same concept also applies directly to Vue 3 components. Each component should deal with one specific operation and avoid attempting to do too much by itself. In practice, when a component grows beyond a certain scope, it is best to split it into multiple components or extract the behavior into external modules. There are cases when you may end up with a many-thousand-lines-long component, but in my experience, this is rarely necessary and can and should be avoided. A warning, though, is that too much specificity could also lead to unnecessary complexity.

As an example, let’s imagine a sign-in screen that also displays a sign-up option. This approach is common on many sites today. You could include all the functionalities inside just one component, but that would break this principle. A better alternative would be to split the components into at least three components for this task:

  • A parent component that handles the UI logic. This component decides when to show/hide the sign-in and sign-up components.
  • A child component that handles the sign-in function.
  • A child component that handles the sign-up function.

Here is a graphical representation of this configuration:

Figure 2.2 – The composition of a sign-in/up interface using multiple components

Figure 2.2 – The composition of a sign-in/up interface using multiple components

I think that you can quickly grasp the benefits of this principle. It makes the code easy to manage, maintain, and adapt since web applications have the tendency to mutate and evolve very, very quickly.

Best practice tip

Give components a single responsibility and functionality. Avoid mammoth monolithic components as much as possible.

Encapsulation

Encapsulation is the notion that you should wrap data and methods to act as a single unit while exposing a well-defined application programming interface (API). Often, this is done in the form of classes, modules, or libraries. JavaScript is not an exception, and it is highly recommended to follow this principle. In Vue 3, this concept applies to not only components but also CSS styles and HTML. The introduction of single-file components is a clear example of how the framework promotes this principle in action and how important it is for today’s development. With only a few edge-case situations, we should consider the (UI) components as black boxes that receive incoming parameters and provide outgoing data. Other components should not be aware of their inner workings, only the API. As we build example applications throughout this book, you will see this principle in action.

KIC – keep it clean

This principle refers mainly to the way you write code. I should emphasize here that KIC applies directly to two categories that strongly affect web and Vue 3 applications:

  • How you format your code
  • How you tidy up events and variables

The first item includes the use of code conventions, comments, and indentation to the organization of the code and logical grouping of functions. For example, if you have methods that deal with create, read, update, and delete (CRUD) operations, it would be best to place them near each other in the code, rather than spread around the source file. Many integrated development environments (IDEs) contain features to collapse or expand the inner code of functions. This helps to quickly review and locate sections in the code with similar logic.

The second part of this principle has to do with memory and reference handling. JavaScript has a very good garbage collector, the function of which is to discard unused data to reclaim memory. However, there are occasions when the algorithm is prevented from freeing up resources because a reference is still pending. If you have worked with other languages, such as C/C++, this issue may sound familiar as you need to manually reserve and release memory when not in use. In JavaScript, if you register a function to listen to an event, it is best to manually deregister it at the appropriate life cycle event of your component when no longer needed. This will prevent memory leaks and waste of memory and also prevent some security risks (which are out of the scope of this book).

We will review the component’s life cycle in Chapter 4, User Interface Composition with Components, but for now, take the following example as a good application of this principle and keep it as best practice. In this example, we will create a composable component to detect when the window size changes, so in the script setup section we will find something like this:

  1. Registers a function on the window object’s resize event during the mounting state.
  2. Deregisters the event before the component is unmounted.

Here is the code fragment:

<script setup>
   import {onMounted, onBeforeUnmount} from "vue"
   onMounted(()=>{
       window.addEventListener("resize", myFunction)
   })
   onBeforeUnmount(()=>{
       window.removeEventListener("resize", myFunction)
   })
   function myFunction(){
       // Do something with the event here
   }
</script>

The onMounted and onBeforeUnmount functions are part of the Vue 3 framework and are triggered by the appropriate component life cycle event. Here, we attach our function to the resize event when the component is mounted to the Document Object Model (DOM), and we release it just before it is removed. The important concept to remember is to clean up after yourself and keep it clean.

DRY – don’t repeat yourself

This principle is quite famous, almost to the point of turning into a cliché. Sadly, it is easily forgotten. It is credited to Andrew Hunt and David Thomas, who used it in the book The Pragmatic Programmer. It is mostly thought of as don’t write the same thing twice and is not far off, but it goes beyond that. It encompasses the notion of avoiding redundancy in the process as well as in the logic of the application. The core idea is that each process that executes business logic should exist in only one place in your entire application.

For example, most web applications have some asynchronous connection with a server through the use of an API. There may also be multiple elements in the application that will use or need to use this remote computer/server communication. If you were going to code the entire code/logic to communicate with the server in each component, we would end up with not only duplication of code but also application logic. Maintaining such a system would open up the door to an amazing number of negative side effects and security concerns, poor user experience, and much more. According to this principle, a better approach is to abstract all communication code related to the server API into a single module, or class. In practice, in JavaScript this can even be delegated to a web worker in a separate thread. We will explore this implementation later in Chapter 8, Multithreading with Web Workers.

As a rule of thumb, if you see yourself writing kind-of-the-same-code” in different components or classes, it is a clear opportunity to abstract the functionality into its own module or component.

KISS – keep it simple and short

This principle is not exclusive to the software design realm. It was coined by the US Navy back in the ’60s (according to Wikipedia, https://en.wikipedia.org/wiki/KISS_principle). The idea is pure common sense: it is better to build simple, small functional parts that work together than attempt to create a big and complex program in one go. Also, algorithms should be implemented in the most simple and efficient way. In web development, this principle is essential. Modern web applications are composed of hundreds of working parts spread over multiple computers, servers, and environments. The more complex a system or code implementation is, the harder it is also to maintain and adapt.

There is a warning, though. Keeping things simple does not mean over-simplification or unnecessary segregation. Too many small parts can introduce unnecessary complexity in the system. Applying the KISS principle means staying in that sweet middle point where things are manageable and easy to understand.

Code for the next

This principle is the idea that you should make your code readable and easy to understand for someone else besides you. Naming conventions, logic flow, and inter-line comments are all part of this. Not only for the case when you may need to delegate your code to another but also when you come back in a year or two to the same code. The last thing you want to do is to waste time thinking about what the past inexperienced you did with that clever line of spaghetti code Smart developers code as if they were going to teach somebody else, simply and elegantly. Especially if you are using or contributing to open-source code, this principle is vital for group collaboration. In this case, it is worth mentioning the Boy Scout Principle, which is similar but applies in groups. It states that when you find a hard-to-read or “spaghetti” code, you refactor it to make it clean.

Best practice tip

Keep your code clean with on-source comments and documentation explaining your logic, as if teaching somebody else. More often than not, you will be teaching yourself.

Design principles apply to many different scenarios, some beyond the practice of software development. It is important to consider them until they become second nature. In general, the application of these and other principles, together with the application of design patterns, make an important mark on your professional development.

You have been reading a chapter from
Vue.js 3 Design Patterns and Best Practices
Published in: May 2023
Publisher: Packt
ISBN-13: 9781803238074
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime
Banner background image