Объектно-ориентированное про…ектирование?

Vanilla Thunder
DesignSpot
Published in
13 min readDec 14, 2021

--

Душная аудитория, 12 человек сидит за столами, все судорожно пишут строки кода на листочках, чёркают, мажут корректором. Преподавательница по лабам смотрит на наши страдающие гримасы с улыбкой. Ей нравится, хотя и немного грустно, что семестр тирании вот-вот закончиться.

«И помните, последнее задание на 9–10 баллов — описать основные принципы и парадигмы ООП», — говорит она и улыбка оголяет её острые жёлтые зубы. Она знает, что мы не знаем, но знаем, что она знает, что мы не знаем. И от этого страдание ещё вкуснее.

«Про иерархию, абстракцию и наследование ещё можно догадаться, но полиморфизм и инкапсуляция… кто вообще придумал эти слова?!», — звучит голос у меня в голове. Звонок. Пора сдавать листики с кодом, чтобы микропроцессор в голове у преподавательницы закомпилил наши шедевры и выплюнул результат в зачётки. Тогда я получил 7 и это был первый курс универа. Кто знал, что эти незнакомые слова всплывут через столько лет, но уже в проектировании интерфейсов.

Что такое ООП?

Это фундаментальный закон познания, когда мы открываем новый домен, типа проектирования взаимодействия, сперва поражены уникальностью, но по прошествии времени начинаем находить параллели с уже существующим в нашем мире. Так дизайн взял многое у психологии и социологии, а сейчас караулит в подворотне статистику и дата-анализ, намереваясь отжать что-то и у них.

В сопряжении сфер и рождается новое знание, когда идеи перетекают из одного домена в другой, но я никогда не думал, что дело дойдёт до ООП. Дошло. И это вдохновляет. Так что это за зверь?

Изначально, ООП, широко известно в узких кругах, как объектно ориентированное программирование — это методология разработки основанной на объектах и классах. Понимаю, пока ничего не понятно, но мы только в начале пути, но сейчас всё проясниться.
Дело в том, что в какой-то момент, программирование перестало трактоваться, как строго определенная последовательность действий:

→ Открыть этот пост,

→ Прочитать пост,

→ Похлопать в ладоши,

→ Поделиться ссылкой.

Вместо этого, кто-то очень умный решил, что вместо того, чтобы пытаться выстроить алгоритмы работы этого мира, нужно сконцентрироваться на том, из чего этот мир состоит — на объектах.

Disclaimer: и да простят меня приверженцы всех других парадигм программирования и опустят свои тухлые помидоры, ибо сейчас речь не о них.

Посмотрите вокруг себя, вас со всех сторон окружают предметы: рядом со мной лежит пёс, подо мной ковёр, рядом кровать, часы, шкаф — всё это объекты, которые обладают какими-то свойствами, и с которыми я могу что-то делать (или они делают что-то сами). Например, я могу вызвать метод СколькоХлама у шкафа и узнать, сколько там одежды, могу переопределить свойство виляния хвостом у пса или обратиться к API часов и узнать, который час.

Тоже самое сделали и для программирования: вместо простых директив, которые идут одна за другой, начали использовать классы и объекты этих классов. То есть всесто того, чтобы писать

→ Если нажали на карточку 1 → Добавить в корзину товар 1,

→ Если нажали на карточку 2 → Добавить в корзину товар 2,

Достаточно было просто создать специальный класс «Карточка», у которого было бы свойство «Товар» и метод «Добавить в корзину». И всё, что оставалось сделать, так это насоздавать экземпляров этого класса, и вуаля — каждая карточка делает нужное действие. Пример утрирован, конечно, там ещё очень много всего супер-сложного, но суть, надеюсь, ясна.

Каждый класс может обладать свойствами и реализовывать методы.

Свойство — это атрибут, присущий всем экземплярам класса. Или проще «Что содержит в себе объект?». Вот калимба. Какими свойствами она обладает? Материал, количество липестков, наличие резонатора, степень настройки. А вот мой пёс. Что у него? Режим работы (сон или пытка), количество вылиняной шерсти, степень голода, длина когтей — всё это свойства.

