Learning Design Patterns: A Summary

Learning Design Patterns: A Summary

What I learned from reading this awesome book and why you should read it too!

Featured on daily.dev

In programming, a "pattern" describes a general, reusable solution to a common occurring problem. As a software developer, it is important to understand when to apply these patterns; because using them arbitrarily can cause more harm than good to your software.

This weekend, I read a book called "Learning Patterns" by Lydia Hallie and Addy Osmani. It is a great book for any level of developer to learn about various design patterns, when to use it, and its pros and cons. It also includes web performance optimization techniques.

In this article, let me share a snippet of the goodness of this book, which would hopefully entice you to get a copy yourself.

The Patterns

Before reading the book, I recommend understanding a bit about React and how it works because the entire book uses examples with React code and focuses on React-specific patterns.

You can read my React Cheat Sheet for Beginners for a quick overview, or read the book's chapter covering the basics of React.

Now, let's look at some patterns!

1. Singleton

The Singleton is a single global instance that is accessible throughout the application. In React apps, this pattern makes it easy for managing states and accessing them globally.

However, Singletons are considered an anti-pattern in JavaScript and should be avoided. Because unlike Java, C++ or C#, we can directly create an object in JavaScript to implement a similar pattern without actually creating a Singleton class.

Some disadvantages of this pattern:

  • Having global variables can potentially cause overwrites and unexpected behavior
  • Difficult to test since we cannot create a new instance, we must test the value based on any previous tests' modification
  • In React apps, there are already state management libraries such as Redux, which makes the Singleton pattern quite redundant

2. Provider

The Provider pattern is commonly seen in React. Passing props from one component to another is just very tedious as the app gets more complex. This is known as prop drilling.

image.png

One example React has implemented to overcome this challenge is the React Context API. It allows data to be accessible from any component in the component tree.

For example, you may need to check whether a user is logged in throughout your app. So you need to wrap all your elements inside some kind of AuthProvider so that any components in this Provider can access its prop.

We first create a Context object like this:

export const AuthContext = React.createContext();

Then, we can have a Provider with a prop we want to be accessible everywhere in our app. Here we have a user state that the AuthProvider will provide to the rest of the components.

export const AuthProvider = ({ children }) => {
  const [user, setUser] = useState(null);

  useEffect(() => {
    app.auth().onAuthStateChanged(setUser);
  }, []);

  return (
    <AuthContext.Provider value={{ user }}>{children}</AuthContext.Provider>
  );

Now we just need to wrap it around all our elements.

function App() {
  return (
    <AuthProvider>
      <Router>
          <Nav />
          <Switch>
            <Route path="/signin" component={SignIn} />
          </Switch>
        </div>
      </Router>
    </AuthProvider>
  );
}

And now our app components can access user anywhere like this:

const { user } = useContext(AuthContext);

For more details on React Context API, feel free to read about useContext hook here or how to set up authentication in this article.

3. Hooks

Hooks in React has become one of the most powerful features to write cleaner and more efficient code. It is not exactly a design pattern, but ever since its release, it has replaced many traditional patterns. According to the official React website, Hooks achieves the following:

  • Allow you to reuse stateful logic without changing your component hierarchy
  • Let you split one component into smaller functions based on what pieces are related (such as setting up a subscription or fetching data)
  • Let you use more of React’s features without classes

Before Hooks, class components are the only way to handle state and lifecycle methods in React. As the app grew, it becomes increasingly complex to have to refactor functional to class components or have many duplicate lifecycle methods.

pic

To learn more about React Hooks at a deeper level, please check out my A Look at React Hooks series, where I cover 8 commonly used Hooks in detail.

4. Container

Our next pattern is the Container pattern. It is quite an overlooked pattern if you are not familiar with React. The purpose of implementing this pattern is to separate the app's view components (only UI) from the functional components that deals with application logic.

The 2 types of components are:

  1. Presentational component - simply about displaying data to user
  2. Container component - cares about what data is shown to user

image.png

For example, the logic for fetching data from an API will be in a Container component while the Presentational component will get the data to display it in a readable format.

This pattern is advantageous as it enforces the separation of concerns. It makes it easy for developers to test and to make changes to the view or the logic whenever needed.

5. Factory

As its name suggests, the factory pattern is about using factory functions to create objects over and over again, without the new keyword.

Take a look at the example below:

// Factory function
const createShape = ({numberOfSides, color}) =>({
   numberOfSides,
   color
})

// create objects from factory
const square = createShape({
   numberOfSides: 4,
   color: "red"
})

const hexagon = createShape({
   numberOfSides: 6,
   color: "yellow"
})

This pattern is useful for when you need to create complex, configurable objects that share some properties. The downside is that in JavaScript, it may be more memory efficient to create new instances rather than objects.

Conclusion

As a developer, studying some patterns can be beneficial to your problem-solving and software design principles because patterns are tried and tested solutions to common problems in software design.

Unfortunately, this is all I have for this article before it turns into an essay. This is just the tip of the iceberg in terms of what this book contains. I highly recommend reading it yourself to learn more patterns in detail.

Thanks for reading, hope this article has inspired you to read the book yourself. Feel free to go to patterns.dev to download the book for free. Do share with me which patterns do you encounter or use most in the comments below. Cheers!


Reference

  • Learning Patterns by Lydia Hallie and Addy Osmani

Did you find this article valuable?

Support Victoria Lo by becoming a sponsor. Any amount is appreciated!