В этой статье рассказывается, как решать проблемы программирования с помощью процесса PEDAC Launch School. Есть много способов решить проблемы с кодированием, и PEDAC - лишь один. Цель этой статьи не в том, чтобы объявить PEDAC лучшим или единственным подходом, а в том, чтобы представить его как один из инструментов, к которому вы можете обратиться, когда начинаете работать над проблемой. Возможно, вам не понадобится PEDAC для решения каждой задачи, но вы найдете много преимуществ в использовании какой-либо системы при работе над более сложными задачами. Чем сложнее проблема кодирования, тем больше вам нужен строгий процесс, такой как PEDAC. Этот подход особенно полезен для новичков, которые учатся программировать, потому что многим новичкам никогда раньше не приходилось использовать систему мышления. Это также подход к более формальным алгоритмическим методам решения проблем.

Что такое ПЕДАК?

PEDAC означает «[Понять] проблему, E образцы / тестовые примеры, D ata Структура, A алгоритм и C оду ». PEDAC преследует две основные цели: обработать проблему (PEDA) и кодировать с намерением (C).

Обработка проблемы состоит из 4 шагов, которые приведут вас от первоначальной постановки проблемы к твердому пониманию того, что требуется. Результатом является алгоритм, который вы будете использовать для реализации решения.

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

Зачем использовать PEDAC?

PEDAC экономит время при решении задач определенной сложности. Может показаться нелогичным, что такой трудоемкий процесс, как PEDAC, может сэкономить время, но это именно то, что он делает, когда проблема сложна. Нельзя сказать, что переход сразу к кодированию всегда медленнее; на самом деле это иногда быстрее для простых задач. Однако чем сложнее проблема, тем больше вероятность того, что переход прямо к кодированию приведет к тому, что мы называем «хакерским» кодированием, уничижительным термином, используемым для описания кода, написанного без намерения или контекста. Кодирование с помощью хакерства и косой черты часто не соответствует требованиям и не справляется с крайними случаями, и приводит к созданию программ, которые трудно понять, поддерживать и масштабировать. Дисциплинированный подход, такой как PEDAC, помогает выявлять и избегать ловушек, с которыми вы можете столкнуться, если не пишете код с намерением.

Распространенные ошибки при использовании "взлома" и "косой черты" или кодирования без намерения:

  • Пропущенные требования
  • Непредвиденные крайние случаи
  • Трудно понять код
  • Код, который сложно поддерживать

Пример проблемы

Давайте поработаем с PEDAC на примере.

Suppose you have an arbitrary natural number (the target) and a set of one or more additional natural numbers (the factors). Write a program that computes the sum of all numbers from 1 up to the target number that are also multiples of one of the factors. 
For instance, if the target is 20, and the factors are 3 and 5, that gives us the list of multiples 3, 5, 6, 9, 10, 12, 15, 18. The sum of these multiples is 78.
If no factors are given, use 3 and 5 as the default factors.

Понять проблему

Заманчиво сразу перейти к REPL и быстро набрать код. Сопротивляйтесь этому искушению. Первым критическим шагом PEDAC является переваривание проблемы, чтобы получить целостное и всестороннее понимание того, что задает проблема в целом. Не торопись. Внимательно прочтите описание проблемы; не пропустите ни одной детали. В большинстве формулировок проблем нет лишних слов, поэтому не читайте их, как журнальную статью. Каждое слово и каждая деталь имеет значение. Ваш мозг имеет тенденцию заполнять пробелы, если вы пропускаете какие-либо детали, но он может делать это неправильно, о чем свидетельствует следующее:

Давайте сначала определим входы и выходы нашей проблемы. Читая формулировку задачи, мы видим, что у нас есть два входа и один выход:

inputs:
  target number
  the set of factors
output:
  sum of multiples

Если вы не знакомы с предметной областью, в проблему также вводится тонкая неявная концепция: multiples.

Чтобы сделать требования / термины явными, мы должны понимать термины в их применении к проблемной области. Это не только слова, которые вы незнакомы, но и слова, которые имеют несколько значений. Например, «баланс» может означать разные вещи в зависимости от того, используем ли мы его в бухгалтерском учете или в контексте цепочки поставок.

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

