После многих лет, десятилетий, многих приложений, многих программ, многих экранов я наконец осознал простую и убедительную истину: представления — это просто функции.
Мои первые программы на BASIC
Когда я был еще ребенком, я создал свои первые представления, просто распечатав:
10 PRINT "Good morning Dave"
После печати пришел ввод. Ввод — это операция по изменению состояния программы:
10 PRINT "Hi" 20 INPUT "What is your name? ", N$ 30 PRINT "Good morning"; N$ 40 GOTO 20
Всегда было одно и то же: распечатать представление, запросить новую информацию и снова распечатать результат. Бесконечный цикл.
SUB MainMenu() DO CALL PrintMainMenu INPUT “What option you choose? “, Option% CALL ExecuteMainOption(Option%) LOOP UNTIL Option% = 0 END SUB
Это было легко и быстро. Когда я начал моделировать графический интерфейс пользователя с окнами, я всегда делал одно и то же: очищал вторичный буфер, печатал все экраны снизу вверх, копировал буфер на экран, а затем вводил снова, ожидая изменения.
Вход в объектно-ориентированный мир
Возможно, я мог бы обвинить в этом Java, но это не так. Первым языком программирования, который я использовал, был C++, за которым последовал VisualBasic (точнее, 2.0).
Объектно-ориентированное программирование было самой крутой вещью. Я помню переход от простых процедурных приложений к объектно-ориентированным. Объекты модели, которые заботятся о себе сами. Я помню, как написал один небольшой трассировщик лучей на C++, великолепно. Механизм рендеринга, который принимал в качестве входных данных абстрактные объекты, заставлял их пересекаться с лучами и генерировал впечатляющие изображения. Использование объектно-ориентированного программирования в моделях было замечательным.
Проблемы появились, когда я начал писать интерфейсы в объектно-ориентированном программировании.
Представление было сложнее, чем просто печатать, это было создание сложного дерева объектов, конфигураций и корректная синхронизация их всех с состоянием. Однако посмотрите на это, интерфейсы были великолепны, со сложным поведением, и почему бы и нет, я был поражен этими блестящими кнопками.
В те дни я не понимал, что произошло. Сначала я подумал, что не понял MVC. Позже я подумал, что мне нужна лучшая методология. Я чувствовал, что что-то не так, но не знал, что. Я начал искать удобный способ кодирования. Я перепробовал много узоров. Почему-то все решения всегда казались чем-то вроде специальных решений.
Дублированные состояния, корень всех зол
Нормализованные состояния, производные состояния, вычисленные состояния, единый источник правды и многое другое. Существует обширный список концепций, объясняющих, почему у вас не должно быть дублированного состояния. Если вы дублируете состояние, вы начинаете работать в высоконадежных решениях, чтобы избежать повреждения данных.
Основной принцип объектно-ориентированного программирования заключается в том, что каждый объект сохраняет свое собственное состояние. Единственный способ взаимодействия с этим состоянием — через методы. Использование одного состояния объекта из другого объекта считается антипаттерном. Другими словами: объектно-ориентированное программирование поощряет дублирование состояний.
В этом проблема объектно-ориентированных представлений: каждое представление имеет свое состояние. Это означает, что ваше состояние дублируется: у вас есть состояние в ваших моделях и у вас есть состояние в представлении.
Когда у вас есть повторяющиеся состояния, вам необходимо их синхронизировать. Если вы внимательно посмотрите на MVC, это одно из предложений о том, как реализовать эту синхронизацию. К сожалению, не совсем удовлетворительно; появились десятки вариантов. Почти каждый проект, который я видел, реализует свой уникальный механизм и пытается более или менее эффективно синхронизировать состояния представлений и моделей.
Функции не имеют состояния
В средах Front End для меня оказалось что-то удивительное: React. В начале я думал, что это на один фреймворк больше, но ошибся.
React рассматривает представление как нечто, что вы можете распечатать. Простой компонент React — это функция рендеринга. Идея создания компонентов в React состоит в том, чтобы позволить React лениво вызывать функции рендеринга; как чисто функциональный язык программирования.
Думайте о представлении, как о чем-то, что вы печатаете из состояния, это просто и мощно. Вы не дублируете состояние, и все всегда согласовано.
Теперь любой дополнительный код для синхронизации состояния приложения и состояния просмотра кажется излишним и добавляет ненужные накладные расходы и сложность.
Представление — это функция
Представления не должны сохранять состояние. Это дублирует состояние, а дублирование состояния приводит к повреждению данных и накладным расходам на синхронизацию.
Функции не имеют состояния, предсказуемы и многократно используются. ¿Почему бы просто не напечатать состояние, чтобы показать свое мнение?
В следующий раз, когда вы захотите написать новое представление, подумайте, что произойдет, если вы сможете его распечатать. Как легко становится, когда вы удаляете состояние из представления.