Как правильно поставить задачу для разработки
«Эти разработчики опять ничего не поняли!» — возмущается заказчик мобильного приложения. Но мы все знаем, что у разработчиков тонкая душевная организация и куча злых мемов на случай недопонимания с заказчиком. Чтобы не попасть в череду уточнений, согласований и — самое плохое — исправлений ошибок, нужно просто грамотно написать задачу для специалистов. Как это сделать, рассказывает руководитель проектного офиса “CleverPumpkin” Лада Ларкина.
В данной статье описывается опыт с упором на специфику работы компании именно в нашей сфере – мы занимаемся разработкой мобильных приложений на заказ, но при этом у нас есть несколько собственных продуктов в виде приложений. Если вы не увидите тут идеальных лично для вас процессов, то не переживайте, это вполне нормально, но в любом случае мы считаем, что описанное в той или иной мере может быть применимо в разных областях создания программного обеспечения.
Этап подготовки
Главное: вы сами должны четко представлять ожидаемый от разработчика результат — без этого не получится правильно описать задачи.
Отнеситесь к сбору информации ответственно: до того, как задача попадет к разработчику, вы должны сами полностью понять бизнес- и функциональные требования.
Главное требование к задаче – прочитавший её разработчик должен сразу понять, что ему нужно делать, и это представление должно совпадать с ожиданиями менеджера. А после прочтения идеально описанной задачи у разработчика появляется четкое представление, как он будет ее выполнять.
Декомпозиция задач
Проанализируйте, как задача может быть декомпозирована. Разделить большую задачу нужно так, чтобы между задачами не было пересечений и они логично дополняли друг друга. Возможно, декомпозированную задачу предстоит выполнять разным разработчикам, и важно, чтобы они не делали двойную работу, минимально пересекались и по итогам реализации было минимум конфликтов.
Если в прогрессе декомпозиции появилось несколько задач, которые нельзя делать последовательно — значит, вы перестарались. Разделять задачу нужно, если ее части можно делать одну за другой.
Но базовое правило для декомпозиции — длительность работы над одной задачей не должна быть больше одного дня. В редких случаях — больше, например, если это сложная интеграция, которую не разбить на несколько шагов. Хотя и тут речь может идти о подзадачах не функциональных, а технических.
Название задачи
В названии нужно коротко сформулировать суть задачи, чтобы ее было легко найти в таск-трекере. Мы рекомендуем использовать такую логику для названия:
[версионная особенность] [раздел] — [часть экрана] — [что сделать]
Разберем каждую часть названия:
[версионная особенность] — это может быть версия платформы, MacOS/iPad фичи;
[раздел] — описывает, в каком разделе добавляется функциональность;
[часть экрана] — указывает конкретный блок на экране, если изменения касаются его;
[что сделать] — суть изменения или фичи;
Примеры хороших названий:
«Подключить Firebase Performance»
«Профиль (авторизованный) — добавить пункт история заказов»
«История заказов — реализовать загрузку и отображение списка заказов»
«Заказ из истории — Блок итого — Добавить строку дополнительных услуг»
«[iPad] История заказов — Реализовать просмотр конкретного заказа в split view режиме»
«[iOS 13+] Настройки — Добавить пункт «Siri shortcuts»
Примеры неудачных названий:
«Подключить экран к API» — (какой раздел, экран?)
«Цветовая индикация» — (ее нужно добавить? изменить? где находится?)
Описание задачи
Описание должно быть необходимым и достаточным.
Необходимым — не должно быть пересечений между задачами в описании. Разработчик должен понимать, какую именно часть задачи ему сейчас реализовывать.
Достаточным — у разработчика не только не должно появиться дополнительных вопросов, но и возможности понять что-то не так. Избегайте двусмысленности в задачах.
Текст задачи должен понять любой новый разработчик на проекте. Нужно осознавать, что разработчики хуже понимают контекст проекта, чем менеджеры, вряд ли присутствовали при формировании ТЗ, разработки дизайна и т.д., а впервые видят описание необходимого обновления. Полезно написать, зачем вообще добавляется эта фича и почему она нужна пользователю — тогда у разработчика появятся понимание, что он делает, и, возможно, предложения для улучшения пользовательского опыта.
Не забудьте описать:
как попасть в раздел, в который вносится доработка, если это не очевидно;
что необходимо сделать с учетом специальных обработок для крайних кейсов, если таковые есть;
указать, было ли ранее в приложении реализована схожая функциональность для переиспользования;
указать, планируется ли в будущем переиспользование, что нужно предусмотреть для этого;
что требуется для реализации — макеты, ключи доступа, инвайты и т.д.;
указать, какие данные используются, откуда они получаются, как обрабатываются. Если данные получаются при каком-то условии, то его надо обязательно указать;
какие запросы будут дергаться;
как будет использоваться результат задачи, в том числе, как его сохранить и передать для другой задачи;
есть ли задачи, которые следует связать с текущей;
надо ли добавить аналитику по этой функции.
Описание должно учитывать платформенные особенности, не допустите ошибочных расхождений в одинаковой функциональности.
Лайфхаки и советы
Структурируйте и будьте аккуратны. Разделяйте задачу на логические блоки, чтобы удобно было читать и находить информацию. Для начального заполнения задачи пользуйтесь шаблоном (например, YouTrack, который мы используем в работе, автоматически добавляет формат базовой задачи с местом для верстки, логики и сразу с базовым чек-листом, всем советуем, очень удобно).
Не допустите пересечения параллельных задач между разработчиками. Так вы получите увеличение трудозатрат на разрешение конфликтов и дублирование.
Ставьте задачи на любые изменения. Без этого вы не сможете доказать разработчику, что он сделал что-то не так. Устные договоренности ничего не значат! Без задачи изменения не будут протестированы тестировщиком. Кроме того, часто поставленные задачи служат единственным источником информации о поведении приложения. Отсутствие задачи в начале — недостаток информации потом.
Связь задач между платформами. Обязательно свяжите задачи про одинаковые фичи между двумя платформами в системе постановки задач. Так проще поддерживать актуальность описаний задач при изменениях на обеих платформах, догоняющий разработчик сможет узнать, кто делал задачу на другой платформе, и прочитать обсуждение.
Визуализация для задачи. Иногда схема, диаграмма или картинка опишет разработчику что-то понятнее, чем сложный текст — или хотя бы поможет быстрее разобраться в задаче.
Чек-лист для разработчика
Чек-листы нужны для самопроверки разработчика. При первой реализации они помогают учесть больше кейсов. Всегда проверяйте:
наиболее старую поддерживаемую версию платформы — она же обычно и самая проблемная;
работу на маленьком девайсе;
темную тему;
Кроме того, в зависимости от задачи чек-лист может дополняться следующими пунктами:
Постановка задачи и спецификация программы
Постановка задачи — это процесс формулировки назначения программного обеспечения и основных требований к нему. Описываются функциональные требования, определяющие функции, которые должно выполнять программное обеспечение, и эксплуатационные требования, определяющие характеристики его функционирования. Этан постановки задачи заканчивается разработкой технического задания с принятием основных проектных решений.
Техническое задание в соответствии со стандартом ГОСТ 19.201—78 «Техническое задание. Требования к содержанию и оформлению» имеет следующие основные разделы:
- • введение: наименование и краткая характеристика программного обеспечения;
- • основание для разработки;
- • назначение разработки: описание функционального и эксплуатационного назначения, спецификации функций;
- • требования к программному изделию: к функциональным характеристикам, к надежности, к техническим средствам;
- • требования к программной документации;
- • технологические требования.
Технологические требования определяют выбор следующих принципиальных решений, влияющих на процесс проектирования программного обеспечения:
- • архитектура программного обеспечения;
- • пользовательский интерфейс;
- • метод программирования;
- • язык программирования;
- • среда программирования.
Архитектурой программного обеспечения называют описание создаваемого программного обеспечения на уровне его компонентов и связей между ними.
Архитектура программной системы во многом зависит от предметной области, для которой разрабатывается система. Поэтому часто архитектуры систем, разрабатываемых для одной и той же предметной области, имеют много общего. Следовательно, при проектировании архитектуры новой системы можно воспользоваться решениями, удачно примененными в ранее разработанных системах.
Развитие данного подхода привело к появлению архитектурных шаблонов (паттернов), на основе которых может создаваться архитектура конкретной системы. Архитектурный паттерн представляет собой описание типовой организации программной системы, опробованной в различных условиях и продемонстрировавшей свою эффективность.
Распространенными являются следующие архитектурные паттерны:
- • модель-представление-контроллер
, MVC) применяется в системах, ориентированных на обслуживание клиентов; - • паттерн хранилища данных применяется в системах, функционирование которых связано с обработкой большого объема данных (информационные системы, системы управления); архитектура таких систем должна содержат компоненты, генерирующие данные, и компоненты, их обрабатывающие;
- • паттерн «клиент-сервер» предусматривают распределение заданий между поставщиками и заказчиками услуг. Поставщики (серверы) предоставляют заказчикам (клиентам) определенный набор услуг (сервисов), доступ к которым осуществляется с помощью удаленного вызова соответствующих процедур;
- • паттерны потоков данных предполагают построение архитектуры системы из функциональных модулей, которые получают входные данные п преобразуют их в выходные. Преобразования могут осуществляться как последовательно, так и параллельно;
- • многоуровневая система представляет собой иерархическую систему, состоящую из нескольких уровней, каждый из которых выполняет определенные функции. Каждый уровень предоставляет услуги вышестоящему уровню и использует услуги нижестоящего уровня.
При процедурном программировании модель построения программы — иерархия множества подпрограмм, при объектно-ориентированном программировании — иерархия множества классов, совокупность обменивающихся сообщениями объектов классов. При этом простом виде архитектуры программа — это совокупность отдельно компилируемых программных единиц, используемая при решении задач.
Пакеты программ — это совокупность программ, решающих задачи некоторой прикладной области. Например, пакет математических программ, пакет графических программ.
Программные комплексы — это совокупность взаимосвязанных программ, совместно решающих небольшой класс задач некоторой прикладной области. Для решения задачи могут использоваться несколько программ комплекса, управляемые интерфейсом с пользователем, причем исходные данные и результаты желательно хранить в пределах одного проекта.
Программные системы — это совокупность подсистем программ, совместно решающих большой класс сложных задач некоторой прикладной области. Отличие от программных комплексов — взаимодействие программ системы через общие данные и наличие развитых пользовательских интерфейсов.
Пользовательский интерфейс представляет собой совокупность программных и аппаратных средств, обеспечивающих диалог пользователя и компьютера. Различают следующие типы пользовательских интерфейсов:
- • примитивные интерфейсы;
- • интерфейсы-меню;
- • интерфейсы со свободной навигацией;
- • интерфейсы прямого манипулирования.
К технологическим требованиям к программному обеспечению относятся:
- • выбор метода программирования: процедурный или объектно-ориентированный;
- • выбор языка программирования: C++, Java, Python и др.;
- • выбор среды программирования: Visual Studio фирмы Microsoft, Embarcadero RAD Studio (включающая Delphi и C++ Builder), Eclipse и др.
Спецификациями называют полное н точное описание функций и ограничений разрабатываемого программного обеспечения. Существуют функциональные спецификации, описывающие функции разрабатываемого программного обеспечения, и эксплуатационные спецификации, описывающие требования к техническим средствам. Требование полноты означает строгое соответствие техническому заданию, а требование точности — однозначное толкование спецификаций разработчиком и заказчиком.
- • декомпозицию и содержательную постановку задач;
- • эксплуатационные ограничения;
- • математические методы решения;
- • модели программного обеспечения.
Модели программного обеспечения зависят от технологии программирования (процедурная или объектно-ориентированная).
При процедурном программировании используются следующие модели разрабатываемого программного обеспечения:
- • функциональные диаграммы, отражающие взаимосвязи функций разрабатываемого программного обеспечения и ориентированные на иерархию функций, декомпозицию функций;
- • диаграммы потоков данных, описывающие взаимодействие источников и потребителей информации и позволяющие специфицировать как функции, так и данные;
- • диаграммы структур данных, описывающие базы данных разрабатываемого программного обеспечения;
- • диаграммы переходов состояний, описывающие поведение разрабатываемого программного обеспечения при получении управляющих данных извне (например, команды пользователя).
При объектно-ориентированном программировании модели разрабатываемого программного обеспечения основаны на предметах реального мира. На этапе определения спецификаций требуется разработать модель предметной области программного обеспечения на базе иерархии классов (типов, определенных пользователем), объектной декомпозиции. Разрабатываемое программное обеспечение представляется в виде совокупности объектов (экземпляров классов), в результате взаимодействия которых через передачу сообщений происходит выполнение требуемых функций.
В настоящее время стандартным средством описания разрабатываемого программного обеспечения с использованием объектно- ориентированного подхода является фактически графический язык UML
Язык UML описывает модель сложной системы в виде специальных графических конструкций (диаграмм).
Диаграмма представляет собой связный граф, вершины которого представляются в виде геометрических фигур, связанных между собой ребрами (дугами).
Все диаграммы используют единую графическую нотацию.
В диаграммах используется три типа графических элементов, имеющих различное назначение:
- • геометрические фигуры обозначают вершины графа. Их форма строго соответствует определенным элементам языка (класс, вариант использования, состояние, деятельность). Каждой вершине присваивается уникальное имя;
- • различные линии (ребра), соединяющие геометрические фигуры (вершины графа) обозначают связи и взаимодействия элементов;
- • специальные графические символы, располагаются около других элементов диаграммы и содержат дополнительную информацию. Дополнительный текст может размещаться также внутри контуров геометрических фигур.
Нотация языка UML определяет использование следующих основных видов диаграмм:
- • вариантов использования (прецедентов) — описывают основные функции системы;
- • классов — описывают классы, их характеристики (поля и операции) и связи между ними;
- • кооперации — показывают взаимодействие объектов в процессе реализации варианта использования;
- • пакетов — показывают связи наборов классов, объединенных в пакеты;
- • состояний — демонстрируют состояния объекта и переходы из одного состояния в другое;
- • деятельности — представляют собой схему потоков управления для решения некоторой задачи;
- • компонентов — описывают компоненты программного обеспечения и их связи между собой;
- • развертывания — позволяют связывать программные и аппаратные компоненты системы.
Каждая из этих диаграмм детализирует и конкретизирует различные представления о модели системы в терминах языка. Совокупность этих диаграмм содержит всю необходимую информацию для реализации проекта сложной программной системы. При создании моделей следует придерживаться следующих основных рекомендаций.
Любая модель должна содержать только те элементы, которые определены в нотации языка UML. Каждый элемент может быть использован только в соответствии с назначением и по правилам, определенным в языке.
Каждая диаграмма должна полностью описывать рассматриваемый фрагмент предметной области, на ней должны быть представлены все значимые элементы. Отсутствие каких-либо элементов может привести к серьезным ошибкам в моделировании.
Все элементы диаграммы должны принадлежать к одному уровню представления. При моделировании сложных систем часть используют иерархический подход, при котором диаграммы нижнего уровня уточняют и детализируют элементы диаграмм высших уровней.
Желательно информацию обо всех элементах диаграммы представлять в явном виде, не используя значения, заданные по умолчанию. Это ускорит и упростит процесс реализации модели.
Каждая модель конкретной программной системы может содержать все или только некоторые типы диаграмм.
Тема 13. Постановка задачи и спецификация программы
Одним из наиболее важных шагов программирования является постановка задачи. Она выполняет функции контракта между пользователем и программистом (программистами). Как и юридически плохо составленный контракт, плохая постановка задачи бесполезна. При хорошей постановке задачи как пользователь, так и программист ясно и недвусмысленно представляют задачу, которую необходимо выполнить, т.е. в этом случае учитываются интересы как пользователя, так и программиста. Пользователь может планировать использование еще несозданного программного обеспечения, опираясь на знание того, что оно может. Хорошая постановка задачи служит основой для формирования ее решения.
Постановка задачи (спецификация программы); по существу, означает точное, полное и понятное описание того, что происходит при выполнении конкретной программы. Пользователь обычно смотрит на компьютер, как на черный ящик: для него неважно, как работает компьютер, а важно, что может компьютер из того, что интересует пользователя. При этом основное внимание фокусируется на взаимодействии человека с машиной.
Характеристики Хорошей Постановки Задачи:
Точность, т.е. исключение любой неоднозначности. Не должно возникать вопросов относительно того, каким будет вывод программы при каждом конкретном вводе.
Полнота, т.е. рассмотрение всех вариантов для заданного ввода, включая ошибочный или непредусмотренный ввод, и определение соответствующего вывода.
Ясность, т.е. она должна быть понятной и пользователю и системному аналитику, поскольку постановка задачи – это единственный контракт между ними.
Часто требование точности, полноты и ясности находятся в противоречии. Так, многие юридические документы трудно понять, потому что они написаны на формальном языке, который позволяет предельно точно сформулировать те или иные положения, исключая любые самые незначительные разночтения. Например, некоторые вопросы в экзаменационных билетах иногда сформулированы настолько точно, что студент тратит больше времени на то, чтобы понять вопрос, чем на то чтобы на него ответить. Более того, студент вообще может не уловить основной смысл вопроса из-за большого количества деталей. Наилучшая постановка задачи та, при которой достигается баланс всех трех требований.
Стандартная форма постановки задачи.
Рассмотрим следующую постановку задачи: «Ввести три числа и вывести числа в порядке».
Такая постановка не удовлетворяет приведенным выше требованиям: она не является ни точной, ни полной, ни понятной. Действительно, должны ли числа вводиться по одному на строке или все числа на одной строке? Означает ли выражение «в порядке» упорядочение от большего к меньшему, от меньшего к большему или тот же порядок, в каком они были введены.
Очевидно, что подобная постановка не отвечает на множество вопросов. Если же учесть ответы на все вопросы, то постановка задачи станет многословной и трудной для восприятия. Поэтому Д. Райли предлагает для постановки задачи пользоваться стандартной формой, которая обеспечивает максимальную точность, полноту, ясность и включает:
наименование задачи (схематическое определение);
общее описание (краткое изложение задачи);
ак уже отмечалось выше, в качестве модульной структуры программы принято использовать древовидную структуру, включая деревья со сросшимися ветвями. В узлах такого дерева размещаются программные модули, а направленные дуги (стрелки) показывают статическую подчиненность модулей, т.е. каждая дуга показывает, что в тексте модуля, из которого она исходит, имеется ссылка на модуль, в который она входит. Другими словами, каждый модуль может обращаться к подчиненным ему модулям, т.е. выражается через эти модули. При этом модульная структура программы, в конечном счете, должна включать и совокупность спецификаций модулей, образующих эту программу. Спецификация программного модуля содержит, во-первых, синтаксическую спецификацию его входов, позволяющую построить на используемом языке программирования синтаксически правильное обращение к нему (к любому его входу), и, во-вторых, функциональную спецификацию модуля (описание семантики функций, выполняемых этим модулем по каждому из его входов). Функциональная спецификация модуля строится так же, как и функциональная спецификация ПС.
В процессе разработки программы её модульная структура может по-разному формироваться и использоваться для определения порядка программирования и отладки модулей, указанных в этой структуре. Поэтому можно говорить о разных методах разработки структуры программы. Обычно в литературе обсуждаются два метода: метод восходящей разработки и метод нисходящей разработки.
Метод восходящей разработки заключается в следующем. Сначала строится модульная структура программы в виде дерева. Затем поочередно программируются модули программы, начиная с модулей самого нижнего уровня (листья дерева модульной структуры программы), в таком порядке, чтобы для каждого программируемого модуля были уже запрограммированы все модули, к которым он может обращаться. После того, как все модули программы запрограммированы, производится их поочередное тестирование и отладка в принципе в таком же (восходящем) порядке, в каком велось их программирование. На первый взгляд такой порядок разработки программы кажется вполне естественным: каждый модуль при программировании выражается через уже запрограммированные непосредственно подчиненные модули, а при тестировании использует уже отлаженные модули. Однако, современная технология не рекомендует такой порядок разработки программы. Во-первых, для программирования какого-либо модуля совсем не требуется текстов используемых им модулей — для этого достаточно, чтобы каждый используемый модуль был лишь специфицирован (в объёме, позволяющем построить правильное обращение к нему), а для тестирования его возможно (и даже, как мы покажем ниже, полезно) используемые модули заменять их имитаторами (заглушками). Во-вторых, каждая программа в какой-то степени подчиняется некоторым внутренним для нее, но глобальным для ее модулей соображениям (принципам реализации, предположениям, структурам данных и т.п.), что определяет её концептуальную целостность и формируется в процессе ее разработки. При восходящей разработке эта глобальная информация для модулей нижних уровней ещё не ясна в полном объеме, поэтому очень часто приходится их перепрограммировать, когда при программировании других модулей производится существенное уточнение этой глобальной информации (например, изменяется глобальная структура данных). В-третьих, при восходящем тестировании для каждого модуля (кроме головного) приходится создавать ведущую программу (модуль), которая должна подготовить для тестируемого модуля необходимое состояние информационной среды и произвести требуемое обращение к нему. Это приводит к большому объему «отладочного» программирования и в то же время не дает никакой гарантии, что тестирование модулей производилось именно в тех условиях, в которых они будут выполняться в рабочей программе.
Метод нисходящей разработки заключается в следующем. Как и в предыдущем методе сначала строится модульная структура программы в виде дерева. Затем поочередно программируются модули программы, начиная с модуля самого верхнего уровня (головного), переходя к программированию какого-либо другого модуля только в том случае, если уже запрограммирован модуль, который к нему обращается. После того, как все модули программы запрограммированы, производится их поочередное тестирование и отладка в таком же (нисходящем) порядке. При таком порядке разработки программы вся необходимая глобальная информация формируется своевременно, т.е. ликвидируется весьма неприятный источник просчетов при программировании модулей. Существенно облегчается и тестирование модулей, производимое при нисходящем тестировании программы. Первым тестируется головной модуль программы, который представляет всю тестируемую программу и поэтому тестируется при «естественном» состоянии информационной среды, при котором начинает выполняться эта программа. При этом все модули, к которым может обращаться головной модуль, заменяются их имитаторами (так называемые заглушки [5]). Каждый имитатор модуля представляется весьма простым программным фрагментом, сигнализирующим, в основном, о самом факте обращения к имитируемому модулю с необходимой для правильной работы программы обработкой значений его входных параметров (иногда с их распечаткой) и с выдачей, если это необходимо, заранее запасенного подходящего результата. После завершения тестирования и отладки головного и любого последующего модуля производится переход к тестированию одного из модулей, которые в данный момент представлены имитаторами, если таковые имеются. Для этого имитатор выбранного для тестирования модуля заменяется на сам этот модуль и добавляются имитаторы тех модулей, к которым может обращаться выбранный для тестирования модуль. При этом каждый такой модуль будет тестироваться при «естественных» состояниях информационной среды, возникающих к моменту обращения к этому модулю при выполнении тестируемой программы. Таким образом, большой объем «отладочного» программирования заменяется программированием достаточно простых имитаторов используемых в программе модулей. Кроме того, имитаторы удобно использовать для подыгрывания процессу подбора тестов путем задания нужных результатов, выдаваемых имитаторами.
Лекция 8
Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:
Как решить любую задачу: пособие для разработчика
Каждый разработчик рано или поздно получает задачу, которую просто не понимает. Разбираемся, как преодолеть пропасть между требованиями и знаниями.
Неважно, как долго вы работаете и как много у вас опыта. Даже разработчик с десятилетним стажем имеет все шансы встретиться с непонятной задачей. Как же быть? Просто начать и верить, что по ходу дела все станет яснее? Или немедленно сообщить начальнику, что вы не понимаете, что от вас хотят?
Оба ответа неправильные.
В разработке ПО (и любой другой профессии) подобные проблемы возникают постоянно. И это неплохо! Поверьте, вы способны не только решить их, но и извлечь из этого пользу, расширив свои знания и навыки.
О «требованиях»
В разных компаниях и проектах требования могут быть разными. Крупные компании обычно тщательно их прописывают, а маленькие могут иногда вообще не составлять.
В конечном счете наша цель как разработчиков – решать проблемы. Каким бы способом вы ни получили задачу, чтобы решить ее, вы должны ее понять.
О шагах
Ниже приведена последовательность шагов для решения сложных задач. Не всегда нужно выполнять каждый из них. Многое может пойти не по плану и вам придется искать ответы у коллег, аналитиков, руководителей, а возможно, и родственников. Этот процесс сбора и обобщения знаний из разных источников абсолютно нормален и поможет вам достигнуть лучшего результата.
И прежде чем мы перейдем к самим шагам, последнее предупреждение: не формализируйте их. Основная цель статьи – научить вас быстрее понимать проблему, а не создавать лишние барьеры и волокиту.
Первый шаг: анализ задачи
На этом шаге нужно попытаться осознать, что вам нужно сделать. Не как, а именно что.
Это важное уточнение. Иногда сразу переходить к воплощению, не продумав все последствия и не осознав конечную цель, может быть опасно.
Классифицируйте задачу
Определите, к какому типу относится работа, которую вам нужно выполнить. Это может быть:
- правка ошибок;
- внедрение новой функциональности;
- создание нового приложения;
- исследование проблемы;
- улучшение производительности.
Это не все возможные типы задач, но теперь вы понимаете, о чем идет речь.
Основная цель на этом этапе – определить вид работы. Это очень важно, поскольку будет напрямую влиять на ваши дальнейшие действия.
Особую важность имеет первый шаг в том случае, если требования составлены нечетко, вроде «нам нужен способ очистить кэш клиентов после обновления веб-сайта». Это можно интерпретировать по-разному:
- Необходимо немедленно реализовать некий механизм очистки кэша, чтобы пользователи всегда видели последние обновления.
- Нужно изучить все возможные способы хранения кэша и определить лучшие методы для его очистки после внедрения обновлений.
- Кэш пользователей уже должен был быть очищен, а вам требуется найти и исправить ошибку, которая этому препятствует.
Если вы не совсем уверены, что скрывается за этими требованиями, следует попросить разъяснений, прежде чем продолжать.
Сформулируйте задачу в паре простых фраз
Обобщите требования в одном или двух предложениях. Возможно, это будет не очень просто, но у вас обязательно получится.
Если вы не можете это сделать, значит, нужно разделить задачу. Таким образом, этот шаг является лакмусовой бумажкой для определения правильной организации рабочего процесса. Если задача слишком велика, нужно решать ее по частям.
Хороший пример обобщения: «при обновлении мы добавляем файлам уникальный идентификатор, чтобы браузер знал, что нужно использовать самый свежий код». Тест на простоту пройден, задача не нуждается в делении.
А пример плохой постановки задачи. «При обновлении мы добавляем файлам уникальный идентификатор, чтобы браузер знал, что нужно использовать самый свежий код. Также мы должны отправить сообщение об обновлении в CDN. Также следует обновить приложение в app store. Также…».
Это точно провал. Для решения этой задачи требуется слишком много действий, поэтому ее, вероятно, следует разделить и отслеживать каждую подзадачу отдельно.
Выделите основные части
Составьте список основных дел в любой удобной форме. Ограничьтесь очень простыми общими описаниями для каждого крупного этапа, а не составляйте подробное руководство. Лучше всего записать все ваши идеи.
Помните, что сейчас вы все еще анализируете задачу, а не решаете ее.
Пример с кэшированием слишком прост и не нуждается в схеме, поэтому мы введем более сложную задачу по созданию новой фичи: «Необходимо показывать целевое рекламное объявление, адаптированное для каждого пользователя на основании собранных данных».
Наметим основные части:
- Текущие объявления следует разделить так, чтобы они могли соотноситься с какой-то конкретной метрикой пользователя.
- Для маркетинговой команды нужен удобный способ сопоставить новые рекламные объявления с пользовательскими данными.
- Система должна агрегировать все показатели, которые имеют отношение к рекламе.
- Наконец, нужно каким-то образом получать идентификатор пользователя и выводить объявления.
Теперь этот список можно использовать для быстрого обсуждения с командой или руководителем, после которого могут быть внесены новые пункты, например:
- Нужно добавить для пользователя возможность сообщить о том, что он больше не хочет видеть конкретные объявления.Вы же не хотите раздражать ваших любимых клиентов!
Вот так, немного подумав над задачей и составив план, вы сэкономили часы или даже дни разработки и избежали множества проблем.
Возможно, вы считаете, что вся эта работа должна быть выполнена еще до того, как разработчик получит требования – и это на 100% верно!
Однако мы, к сожалению, не живем в идеальном мире, и требования не всегда полностью конкретизируются до того, как попадут к разработчику. Поэтому нужно сделать все возможное, чтобы правильно оценить задачу.
Определите проблему, которую вы пытаетесь решить
Определитесь, какую существующую или предполагаемую проблему реального мира вы пытаетесь решить.
В идеале ответ очевиден. Например, в задаче с кэшем цель состоит в том, чтобы пользователи всегда видели последние обновления. В примере с рекламой мы решаем проблему релевантности объявлений для пользователя.
Если вы не можете ответить на вопрос, вероятно, следует спросить кого-то, зачем вы решаете эту задачу. Либо вы получите более четкое представление, либо еще раз подумаете о том, что необходимо сделать.
Более глубокое понимание проблемы и цели позволит вам принять лучшие решения при реализации и избежать бесполезных усилий.
Второй шаг: разбор и оценка требований
Вы уже знаете, что и зачем вы должны сделать. На следующем шаге следует понять, каким способом решать задачу и почему им.
Уточните все термины, связанные с задачей
Вероятность встретить незнакомые понятия гораздо выше, если вы новичок или являетесь сотрудником большой компании.
Речь идет и о бизнес-терминах, например, продуктах, клиентах или процессах, и о понятиях разработки, таких как названия инструментов, приложений, служб или библиотек.
Возможно, вы знаете, что значит создать доступ к агрегированным данным о пользователе, а как насчет ее добавления в DAO? А имеете ли вы представление о том, что такое MADF в форматировании рекламных данных?
Если вы не понимаете важные термины, то общий смысл задачи может от вас ускользнуть и пострадает реализация.
Определите, как должна быть выполнена задача
Теперь можно начинать думать, как выполнить задачу. В зависимости от проекта этот этап может сильно различаться. Вам могут просто рассказать, какую функциональность нужно получить в итоге, или подробно описать каждый шаг, который следует сделать. Чаще всего встречается нечто среднее.
Если вы получили инструкции, то обязательно ознакомитесь с ними и оцените их. Это кажется очевидным, но обратите внимание, в какой именно момент мы переходим к этому шагу.
Вы могли бы погрузиться в технические детали реализации прежде, чем поняли суть и цель задачи. Но вы сделали все правильно и теперь можете объективно оценить каждую инструкцию.
Определите, решены ли проблемы
Именно на этом шаге происходит реальный анализ и интерпретация задачи. Здесь вы можете сосредоточиться на общей картине целей и результатов, подводя итог тому, что и зачем (анализ) и как (интерпретация) вы должны сделать.
Проделав всю подготовительную работу, вы видите более широкую картину. Взгляните на план действия и подумайте, приведет ли он вас к нужному результату и решит ли первоначальную задачу.
Если ответ положительный, начинайте работать. В ином случае для разрешения конфликтов необходимо перейти к третьему шагу.
Третий шаг: критическое мышление
Вы уже хорошо понимаете суть проблемы и знаете, как ее решить. Последний шаг поможет убедиться, что ваше решение правильное.
Чтобы создать самый лучший продукт, мы обязаны отсекать недостатки и бессмысленные вещи, но прежде чем сказать коллегам о том, что конкретный подход неправильный, нужно объяснить почему это так.
Сформулируем некоторые основные правила о разногласиях.
Когда не соглашаться
- Не возражайте, пока не поймете полностью.
Вы хорошо понимаете, с чем именно несогласны? Если у вас нет всех необходимых данных, самое время вернуться к предыдущим шагам.
- Не спорьте по субъективным вопросам. Сосредоточьтесь на реальных возможных проблемах.
«Мне не нравится» – это субъективно. “Большое количество операций плохо повлияет на производительность» – это объективно.
- Подготовьте аргументированное объяснение вашего несогласия.
Вы не способны объяснить, почему это неправильно? А вы уверены, что это действительно неправильно?
Прежде чем вы не согласитесь, внимательно выслушайте коллег и постарайтесь понять их аргументы. Может быть, вы что-то упускаете.
Как не соглашаться
Чтобы ваше несогласие было объективным, оно должно ясно демонстрировать, что принятое решение:
- основано на неполной информации, не учитывает существующих условий и данных;
- основано на ложной или ошибочной информации;
- нелогично или ломает существующую функциональность. Также нелогичной может быть сама исходная проблема;
- не решает проблему полностью. Иногда это именно то, что требуется. В разработке ПО мы часто начинаем с создания минимально жизнеспособного продукта, лишенного некоторой второстепенной функциональности. Но порой решение не дотягивает даже до этого уровня.
Подведем итоги
Запомните самое важное: не формализируйте этот процесс. На практике он гораздо быстрее и проще, чем в теории. Просто записывайте ваши мысли в заметки и при необходимости поговорите пару раз с коллегами, чтобы уточнить все тонкости задачи и реализации. Вот и все!
Вот упрощенный список шагов:
Шаг 1. Анализ
- Классификация задачи;
- Резюме в паре предложений;
- Выделение основных частей;
- Определение проблемы.
Шаг 2. Разбор и оценка
- Уточнение терминов;
- Составление общего плана реализации;
- Проверка, решает ли этот план проблему.
Шаг 3. Критическое мышление
- Знайте, когда не соглашаться;
- Знайте, как не соглашаться.
Используете ли вы эти приемы? А может быть, у вас есть своя система для понимания сложных задач? Расскажите о ней в комментариях.