Метод — это действия, которые можно произвести с объектом (или действия, которые выполняет он сам). А какие методы реализует калимба? Извлечь звук, настроить ноту молотком, успокоить разум медитацией. А пёс? Вилять хвостом, скулить, смотреть жалобными глазами (принимает константу «Хозяин»), дрожать, поглощать объекты (принимает любой объект, можно не съедобный), лаять (по умолчанию выставлена степень чувствительности «Пук белки в радиусе 3 км») и т.д. — всё это методы моего пса.

Самое интересное, что когда разберёшься, как это работает, то всё захочется структурировать под такой шаблон. Наверное потому в примерах фигурирует мой пёс. Но на этом, наверное всё. Если вам захочется ещё глубже погрузиться в тему и начать копать в код, сейчас в сети полно инфы по теме — удачи вам в изучении интерфейсов и псевдо-классов. Но если вам хочется узнать, зачем вы только что прочли введение в Объектно Ориентированное Программирование, то прошу за мной.

Причём тут дизайн?

Да собственно при том, что сейчас набирает популярность такой подход к проектированию, как OOUX (Object Oriented UX), который по сути своей базируется на парадигме описанной выше.

Sophia V. Prater в своей статье 2015 года предложила отойти от привычного процесса проектирования экранов и обратить внимание на Объекты, на которых всё строится.

Уже успела устареть сама мысль о том, что наш подход к проектированию устарел. Пора бы уже перестать начинать дизайн с того, чтобы рисовать страницы-прямоугольники и фаршировать их контентом под фразу «Ну, наверное вот это должно быть на тут», а потом «Блин, забыл, нужно же ещё вот это…». Бывало у вас такое? У меня, например, уходило не одна итерация скетчинга, чтобы всё устаканить. Хотя я и считаю, что скетчинг, на то и скетчинг, чтобы быстро итерировать. Но ведь можно это делать эффективнее.

Отход от экранного мышления неизбежен, ведь взаимодействие выходит далеко за рамки монитора, а проектирование обязано покрывать все закоулки пользовательского опыта. И если вы ещё думаете «Нужно сделать главную, потом корзину, потом карточку товара…», то у меня для вас новости: вы ходите по тонкому льду, рискуя упустить что-то важное.

У вас не было такого чувства, что в нашем процессе чего-то не хватало. Но даже несмотря на это паучье чутьё, мы не знали, как делать работу иначе, потому экранное мышление просуществовало так долго. Но это не значит, что OOUX взял родился в одночасье. Ещё до того, как я услышал это модное словцо, я занимался чем-то подобным, рисуя flow взаимодействия с прописью всех компонентов и данных в них. Но как это называется, я не знал. Я в этом не одинок. Все дизайнеры, рано или поздно, начинают задумываться над тем, что им понадобиться для успешного завершения процесса, просто делают это по-разному.

Пример псевдо OOUX вшитого в microframe

И тут в игру вступает OOUX, формализующий это дело. Ещё до того, как хвататься за карандаш, нужно задуматься, а с чем будет вестись взаимодействие, какие объекты понадобятся, какими свойствами и методами они будут обладать, чтобы обеспечить пользователю комфортное достижение целей. Теоретически, это должно вас привести к более эффективному рабочему процессу и снижению вероятности что-то забыть. На практике же, давайте смотреть.

🌪 Классический пример

Давайте разберем на одном примере два процесса проектирования и сравним их. На одной чаше весов будет экранное мышление, а на другой — OOUX, подход предложенный Софией. Рассматривать мы будем проектирование сервиса для аренды кваритир.

Ещё до того, как я стал ярым пропагандистом сторифрейминга, то есть словарного описания ментальной модели пользователя, мой процесс выглядел приблизительно так. Приходит задача:

Для меня, как для пользователя системы, важно получить весь список предложений с возможностью фильтрации и поиска, чтобы я мог выполнить выбор оптимального варианта жилья. Было бы замечательно, если бы система сама предлагала мне варианты, наиболее подходящие моим запросам, но сейчас этого не происходит, из-за чего приходится тратить много лишнего времени и усилий на поиск.