target number: 
20
multiples of 3: 
3, 6, 9, 12, 15, 18 (all have no remainder when divided by 3)
multiples of 5: 
5, 10, 15 (all have no remainder when divided by 5)

Неявные требования

Эта постановка задачи также содержит несколько правил, которые мы должны помнить:

  1. Суммируемые множители должны быть уникальными. Число 15 представлено как кратное 3 и 5, но мы добавляем его только один раз при вычислении суммы(3 + 5 + 6 + 9 + 10 + 12 + 15 + 18 = 78). Обратите внимание, что мы узнаем это неявно из примера: требование уникальности не указано явно.
  2. Целевое значение является пределом, но оно не считается кратным. В этом примере цель 20 не включается в сумму, даже если она кратна 5. Как и в случае с первым правилом, это требование неявно.
  3. Все числа являются натуральными числами: они представляют собой набор целых чисел, больших или равных 0 или 1 (см. Это определение с сайта mathworld.wolfram.com). Поскольку добавление 0 к любому числу не меняет его, не имеет значения, какое определение мы используем. Для простоты предположим, что натуральные числа начинаются с 1.

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

Уточняющие вопросы

  1. Каковы возможные значения целевого числа? Разрешены отрицательные числа? Любое натуральное число больше 0. Всегда будет целевое значение.
  2. Как коэффициенты будут предоставлены программе? В виде массива.
  3. Что произойдет, если в качестве фактора указан только один номер? Должна ли программа предполагать, что нужен второй коэффициент, равный 3 или 5? Нет. По умолчанию 3 и 5 только, если коэффициенты не указаны.

Согласуются ли эти ответы с какими-либо предположениями, которые вы собирались сделать? Может быть; может быть нет. Вот в чем смысл задавать вопросы. Убедитесь, что вы решаете правильную проблему, получив разъяснения, даже если вы думаете, что понимаете проблему.

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

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

Вот простая ментальная модель этой проблемы:

Determine a list of all multiples of a set of factors up to a target value, then filter the list of multiples to the unique values. Finally, compute and return the sum of the unique multiples.

Вот еще одна ментальная модель:

Incrementally build a list of numbers that are multiples of a set of one or more factors. Add a multiple to the list only if it is not yet on the list. Finally, compute and return the sum of the numbers on the list.

Обратите внимание, что в этом примере мы придумали две ментальные модели. Мы сделали это, чтобы подчеркнуть, что есть несколько точек зрения на создание надежной ментальной модели; Как правило, вам не нужно придумывать более одной модели, если она полностью и точно соответствует требованиям.

Примеры / Тестовые примеры

Это было много, но это был только первый шаг - буква «П» в PEDAC. Теперь мы готовы перейти к букве «E», что означает «Примеры или тестовые примеры». На этом этапе наша цель - привести примеры, подтверждающие наше понимание проблемы и подтверждающие, что мы работаем в правильном направлении. Подтверждение обычно исходит от человека или документации процесса: мы можем попросить человека подтвердить вывод при вводе, или мы можем проследить процесс, чтобы проверить вывод при вводе.

Возвращаясь к примеру проблемы, давайте приведем несколько примеров. Наши примеры будут в форме тестов, которые покажут ожидаемые результаты при определенных входных данных:

Обратите внимание, что мы взяли наши примеры из наших правил. Обычно это отличное место для поиска тестовых примеров.

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

В этом примере проблемы есть один важный крайний случай: что произойдет, если последнее число перед целевым значением кратно одному или нескольким факторам?

В каждом из приведенных выше тестовых случаев последнее число, добавленное к сумме, равно 18 или 15. Это оставляет 19 (последнее проверенное значение) из суммы, что является правильным решением. Предположим, однако, что 19 должно быть включено в сумму, что должно быть, если19 является одним из факторов. Поскольку 19 - это последнее возможное число для проверки (при целевом значении 20), оно находится на «краю» диапазона суммируемых значений. Чтобы быть уверенным, что мы включаем 19 в сумму, нам нужно предоставить тестовый пример, который ее обрабатывает.

