Trying to understand Components (in general)

github logo ・1 min read

So, I'm still struggling to decide what makes a good component during the development of a web application. How do I know if my component is too big? or if it is too small? Does a component always have to be developed with reusability in mind?

It would be a great help if there is some good learning resource to teach patterns in Components to understand the DOs and DONTs when creating a new component.

twitter logo DISCUSS (4)
markdown guide
 

This is a great question and not one that many feel comfortable asking.

Just like any software architecture decision, there's almost never a right or wrong answer. It's a skill that you'll get better with over time. I think of it as intuition-based skill. Here are some of the lessons that I have learned that may help with learning.

Take a small amount of time (actual amount will depend on the size of the feature) and think about your architecture before you write any code.

  • Write a brief outline/mind map (it doesn't have to be super detailed), organizing your components and where the business logic will go within those components.
  • Breaking up the business & view logic will help you get a birds eye view of the feature rather than trying to keep it all in your head as you're implementing it.
  • Many engineers jump into coding to figure it out as they go. This step is a simple way to save yourself time by forcing yourself to outline the components before hand. You'll spot patterns and be able to see where you may be repeating logic.

Imagine what is likely/unlikely to change.

  • Let's say that you're about to implement a simple Button component. Imagine that you are yourself in 3 months (or 6 months or a year etc...) and for whatever reason, your requirements have completely changed. What is still going to be true regardless of those requirements and what would likely change? In the most simple case, you know a button is always going to have certain functionality that's inherent to buttons, but popular style trends change with the weather. What does this tell you about implementing the button?
    • It's easy to get carried away with this one. Don't over-optimize and try to think of every scenario. It's okay if you have to go back and change your code.
    • Don't invest extra time to make your component adapt to your predicted future requirements. This is important. This is the over-optimizing fallacy. The benefit of this step is that you should only spend the same amount of time/effort as you would if you were to naively implement the component.

Avoid Paralysis by Analysis.

  • I struggle with this one a lot. It's not important that your code is perfect from the start. Try time boxing your architecture decisions and if you're not confident by the end of the time box, then just go with it. You can always change code later.

Reflect on every decision post-implementation.

  • You'll realize that you made mistakes... don't get discouraged. That's how you learn this type of skill.
  • Sometimes your decision that ended up being a mistake was the right decision given what you knew at the time. Be honest with yourself. Reflect on whether you could have made the right decision given the information that you had at the time.

I highly recommend Clean Code by Bob C. Martin & Pragmatic Programmer by Andrew Hunt & David Thomas. Both are really great books on this topic.

I hope that this helps.

 

Thats some really good tips there, thanks for sharing.

 

(I'm an Angular dev that cares about code quality and will provide my opinion of what makes a good component, from a mix of a few articles and from some experience πŸ˜„)

TLDR: There is no such thing as a "good component" in general, its all based upon what your doing, but smaller is usually better.


I'd say there are 2 types of components:

  1. Smart/view/top-level components - These have the core business-logic, and potentially some state. They delegate what is happening on the page, and can be considered more like "views". Do not try to re-use this component, instead delegate its logic to other entities that can be re-used. (In Angular you'd use directives, pipes, and services to handle shared logic)

This component could get large, but you want to delegate to other entities as much as possible, leaving just "big picture" stuff to this component. These entities could be external functions/helper-classes or sub "smart" components.

You could create a smart component inside another smart component, but I'd only consider this for complex views with multiple parts that are separate. Generally you will run into issues communicating between smart components that are "siblings", and this is where state-management solutions like Redux/ngrx come in, or solutions like React Hooks. If you don't use these solutions, I'd be very careful creating multiple sibling components without a solid game-plan on how to communicate between them.

  1. Dumb/UI/presentational components - These are your bread and butter components. In a perfect world all your UI is handled by UI components with your smart components just passing data(this is my opinion πŸ˜‰). If the smart components handle big picture stuff, UI components should focus on the smaller things, like displaying data, inputting data, formatting data, etc. They shouldn't have state, and should have little to 0 logic. These should be made with the idea of re-usability so they shouldn't know where they are in the app. You could compare these to pure functions (in React, components could be created from pure functions πŸ˜‰)

The issues with these concepts is its hard to know which one to use most of the time, and handle all the edge cases. Its very easy to just make everything "smart", but then you end up having a hard time re-using anything.
You can't make all components dumb because you will eventually need some logic otherwise your app does nothing πŸ˜‰

The key is to focus components, of any complexity, on primarily displaying data and managing minimal state. These sort of approaches are founded in a lot of state-management solutions, which pull away responsibility from the components themselves. (here's the motivation behind Redux) You should always strive to make all components simpler regardless of framework, or if your are or aren't using a state-management system.

Finally I want to point out as an Angular dev I can say an Angular component can be backed up by services (common logic, message passing), injection-tokens (customization via DI), directives (template logic) and pipes (template logic), which remove a number of use-cases from component logic.

I have limited knowledge of React, but do know JSX is far more flexible, so the presentation of complex UI is easier in React than it is for Angular. (no idea where VueJS stands here haha)

Keep things simple, and move logic out of components when and where possible. Isolate state out of components and most problems and complexity should go away. :)


extra reading:

Primary sources (framework docs):
reactjs.org/docs/hooks-intro.html

reactjs.org/docs/components-and-pr...

angular.io/guide/component-interac...

Secondary sources (blogs):
blog.angular-university.io/angular...

itnext.io/react-component-class-vs...

 

I didn't expect to have such a complete answer

Your comment is pure gold

Classic DEV Post from Mar 5

3 Things You Can Do to Improve as a Developer

How do we identify and solve real problems?

matluz profile image

Creating your DEV account is like casting a vote for open source, inclusion in software, and creating your profile is great for your career.

Get started now ❀️