«Ну и что тут сложного», — думаю я, — «нам просто нужен листинг из карточек-предложений, возможно, предложу карту, как паттерн для более эффективного выбора, фильтры там будут сверху (просто дроп-дауны), на карточках обязательно фото, описание, рейтинг, стоимость… Ну как-то так.» Оторвав лайнер от бумаги, можно насладиться своим трудом. В лучших традициях дриббблоделов, кайф!

Простите за детализацию, но это просто пример 🙂

Ну всё, расчихляем фигму. Хотя можно было бы прорисовать ещё пару экранов и переходы между ними, соорудив полноценный микрофрейм, но в нашем случае…

За этим следовали несколько итераций в редакторе, демо и открытое шампанское. Но если этот процесс знаком и вам, вы должны помнить, как ваше ликование разбивалось о скалы «новых обстоятельств». Как пришёл БА и жёстким подзатыльником выбил клубнику изо рта и сказал: «У нас описание объекта в триста строк сгенерировано искусственным интеллектом AliExpress, карта не работает, как и рейтинг, фоток пока нет, арендовать объект нельзя, можно только посмотреть номер арендодателя… и вообще, мы теперь шаурму продаём». Знакомо? Что вы вздыхаете? Все там были.

☀️ OOUX на практике

Теперь давайте посмотрим, что произойдёт, если сперва задуматься об объектах, их свойствах и методах. Вместо того, чтобы хвататься за карандаш… Не, ну карандаш давайте всё-таки возьмём, но не будем рисовать прямоугольники, а начнём писать.

Но прежде, чем вы начнёте линеить белую гладь листа, я хотел бы обратить внимание, что в процессе мы познакомимся с некоторыми принципами работы с объектами, проще — непонятными словами, типа абстракция, инкапсуляция, наследование и полиморфизм. Взяты они всё из того же программирования, но отлично вписываются и в наш дизайн-подход. Просто, чтобы вы не пугались, смысл откроется по пути. Итак, поехали.

Выделяем объекты

Откуда вообще берутся объекты? В основном, из целей и задач пользователя, которые хорошо бы определить заранее. В нашем случае, на поверхности лежат минимум 3 объекта: мы хотим найти лучший вариант жилья, значит у нас всенепременно будут объявление, арендодатель и арендатор со всеми его просмотренными объявлениями, контактами, интересами и остальными атрибутами.

Хотя есть здесь свой подвох: просто на целях или JTBD сконцентрироваться не получится. Так или иначе придётся создавать сторифрейм или пользовательские истории, чтобы понять, как целей достигнуть, и с какими объектами придётся столкнуться по-пути.

В нашем примере, всё довольно просто — есть объявления, которые создаёт один пользователь, а второй их просматривает. И при этом, на этот сценарий могут наложится дополнительные объекты-помощники, например, «Договор аренды», если наш сервис поддерживал бы такую функцию.

Далее в примере я буду использовать только объект «Объявление», для простоты восприятия.

Определяем наполнение объектов

После того, как объекты определены, хорошо бы усадить рядом аналитика или эксперта в области, чтобы определить, каким минимальным набором свойств должен обладать объект, чтобы нормально функционировать в системе. Желательно помечать предполагаемые объемы и типы данных, чтобы в последствии не встретить непроходимую стену скорби бизнес-анализа.

Золотого правила, как определить набор свойств нет — слушайте своё сердце, здравый смысл и user flow, задаваясь вопросом «на основе чего будет приниматься решение?»

И здесь нас поджидает первый принцип ООП — Абстракция. Суть его в том, что объект не нужно описывать максимально детально, нужно руководствоваться минимальным достаточным набором. Для тех, кто хоть когда-нибудь что-нибудь покупал онлайн: для объекта «Заказ», с точки зрения взаимодействия, не важен вес посылки, если только на него не завязана стоимость доставки. Как и неважен логистический маршрут и имя водителя фуры, главное — дата поставки. Хотя никто не мешает набрейнстормить все-все возможные свойства, а потом урезать лишнее—тоже неплохо работает.

Для нашего примера я позволил накидать себе немного свойств и методов «из головы». Как вы понимаете, здесь описаны только мои предположения, которые по-идее, должны будут стать свалидированными гипотезами. Но пока и рак рыба.