Структура данных

Теперь мы готовы перейти к третьему этапу подхода PEDAC - букве «D». Когда наши тестовые примеры готовы, следующее, что нужно сделать, - это определить, с какими структурами данных мы будем работать, чтобы преобразовать входные данные в выходные. Основные соображения здесь - это предполагаемый язык программирования и наша ментальная модель.

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

Следует отметить, что структура данных будет влиять на ваш алгоритм. По этой причине мы обычно объединяем этапы «Структура данных» и «Алгоритм».

Алгоритм

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

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

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

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

Давайте попробуем это на первом примере из нашей первой ментальной модели:

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

Код

Это последний шаг в PEDAC - буква «C», что означает «код с намерением». Этот этап посвящен реализации решения на выбранном вами языке. Основное преимущество инвестирования времени в предыдущие шаги (PEDA) состоит в том, что реализация сводится к простому переводу алгоритма в синтаксис языка программирования.

Не беспокойтесь, если после выполнения всех вышеперечисленных шагов вам все равно придется вернуться к своему алгоритму. Это может случаться и будет происходить часто. В конце концов, вы человек и, возможно, что-то упустили. Однако PEDAC стремится минимизировать эти ошибки, чтобы вы не пропустили основные требования, и даже если вы возвращаетесь к предыдущим шагам, в основном это делается для точной настройки подхода.

Вот Ruby-реализация алгоритма, который мы разработали для первой ментальной модели:

Вот реализация JavaScript с использованием алгоритма, который мы разработали для второй ментальной модели:

Для обеих ментальных моделей подойдет Ruby или JavaScript. Однако первая модель немного лучше подходит для Ruby, поскольку в Ruby есть метод для возврата уникальных значений в массиве; JavaScript этого не делает.

Резюме

Мы надеемся, что эта демонстрация процесса PEDAC послужила аргументом в пользу его использования. Несмотря на то, что это было многословным, чтобы подробно описать каждый шаг, такое многословие не всегда необходимо для каждой проблемы. Вам также не нужно строго соблюдать последовательность PEDA. Ключевые идеи заключаются в том, чтобы обработать проблему так, чтобы вы придумали алгоритм, а затем кодировали с намерением. Поначалу это может показаться трудоемким, но как только вы привыкнете к этому, вы будете удивлены, насколько быстро и эффективно PEDAC помогает вам решать проблемы.

часто задаваемые вопросы

  1. Какие проблемы я могу решить с помощью PEDAC? PEDAC не подходит для многих абстрактных операций, таких как «проектирование пользовательского интерфейса». Он хорошо работает с проблемами процедурного кодирования, поскольку приводит вас к серии шагов / инструкций, которым вы можете следовать для получения детерминированного результата.
  2. Когда мне следует использовать PEDAC? Стоит ли мне использовать его, даже если проблема небольшая? Если у вас нет предыдущего опыта использования формального процесса решения проблем, то да, используйте его и для простых задач. Привыкайте к решению проблем, следуя инструкциям PEDAC. Как только вы привыкнете к нему, он станет частью вашей «мышечной памяти», и вы сможете более естественно использовать его для решения более сложных задач, где оно вам действительно понадобится. Если ваше первое знакомство с PEDAC связано с самыми сложными проблемами, вам будет трудно научиться использовать этот процесс.
  3. Могу ли я использовать PEDAC для разработки приложений, а не только для решения проблем с кодированием? Да, но перед его использованием вам нужно будет выполнить некоторые предварительные работы. Чтобы эффективно использовать PEDAC, разбейте приложение на более мелкие требования. Скорее всего, вам придется сравнить с предыдущими проблемами кодирования, которые вы решили, если он достаточно мал для PEDAC. PEDAC может быть применен к любой проблеме, имеющей определенные входные и однозначные выходы, поэтому вам придется разбивать свое приложение до тех пор, пока у вас не появятся конкретные и однозначные требования.