Some things that are worth adding: - loading and error states. What do you do while results are loading? What do you show when there is an error? - how to match results from server with what user has already typed. This is an actual problem when your data request takes second and more. User can continue typing, and even with debounce you send a new http request before getting the response from previous one. To solve use AbortController to cancel previous requests or maybe just have something in the response to indicate what query was used so you can match it with current state of query.
This is essentially the "Race condition" problem. Its a common problem whenever you fire multiple network requests but only one response needs to gets rendered
Today I was asked this question on a FAANG onsite for a fullstack job. You're channel literally is the only source of reliable frontend design content that I found on the internet. Thank you!
Hey! Thanks for such useful content! Talking about the plan I think it makes sense to move some points: 1. Requirements - Core functionality (features without which the project won't take off) - Additional functionality (for v2) - Accessibility can be included either in the Core section or in Additional one. 2.Architecture, Components Responsibilities - High-level mock up: draw basic UI, name components and its elements - Data Entities "Worry about the data structures first, and your code will naturally be cleaner." L. Torvalds - Dependency graph 3. API (Properties) 4. Store 5. Optimisations - it is the last one because at this point we have the whole picture and we know tight places. - Additional Configuration (like cache size, min query, etc.), because now we know optimisations, its trade-offs and we can provide tools to control these trade-offs.
Hi, thank you for your comment. I think there is no silver bullet plan. You can adopt my plan to your needs. Your plan is a good one, just remember that you have about 30-35 minutes for your design 😊
Hi, Anup. Thanks a lot for your support. I'm going to continue to work on the videos in May because currently I'm relocating to a new country and I'm a bit busy with that stuff. I have a big plan for the content, which I've already prepared, so stay tuned :)
This was super useful and well structured, thanks! One area that you didn’t mention was testing, which strikes me as something worth at least mentioning when designing a consumable component.
Good point, you're right. Depending on the situation, you should mention that. But in the real interview, you are usually asked to focus on one or two areas.
Привет, спасибо за крутой урок!) Возник вопрос, пользовались ли вы заготовленными заранее схемами, когда проходили интервью в компании? Или это запрещено во время интервью?
I'm not clear why you store the resultMap in the widget. If you search 'Jack' you store the result in the resultMap, but after 2 seconds , the results in the backend changes, but you type 'Jack' again, the widget will use the result from the resultMap cache. Even though you use a cacheTime in the widget, but how do you know within the cacheTime, the backend data whether update for the same query key ?
Hi, Hu. Thank you for your question. The answer is - it depends where you want to use the widget and what are the requirements. 1. If the data tend to change pretty fast, then you configure your widget to have a lower cache lifetime. 2. If it's pretty stable and doesn't change often, then you are free to increase a cache lifetime Because the widget component is usually generic stuff, the implementation shouldn't depend on the backend. The key to flexibility here is configuration. Change your config accordingly to the server API. If you want to know somehow, that the data is changed on the backend and your system really need this, then you could possibly configure a server-side event for that, which you can react on your front-end to clean the cache, but this will lead to the increased complexity of architecture. There are trade-offs everywhere :)
How to maintain both sync and async. In async, outer component have to pass the updated data. But in case of sync or internal search, our component has to filter the search result from the initial data. In react terms, we have to maintain state form sync case and rely on props for async case. Do we have to write two versions of the widget? Not sure how to handle this through code. Can anyone help? same goes with poll widget too.
You could have this widget handle async as well - just give it a prop like dataSource and that dataSource must implement how to access the results (either from a static store, or through async querying)
The widget component will always render results from props. We can add another props called customOnChangeHandler() which the parent component will pass. This function can trigger an API call to fetch the new results. The widget component will call this function inside it's onChange method.
They're not being stored in the store. They're being stored in the component's internal state. After a query is done and result selected, the results are wiped from the component state.
Hi Aya. DOM write is a costly operation, so instead of creating new element and inserting it in DOM Tree, we update internal DOM structure, this could also be called "soft-write", we replace only content of html element, this is pretty cheap. BTW all frameworks, like React, Angular and etc do it for you. In this design, we use only standard DOM API, that's why we have to take care of that. I hope it explains the idea
Thanks for this very good content! I just think that the Property design is a little not standard... I woulg rather write it like HTTP requests: GET: /restEntity/{:param}?{:query}&{:order} returns: [{ id: int, name: str, description: str, page: int}, {...}] etc... the Issue with the Props { getData(): string... seems to me not so clear...
This would be pretty unclear in the context of a frontend systems design. The video's use of TypeScript to describe data is more aligned with frontend and remains agnostic and high level.
I think it is a bad idea to keep resultsMap inside the component state. Too much logic for UI component. The way I handle this is to wrap my onQuery in a closure function. Cache is private map to the onQuery function. The widget's source of truth is just onQuery function. The caching logic is abstracted away from the component.
@@hkjpotato I think it's the number of string that needs to be typed before applying the filter. I think it's unnecessary if you already have debounce. It needs to be optional.
Your General Requirements are actually Functional Requirements, and your Functional Requirements are actually Non-Functional Requirements.
Some things that are worth adding:
- loading and error states. What do you do while results are loading? What do you show when there is an error?
- how to match results from server with what user has already typed. This is an actual problem when your data request takes second and more. User can continue typing, and even with debounce you send a new http request before getting the response from previous one. To solve use AbortController to cancel previous requests or maybe just have something in the response to indicate what query was used so you can match it with current state of query.
Thanks for a great comment. You can definitely also talk about during the interview
This is essentially the "Race condition" problem. Its a common problem whenever you fire multiple network requests but only one response needs to gets rendered
To handle the race conditions, we can attached timestamps to each request & show the result of the latest request only.
Today I was asked this question on a FAANG onsite for a fullstack job. You're channel literally is the only source of reliable frontend design content that I found on the internet. Thank you!
Hey! Thanks for such useful content!
Talking about the plan I think it makes sense to move some points:
1. Requirements
- Core functionality (features without which the project won't take off)
- Additional functionality (for v2)
- Accessibility can be included either in the Core section or in Additional one.
2.Architecture, Components Responsibilities
- High-level mock up: draw basic UI, name components and its elements
- Data Entities "Worry about the data structures first, and your code will naturally be cleaner." L. Torvalds
- Dependency graph
3. API (Properties)
4. Store
5. Optimisations - it is the last one because at this point we have the whole picture and we know tight places.
- Additional Configuration (like cache size, min query, etc.), because now we know optimisations, its trade-offs and we can provide tools to control these trade-offs.
Hi, thank you for your comment. I think there is no silver bullet plan. You can adopt my plan to your needs. Your plan is a good one, just remember that you have about 30-35 minutes for your design 😊
@@FrontEndEngineer agree. Anyway your plan is very solid one.
Even though your interview season is over. I think PPL will still appreciate you continuing this series
Hi, Anup. Thanks a lot for your support. I'm going to continue to work on the videos in May because currently I'm relocating to a new country and I'm a bit busy with that stuff.
I have a big plan for the content, which I've already prepared, so stay tuned :)
@@FrontEndEngineer happy to hear this.
most underrated channel on youtube
This was super useful and well structured, thanks! One area that you didn’t mention was testing, which strikes me as something worth at least mentioning when designing a consumable component.
Good point, you're right. Depending on the situation, you should mention that. But in the real interview, you are usually asked to focus on one or two areas.
another amazing video, thanks man!
Performance:
1. use semantic elements
2. minimum html depth
3. No layout thrashing
Thank you for this!
Does it make sense to add a “Tech choices” section to the overall explanation? It could come right after requirements and scoping part.
Thank u for the detailed video.. It was really helpful.
what's this chart tool?
Привет, спасибо за крутой урок!)
Возник вопрос, пользовались ли вы заготовленными заранее схемами, когда проходили интервью в компании? Или это запрещено во время интервью?
Лучше не стоит, это сразу говорит о том, что ты знаешь вопрос
I'm not clear why you store the resultMap in the widget. If you search 'Jack' you store the result in the resultMap, but after 2 seconds , the results in the backend changes, but you type 'Jack' again, the widget will use the result from the resultMap cache. Even though you use a cacheTime in the widget, but how do you know within the cacheTime, the backend data whether update for the same query key ?
Hi, Hu. Thank you for your question.
The answer is - it depends where you want to use the widget and what are the requirements.
1. If the data tend to change pretty fast, then you configure your widget to have a lower cache lifetime.
2. If it's pretty stable and doesn't change often, then you are free to increase a cache lifetime
Because the widget component is usually generic stuff, the implementation shouldn't depend on the backend. The key to flexibility here is configuration. Change your config accordingly to the server API. If you want to know somehow, that the data is changed on the backend and your system really need this, then you could possibly configure a server-side event for that, which you can react on your front-end to clean the cache, but this will lead to the increased complexity of architecture. There are trade-offs everywhere :)
How to maintain both sync and async. In async, outer component have to pass the updated data. But in case of sync or internal search, our component has to filter the search result from the initial data. In react terms, we have to maintain state form sync case and rely on props for async case.
Do we have to write two versions of the widget?
Not sure how to handle this through code. Can anyone help?
same goes with poll widget too.
You could have this widget handle async as well - just give it a prop like dataSource and that dataSource must implement how to access the results (either from a static store, or through async querying)
The widget component will always render results from props. We can add another props called customOnChangeHandler() which the parent component will pass. This function can trigger an API call to fetch the new results. The widget component will call this function inside it's onChange method.
The API results could be cached by the browser itself. Why do we need to store them in the store ?
They're not being stored in the store. They're being stored in the component's internal state. After a query is done and result selected, the results are wiped from the component state.
First thank u ..I could not understand updateItem what is it? How can we benefit from it !!
Hi Aya. DOM write is a costly operation, so instead of creating new element and inserting it in DOM Tree, we update internal DOM structure, this could also be called "soft-write", we replace only content of html element, this is pretty cheap. BTW all frameworks, like React, Angular and etc do it for you. In this design, we use only standard DOM API, that's why we have to take care of that. I hope it explains the idea
Thanks for this very good content!
I just think that the Property design is a little not standard...
I woulg rather write it like HTTP requests:
GET: /restEntity/{:param}?{:query}&{:order}
returns: [{ id: int, name: str, description: str, page: int}, {...}]
etc...
the Issue with the Props {
getData(): string...
seems to me not so clear...
This would be pretty unclear in the context of a frontend systems design. The video's use of TypeScript to describe data is more aligned with frontend and remains agnostic and high level.
Since this is a component he is defining the props or parameter definition that will be sent to the component.
Can you provide the schema of the design?
sorry, schemas were lost during google drive migration :(
I think it is a bad idea to keep resultsMap inside the component state. Too much logic for UI component. The way I handle this is to wrap my onQuery in a closure function. Cache is private map to the onQuery function. The widget's source of truth is just onQuery function. The caching logic is abstracted away from the component.
useful point:minquery
ok skeleton placeholder (all related to state), I still dont know what minQuery is here
minQuery is the "size" of string when search start..what a name
@@hkjpotato I think it's the number of string that needs to be typed before applying the filter. I think it's unnecessary if you already have debounce. It needs to be optional.