Lutamos com Msg muito grande em aplicativos Elm

De acordo com a Elm Architecture, toda a lógica do aplicativo está concentrada em um só lugar. Essa é uma abordagem bastante simples e conveniente, mas com o crescimento do aplicativo, é possível ver a função de update com 700 linhas, Msg com cem construtores e Model , que não cabe na tela.


Esse código é muito difícil de aprender e geralmente é mantido. Gostaria de demonstrar uma técnica muito simples que melhorará o nível de abstrações em sua aplicação.


Vejamos um exemplo simples.


Primeiro, crie um pequeno aplicativo com apenas um campo de texto. O código completo pode ser encontrado aqui .


 type alias Model = { name : String } view : Model -> Html Msg view model = div [] [ input [ placeholder "Name", value model.name, onInput ChangeName ] [] ] type Msg = ChangeName String update : Msg -> Model -> Model update msg model = case msg of ChangeName newName -> { model | name = newName } 

A aplicação está crescendo, adicionamos o sobrenome "sobre nós mesmos" e o botão "Salvar". Confirme aqui .


 type alias Model = { name : String , surname : String , bio : String } view : Model -> Html Msg view model = div [] [ input [ placeholder "Name", value model.name, onInput ChangeName ] [] , br [] [] , input [ placeholder "Surname", value model.surname, onInput ChangeSurname ] [] , br [] [] , textarea [ placeholder "Bio", onInput ChangeBio, value model.bio ] [] , br [] [] , button [ onClick Save ] [ text "Save" ] ] type Msg = ChangeName String | ChangeSurname String | ChangeBio String | Save update : Msg -> Model -> Model update msg model = case msg of ChangeName newName -> { model | name = newName } ChangeSurname newSurname -> { model | surname = newSurname } ChangeBio newBio -> { model | bio = newBio } Save -> ... 

Nada de notável, está tudo bem.


Mas a complexidade aumenta dramaticamente quando decidimos adicionar outro componente à nossa página que não tem nenhuma relação com o existente - o formulário para o cão. Confirmar


 type Msg = ChangeName String | ChangeSurname String | ChangeBio String | Save | ChangeDogName String | ChangeBreed String | ChangeDogBio String | SaveDog update : Msg -> Model -> Model update msg model = case msg of ChangeName newName -> { model | name = newName } ChangeSurname newSurname -> { model | surname = newSurname } ChangeBio newBio -> { model | bio = newBio } Save -> ... ChangeDogName newName -> { model | dogName = newName } ChangeBreed newBreed -> { model | breed = newBreed } ChangeDogBio newBio -> { model | dogBio = newBio } SaveDog -> ... 

Já nesta fase, você pode ver que Msg contém dois "grupos" de mensagens. Meu "talento programático" sugere que essas coisas precisam ser abstraídas. O que acontecerá quando mais 5 componentes aparecerem? E os subcomponentes? Será quase impossível navegar neste código.


Podemos introduzir essa camada adicional de abstração? Claro !


 type Msg = HoomanEvent HoomanMsg | DoggoEvent DoggoMsg type HoomanMsg = ChangeHoomanName String | ChangeHoomanSurname String | ChangeHoomanBio String | SaveHooman type DoggoMsg = ChangeDogName String | ChangeDogBreed String | ChangeDogBio String | SaveDog update : Msg -> Model -> Model update msg model = case msg of HoomanEvent hoomanMsg -> updateHooman hoomanMsg model DoggoEvent doggoMsg -> updateDoggo doggoMsg model updateHooman : HoomanMsg -> Model -> Model updateHooman msg model = case msg of ChangeHoomanName newName -> { model | name = newName } -- Code skipped -- updateDoggo : DoggoMsg -> Model -> Model -- Code skipped -- view : Model -> Html Msg view model = div [] [ h3 [] [ text "Hooman" ] , input [ placeholder "Name", value model.name, onInput (HoomanEvent << ChangeHoomanName) ] [] , -- Code skipped -- , button [ onClick (HoomanEvent SaveHooman) ] [ text "Save" ] , h3 [] [ text "Doggo" ] , input [ placeholder "Name", value model.dogName, onInput (DoggoEvent << ChangeDogName) ] [] , -- Code skipped -- ] 

Utilizando o sistema do tipo Elm, dividimos nossas mensagens em dois tipos: humano e canino. Agora, o limite para inserir esse código será muito mais fácil. Assim que algum desenvolvedor precisar alterar algo em um dos componentes, ele poderá determinar imediatamente pela estrutura de tipos de quais partes do código ele precisa. Precisa adicionar lógica à retenção de informações de cães? Veja as mensagens e inicie uma pesquisa nelas.


Imagine que seu código é uma grande referência. Como você pesquisará informações que lhe interessam? Por índice (Msg e Modelo). Será fácil para você navegar no índice sem dividir em seções e subseções? Dificilmente.


Conclusão


Essa é uma técnica extremamente simples que pode ser usada em qualquer lugar e é bastante fácil de incorporar no código existente. A refatoração de um aplicativo existente será totalmente indolor, graças à digitação estática e ao nosso compilador de olmo favorito.


Depois de passar apenas uma hora do seu tempo (passamos menos de 20 minutos em cada aplicativo em nosso projeto), você pode melhorar significativamente a legibilidade do seu código e definir o padrão de como escrevê-lo no futuro. Não é bom o código que é fácil de corrigir erros, mas aquele que proíbe erros e define um exemplo de como o código deve ser escrito.


Exatamente a mesma técnica pode ser aplicada ao Model , destacando as informações necessárias nos tipos. Por exemplo, em nosso exemplo, o modelo pode ser dividido em apenas dois tipos: Hooman e Doggo , reduzindo o número de campos no modelo para dois.


Deus salve o sistema do tipo Elm.


O repositório PS com código pode ser encontrado aqui, se você quiser ver as diferenças

Source: https://habr.com/ru/post/pt455553/


All Articles