A complexidade dos sites modernos cresceu significativamente nos últimos anos. A crescente demanda por designs de alta qualidade e padrão da indústria intensifica ainda mais os desafios enfrentados pelos desenvolvedores de front-end. Hoje, até mesmo aplicativos de front-end precisam de algumas considerações arquitetônicas para simplificar o processo de desenvolvimento. Em meu , compartilhei minha experiência na implementação da abordagem de arquitetura limpa em aplicativos front-end enquanto trabalhava em meu . artigo anterior projeto paralelo Neste artigo, pretendo me aprofundar na abordagem do design atômico, com base em minhas experiências com o mesmo projeto. Discutirei suas vantagens e desvantagens e avaliarei sua utilidade em diferentes cenários. Antecedentes em sistemas de design Para começar, vamos explorar o conceito de um sistema de design. são coleções abrangentes de componentes, diretrizes e princípios reutilizáveis que capacitam as equipes a projetar e desenvolver interfaces de usuário consistentes em várias plataformas. Os sistemas de design Eles atuam como uma única fonte de verdade para designers e desenvolvedores, garantindo que os aspectos visuais e funcionais de um produto se alinhem e sigam a identidade da marca estabelecida. Se você estiver interessado em explorar exemplos de implementações de sistemas de design, considere examinar o seguinte: Sistema de design de carbono Sistema de design de ilhós Se você quiser mergulhar mais fundo no tópico de sistemas de design, recomendo verificar . Ele descreve este tópico em detalhes, detalhes que não são necessários para nós no escopo deste trabalho. este artigo Como o design atômico é derivado dos sistemas de design Com base nos sistemas de design, o design atômico é uma metodologia que agiliza a organização e a estruturação de componentes e diretrizes reutilizáveis. Concebido por é inspirado na química, pois desconstrói as interfaces do usuário em seus blocos de construção mais fundamentais e os remonta em estruturas mais intrincadas. Brad Frost, o Atomic Design Aqui está uma imagem que ilustra a analogia com a química: As reações químicas são representadas por equações químicas, que geralmente mostram como os elementos atômicos se combinam para formar moléculas. No exemplo acima, vemos como o hidrogênio e o oxigênio se combinam para formar moléculas de água. Em essência, o design atômico é uma evolução natural dos sistemas de design, fornecendo uma abordagem sistemática para a criação de componentes flexíveis e escaláveis. Ao aplicar os princípios do design atômico, as equipes podem gerenciar seus sistemas de design com mais eficiência, pois a natureza modular dessa metodologia facilita a manutenção, atualização e extensão dos componentes e padrões do sistema. Se você está preocupado que isso possa parecer complexo, não se preocupe. Nas próximas seções, demonstrarei como aplicar esses princípios usando um exemplo da vida real do aplicativo que desenvolvi, tornando-o fácil de entender e implementar em seus próprios projetos. Visão geral do design atômico O design atômico organiza os componentes em cinco níveis distintos, cada um baseado no anterior. Vamos explorar esses cinco níveis em detalhes: : os blocos de construção mais básicos de uma interface de usuário, os átomos representam elementos HTML individuais, como botões, campos de entrada e cabeçalhos. Eles são as menores unidades funcionais e não podem ser mais divididos. átomos : as moléculas são formadas pela combinação de dois ou mais átomos em um grupo funcional. Por exemplo, uma molécula de formulário de pesquisa pode consistir em um átomo de entrada de pesquisa, um átomo de botão e um átomo de rótulo. As moléculas representam componentes simples que podem ser reutilizados em um projeto. moléculas : os organismos são componentes mais complexos, criados pela combinação de múltiplas moléculas e/ou átomos. Eles representam seções distintas de uma interface de usuário, como cabeçalho, rodapé ou barra lateral. Os organismos ajudam a formar o layout geral e a estrutura de uma página. Organismos : os templates são essencialmente layouts de página construídos usando organismos, moléculas e átomos. Eles definem a estrutura e a disposição dos componentes em uma página sem especificar nenhum conteúdo real, servindo como modelo para vários cenários de conteúdo. templates : as páginas são as instâncias finais e totalmente realizadas de modelos, completas com conteúdo e dados reais. Eles representam o que os usuários verão e interagirão, mostrando como os componentes e o layout se adaptam a diferentes tipos de conteúdo e casos de uso. páginas O aplicativo NotionLingo: um estudo de caso A fim de desenvolver uma perspectiva bem informada sobre design atômico para desenvolvimento de front-end, embarquei em uma jornada para criar um aplicativo. Durante um período de seis meses, ganhei informações e experiências valiosas enquanto trabalhava neste projeto. Consequentemente, os exemplos fornecidos ao longo deste artigo são extraídos de minha experiência prática com o aplicativo. Para manter a transparência, todos os exemplos são derivados de código acessível publicamente. Você pode explorar o resultado final visitando o ou o próprio . repositório site Lembre-se de que usarei exemplos codificados em . Se você não estiver familiarizado com essa linguagem, não se preocupe - pretendo ilustrar os conceitos fundamentais do design atômico, em vez de focar nos detalhes essenciais do código. React átomos Para entender melhor os componentes do meu repositório, você pode encontrá-los no seguinte diretório: . Nesse local, criei um novo diretório chamado para manter a nomenclatura consistente com a metodologia de design atômico. Este novo diretório contém todas as pequenas partes necessárias para construir todo o processo de integração. /client/presentation atoms A lista completa de átomos é a seguinte: atoms ├── box ├── button ├── card ├── card-body ├── card-footer ├── container ├── divider ├── flex ├── form-control ├── form-error-message ├── form-helper-text ├── form-label ├── heading ├── icon ├── input ├── list ├── list-icon ├── list-item ├── spinner ├── tab ├── tab-list ├── tab-panel ├── tab-panels ├── tabs └── text Esses nomes de átomos podem ser familiares para você, pois são baseados no pacote . A maioria deles já contém o estilo de correspondência padrão para meu aplicativo, portanto, não há nada particularmente exclusivo para descrever neste nível. Com isso em mente, podemos prosseguir diretamente para discutir as . Chakra UI molecules moléculas Nesta fase, o processo de design atômico torna-se mais interessante e seu verdadeiro poder começa a se revelar. Embora definir seus átomos básicos possa ter sido uma tarefa demorada e monótona, construir novos componentes usando átomos se torna muito mais agradável. Para definir as moléculas, criei um diretório dentro do meu diretório . A lista completa de moléculas necessárias é a seguinte: molecules /client/presentation molecules ├── available-notion-database ├── full-screen-loader ├── input-control ├── onboarding-step-layout └── onboarding-tab-list De fato, com apenas cinco moléculas, temos componentes suficientes para atingir nosso objetivo. É importante observar que este também é um local ideal para incluir layouts compartilhados construídos sobre outros átomos. Por exemplo, o é utilizado para manter uma aparência consistente em todas as cinco etapas do processo de integração. onboarding-step-layout Os outros componentes são os seguintes: : Usado para exibir os detalhes do banco de dados do usuário buscado (os usuários podem ter vários bancos de dados, então ofereço a capacidade de escolher um na etapa 4). available-notion-database O componente aparece na interface do usuário assim: : Usado logo no início, quando estou buscando os detalhes do usuário para verificar se o usuário já definiu a integração do Notion ou não. O código para este componente se parece com isto: full-screen-loader import { FC } from 'react'; import { Flex, Spinner } from '@presentation/atoms'; import { FullScreenLoaderProps } from './full-screen-loader.types'; export const FullScreenLoader: FC<FullScreenLoaderProps> = ({ children, ...restProps }): JSX.Element => ( <Flex alignItems="center" bg="gray.50" height="full" justifyContent="center" left={0} position="fixed" top={0} width="full" zIndex="9999" {...restProps} > <Spinner /> {children} </Flex> ); Não há ciência de foguetes aqui. Esta é apenas uma combinação dos já definidos átomos e . flex spinner : Um wrapper para o átomo com , , e para mostrar se há alguma ação em segundo plano acontecendo. O componente aparece na interface do usuário assim: input-control input form-label form-control form-error-label spinner : Este é basicamente um componente de etapa, mas, no meu caso, estou usando as guias para navegação, então é daí que vem o nome. O componente aparece assim: onboarding-tab-list da IU do Chakra Agora que mais peças estão prontas, podemos definir blocos maiores em nosso quebra-cabeça de design. Organismos Esta seção é onde crio cada componente responsável por exibir cada etapa do processo de integração. Para esclarecer as coisas, mostrarei apenas a lista de organismos criados: organisms ├── onboarding-step-one ├── onboarding-step-two ├── onboarding-step-three ├── onboarding-step-four └── onboarding-step-five Acredito que os nomes são auto-explicativos e não deve haver mal-entendidos. Para ilustrar como montei tudo, vou apresentar o código de um passo como exemplo. Claro, se você quiser conferir mais, basta visitar . meu repositório export const OnboardingStepFour: FC<OnboardingStepFourProps> = ({ onBackButtonClick, onNextButtonClick, }): JSX.Element => { const { hasApiTokenData, isSetApiTokenLoading, setApiToken, setApiTokenError } = useSetApiToken(); const handleInputChange = debounce(async (event: ChangeEvent<HTMLInputElement>) => { const result = await setApiToken(event.target.value); if (result) { onNextButtonClick(); } }, 1000); return ( <OnboardingStepLayout subtitle="Paste your copied integration token below to validate your integration." title="Validate your integration" onBackButtonClick={onBackButtonClick} > <InputControl isRequired errorMessage={setApiTokenError || undefined} isDisabled={isSetApiTokenLoading || hasApiTokenData} isLoading={isSetApiTokenLoading} label="Integration token" name="integrationToken" placeholder="Your integration token" onChange={handleInputChange} /> </OnboardingStepLayout> ); }; Este código é totalmente responsável por exibir a etapa quatro do meu processo de integração. Acredito que a única preocupação que você possa ter é em fazer requisições em organismos. Isso é aceitável? Não existe uma resposta única para todos, e preciso responder a essas preocupações com "Depende". Depende da sua estrutura. Se incluir uma chamada de API em uma molécula ou organismo faz sentido no contexto de seu aplicativo e não complica excessivamente o componente, pode ser uma solução aceitável. Apenas tome cuidado para não permitir que os componentes da apresentação fiquem muito ligados à busca de dados ou à lógica de negócios, pois isso pode torná-los mais difíceis de manter e testar. No meu cenário, esse componente é usado em um local e outras soluções para realizar uma chamada de API nesse cenário são mais complexas e podem produzir muito mais código do que o necessário. Modelos Nesse estágio, o foco está na estrutura e no arranjo dos componentes, e não nos detalhes mais sutis da IU. Os modelos também ajudam a identificar onde o gerenciamento de estado deve residir, geralmente nos componentes da página que usam os modelos. No exemplo de código fornecido, temos um componente que serve como modelo: Onboarding import { FC } from 'react'; import { Flex, Heading, TabPanels, Tabs, Text } from '@presentation/atoms'; import { OnboardingTabList } from '@presentation/molecules'; import { OnboardingStepFive, OnboardingStepFour, OnboardingStepOne, OnboardingStepThree, OnboardingStepTwo, } from '@presentation/organisms'; import { OnboardingProps } from './onboarding.types'; export const Onboarding: FC<OnboardingProps> = ({ activeTabs, createNotionIntegrationTabRef, displayCreateNotionIntegrationTab, displaySelectNotionDatabaseTab, displayShareDatabaseIntegrationTab, displayValidateIntegrationTab, displayVerifyDatabaseTab, selectNotionDatabaseTabRef, shareDatabaseIntegrationTabRef, validateIntegrationTabRef, verifyDatabaseTabRef, }) => ( <Flex direction="column" overflowX="hidden" px={2} py={{ base: '20px', sm: '25px', md: '55px' }}> <Flex direction="column" textAlign="center"> <Heading color="gray.700" fontSize={{ base: 'xl', sm: '2xl', md: '3xl', lg: '4xl' }} fontWeight="bold" mb="8px" > Configure your Notion integration </Heading> <Text withBalancer color="gray.400" fontWeight="normal"> This information will let us know from which Notion database we should use to get your vocabulary. </Text> </Flex> <Tabs isLazy display="flex" flexDirection="column" mt={{ base: '10px', sm: '25px', md: '35px' }} variant="unstyled" > <OnboardingTabList activeTabs={activeTabs} createNotionIntegrationTabRef={createNotionIntegrationTabRef} selectNotionDatabaseTabRef={selectNotionDatabaseTabRef} shareDatabaseIntegrationTabRef={shareDatabaseIntegrationTabRef} validateIntegrationTabRef={validateIntegrationTabRef} verifyDatabaseTabRef={verifyDatabaseTabRef} /> <TabPanels maxW={{ md: '90%', lg: '100%' }} mt={{ base: '10px', md: '24px' }} mx="auto"> <OnboardingStepOne onNextButtonClick={displayCreateNotionIntegrationTab} /> <OnboardingStepTwo onBackButtonClick={displayVerifyDatabaseTab} onNextButtonClick={displayShareDatabaseIntegrationTab} /> <OnboardingStepThree onBackButtonClick={displayCreateNotionIntegrationTab} onNextButtonClick={displayValidateIntegrationTab} /> {activeTabs.validateIntegration ? ( <OnboardingStepFour onBackButtonClick={displayShareDatabaseIntegrationTab} onNextButtonClick={displaySelectNotionDatabaseTab} /> ) : null} {activeTabs.selectNotionDatabase ? ( <OnboardingStepFive onBackButtonClick={displayVerifyDatabaseTab} /> ) : null} </TabPanels> </Tabs> </Flex> ); Esse componente reúne átomos, moléculas e organismos para criar o layout do processo de integração. Observe que o gerenciamento de estado e a lógica de navegação de guias foram separados desse componente. As funções necessárias de estado e retorno de chamada agora são recebidas como props, permitindo que um componente de "página" de nível superior manipule o estado e o gerenciamento de dados. Onboarding Essa separação de preocupações mantém o modelo focado no layout e na estrutura, ao mesmo tempo em que garante que o gerenciamento de estado seja tratado no nível apropriado. No final, gostaria de apresentar o passo 4 como resultado final: Páginas No contexto de nossa discussão anterior, o componente "page" usa o modelo e lida com o gerenciamento de estado para o processo de integração. Embora o código desse componente de página específico não seja fornecido aqui, você pode encontrá-lo em meu repositório. Conforme mencionado, não há nada de extraordinário no código do componente da página; ele se concentra principalmente em gerenciar o estado e transmiti-lo ao modelo . Onboarding Onboarding Se dermos uma olhada em como o design atômico se parece na prática. Vamos mergulhar nos prós e contras dessa abordagem. Não há rosa sem espinhos Embora o design atômico ofereça inúmeros benefícios óbvios, como modularidade, reutilização e manutenção, ele também apresenta algumas desvantagens que valem a pena considerar no início: : o design atômico requer uma estrutura e organização bem planejadas, que podem ser demoradas e difíceis de configurar inicialmente. Ele também pode apresentar complexidade adicional à sua base de código, especialmente para projetos menores, nos quais essa abordagem granular pode ser desnecessária. configuração inicial e complexidade : para desenvolvedores novos no design atômico, a metodologia pode ter uma curva de aprendizado acentuada. Requer uma compreensão sólida dos diferentes níveis e como eles se encaixam, o que pode ser esmagador para iniciantes. curva de aprendizado : a implementação do design atômico pode envolver a criação de um grande número de componentes pequenos e especializados. Isso pode levar ao aumento da sobrecarga no gerenciamento e manutenção desses componentes, principalmente quando um componente é usado apenas em um contexto específico. sobrecarga : com o foco na criação de componentes reutilizáveis e modulares, há um risco potencial de excesso de engenharia, onde os desenvolvedores podem gastar muito tempo refinando componentes individuais em vez de se concentrar no aplicativo mais amplo. risco de excesso de engenharia : o sucesso do design atômico depende de comunicação e colaboração claras entre designers, desenvolvedores e outras partes interessadas. Deixar de estabelecer uma linguagem ou entendimento comum da metodologia pode levar a confusão e inconsistências na implementação. comunicação e colaboração No entanto, essa abordagem tem seus próprios pontos fortes já mencionados. Vamos falar sobre eles com mais detalhes: : ao decompor o design nos elementos mais fundamentais, a construção da complexidade dos componentes tornou-se uma tarefa mais gerenciável. Embora criar átomos apresentasse alguns desafios, criar qualquer componente baseado nesses átomos era extremamente agradável. escalabilidade : a capacidade de reutilizar átomos, moléculas e organismos reduz significativamente o tempo gasto na concepção e desenvolvimento de novos recursos. Uma vez estabelecidos os componentes básicos, criar novas interfaces pode ser tão simples quanto combinar elementos existentes. eficiência : vem diretamente do ponto anterior. Como os mesmos átomos, moléculas e organismos são usados em vários modelos e páginas, a interface do usuário permanece uniforme, proporcionando uma experiência perfeita para os usuários. consistência : o design atômico suporta inerentemente a documentação. A estrutura baseada em átomos pode servir como um guia visual claro de como os componentes devem ser construídos e usados. Isso pode ser especialmente útil para integrar novos membros da equipe. documentação : um dos maiores pontos fortes do design atômico é como ele contribui para a sustentabilidade de um sistema de design. Ao quebrar tudo em suas partes atômicas, quaisquer alterações ou atualizações podem ser feitas no nível atômico e então propagadas pelo sistema. Por exemplo, se você decidir mudar a cor de um botão, você só precisa fazer essa mudança uma vez no nível do átomo, e isso será refletido em todas as moléculas, organismos e modelos onde esse botão é usado. Isso simplifica muito o processo de atualização e manutenção do sistema de design ao longo do tempo. sustentabilidade Conclusão Em conclusão, embora o design atômico possa parecer uma faca de dois gumes - um pouco assustador em termos de configuração inicial e curva de aprendizado - seus benefícios potenciais valem a luta inicial. E lembre-se, mesmo as espadas mais formidáveis são inofensivas nas mãos de um cavaleiro habilidoso!