Заметьте, что я эти упражнения делал один, но никто не мешает собраться на командный мозговой штурм с экспертами домена или асинхронно накидывать идеи в коллективе. Так и меньше вероятность того, что что-то забудется и все будут в курсе наших ожиданий, начнут говорить на одном языке.

Определяем связи и вложенность компонентов

Закономерным шагом в процессе определения свойств будет создание иерархии или вложенности объектов друг в друга. Например, избранные объявления в объекте «Арендатор».

Иерархия поможет увидеть преемственность данных в системе и сможете понять в каких контекстах и что будет реиспользовано. Здесь стоит упомянить о Наследовании, как о способе упорядочивания системы. Если коротко, то это способ организации, при котором мы «выносим за скобки» всё общее, а в объектах оставляем уникальное. Аналогия из биологии: какой-то набор свойств вы унаследовали от отца, а какие-то свойства приобрели самостоятельно. Отец ваш, как и вы, в свою очередь, являетесь представителями млекопитающих с парным набором конечностей, которые в свою очередь наследуются… ну вы поняли.

Давайте предствим, что у нас на сервисе будет присутствовать два разных типа объявлений: долгосрочная и краткосрочная аренда (посуточно). Можно было бы рассматривать их как один объект «Объявление», нафаршировав его всем возможным набором свойств и методов для каждого типа. Однако, если различия слишком большие—отзывы и рейтинг на саму квартиру гораздо более важны при посуточной аренде, а для долгосрочной гораздо более ценны мнения о хозяине; где-то котируется цена за месяц, а где-то за сутки; удалённость от центра или близость к достопримечательностям и т.д. Тут лучше воспользоваться наследованием.

Несмотря на различия, сходства ведь тоже есть. И что делать? В таком случае можно поступить следующим образом: создать объект «Объявление», куда положить все схожие свойства и методы, а от него унаследовать ещё два объекта «Посуточное объявление» и «Долгосрочное объявление». Так вы сможете вынести за скобки всё общее и избежать избыточности и дубликатов.

Приоритезируем свойства

Не все свойства одинаково полезны: какие-то могут представлять собой мета-информацию (информация о жизни объекта в системе, типа «когда объявление создано»), а какие-то представляют собой критерий принятия решения (такие, как фотографии в объявлении).

В связи с этим, чтобы построить грамотную визуальную иерархию, адаптированную под любой контекст, свойства желательно проранжировать. Тут вам и карточная сортировка в руки.

Определяем CTA-inventory

Как только свойства устаканились, можно переходить к методам, то есть к тому, что с нашим объявлением можно делать.

А чтобы не думать, с чего начать, и сразу смазать свои мозго-шестерни, то вот вам одно определение, которое я перенял из программирования — CRUD. Это акроним методов, который должны поддерживать все объекты, хранимые в базах данных: создание (Create), чтение (Read), обновление (Update), удаление (Delete). С этого можно начать, но не останавливаться, ведь CTA-inventory (такое название придумали методам объекта) должен адаптироваться под ваши конкретные нужды.

И здесь нам снова поможет Flow map, дабы понять, все-ли действия покрыты и можно-ли попасть о все части сценария. В этом процессе могут возникнуть дополнительные свойства, которые нужно добавить в перечень. Например, метод добавления в избранное породит свойство «объявление в избранном или нет».

Чувствуете? Как-то все просто. Давненько никакой заумный принцип не всплывал. А вот и он — Инкапсуляция. Дело в том, что свойства и методы не могут существовать вне объекта, иначе они перестануть быть свойствами. А значит, если что-то где-то происходит, значит это кому-то нужно.

Тот же метод добавления объявления в избранное будет частью объекта… «Пользователь», ибо именно в нём будут храниться ссылки на все «залайканые объявления», а не в объявлении айдишники всех пользователей, которые его залайкали.

Определяем контекст

Но что ещё более интересно, что любой объект должен будет работать в разных контекстах и для разных ролей, при этом сохраняя свою целостность.

Таким образом формируется набор свойств и методов для одного объекта, который должен будет реализовываться во всех его представлениях — хоть на карточке, хоть на отдельной странице. Это и есть проявление завершающего принципа ООП — Полиморфизма. Он гласит: один интерфейс, но много его реализаций.

В этом и крутота объектно-ориентированного подхода —он абстрактный, не привязаный к каким-то экранам. Но это не значит, что нужно везде реализовывать весь набор свойств: что-то можно и скрывать за ненадобностью, но это скорее повод подумать, а не тыкать пальцем в небо.

Для каждого из наших объектов, коих не так много, мы определили представления (карточки, элементы списка, страницы и т.д.) и состояния (ожидает оплаты, оплачен, ошибка, обработка и т.д.), а затем для каждой пары выбираем необходимый набор свойств и методов. Получилась довольно наглядная модель.

И казалось бы, всё супер, пора возрадоваться и переносить всё на бумагу. И вы будете правы. Ну как вам новый подход? Мне очень нравится, но не смотря на все достоинства, подход не лишён своих недостатков.

🤔 Реальность шепчет

Каким бы логичным и правильным не показался OOUX, в реальности, как вы понимаете, нет чистого чёрного и чистого белого. Я решил затестить подход в боевых условиях (проект финансового домена), а не на поварах и макаронах, и посмотреть, что из этого получится.

Со старта начали вылезать камушки, например, нельзя просто взять и сказать «мне нужно это и это», ибо ты не знаешь, что тебе понадобиться на пути, пока ты его не создашь. Так или иначе, приходится строить сторифрейм или user flow, который уже вбирает в себя части OOUX — получается слегка двойная работа. То есть, начинать с OOUX сложные проекты не получится, а вот продолжать вполне себе можно.

Продолжая испытания выяснилось, что в одиночку проект из незнакомого домена потянуть будет невозможно, так как приоритетный набор свойств будет вам неизвестен, а «из головы» генерить их можно просто бесконечно. Конечно, в нашем случае нам помогли консультации экспертов, а вам могут помочь и воркшопы, но как вы понимаете, не везде есть ресурсы на всё это.

Также, для простых простых сценариев OOUX избыточен и излишне трудоёмок, а порой и вовсе не требуется — не факт, что кто-то вам вообще спасибо за это скажет. Хотя никто не мешает вам структурировать таким образом свои мысли, даже если ничего нового вы не узнаете.

Ну и завершающий недостаток — неприменимость подхода в проектировании процессов, где скорее важно не «что», а «куда» и «как». Здесь скорее подойдёт функциональное проектирование, но это уже совсем другая история.

Как итог, в нашем случае подход был довольно тепло воспринят стейкхолдерами, как вполне наглядная объектная модель (думаю, БА и FE должны оценить). Команде дизайна она помогла исправить ряд недостатков системы, которые просто выпали из головы на ранних этапах проектирования. В общем, лично мне подход кажется перспективным, главное не пихать его во все щели по поводу и без, а находить правильный контекст применения: если вы проектируете процессы в условиях большой неопределенности — OOUX вам мало поможет, а вот если ваш сервис работает с вполне чётким набором объектов — это ваш друг.

Памятка по объектно-ориентированному проектированию

или как OOUXить

  1. Определитесь с объектами в вашей системе,
  2. Наполните объекты свойствами (Абстракция),
  3. Выстройте иерархию и используйте наследование,
  4. Приоритезируйте ваши свойства,
  5. Определите методы (CTA-inventory), помня про инкапсуляцию,
  6. Адаптируйте ваш объект под все контексты использования: состояния и представления (Полиморфизм).

Далее по теме

Первая часть оригинальной серии статей об объектно-ориентированном проектировании от Софии,

Вторая часть про определение методов (на русском),

— О важности перехода к новой модели мышления,

— Чуть-чуть программирования и трансформеров в ООП.

На этом все. Чуть было не забыл порекламировать свой канальчик в телеге, где нет рекламы и только мысли и отборный контент.

Теперь точно всё. Прекрасного вам настроения, простых объектов с шикарными свойствами и понятными методами. Счастья-здоровья и корабль любви. 🛳❤️

--

--

Vanilla Thunder
DesignSpot

Dmitry Vanitski, Principal UX Designer, Lithuania