Урок №25. Разработка ваших первых программ

  Юрий  | 

    | 

  Обновл. 16 Мар 2019  | 

 14277

 ǀ   18 

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

Во многих отношениях, программирование — это как архитектура. Что произойдёт, если вы попытаетесь построить дом без соблюдения архитектурного плана? Дом может вы и сумеете построить, но какой он будет: кривые стены, протекающая крыша и т.д. Аналогично, если вы начнёте программировать что-нибудь серьёзное перед тем, как составите план, то очень скоро обнаружите, что ваш код имеет очень много проблем, на решение которых вы потратите гораздо больше времени/усилий/нервов, нежели на изначальное составление хорошего плана.

Шаг №1: Определите проблему

Первое, что вам нужно сделать — определить проблему, которую решит ваша программа. В идеале, вы должны сформулировать это одним или двумя предложениями. Например:

   Я хочу написать программу-справочник для удобного хранения и редактирования всех телефонных номеров и звонков.

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

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

Хотя этот шаг кажется очевидным, но он также очень важен. Самое худшее, что вы можете сделать — это написать программу, которая делает не то, что вам нужно!

Шаг №2: Определите свой инструментарий, цели и план бэкапа


Для опытных программистов на этом этапе будет ещё немало дополнительных пунктов:

   Какая ваша целевая аудитория и какие у неё потребности?

   На какой архитектуре/ОС ваша программа будет работать?

   Какой инструментарий вы будете использовать?

   Будете ли вы разрабатывать программу в одиночку или в составе команды?

   Анализ требований.

   Определение стратегий тестирования/обратной связи/релиза.

   Создание плана бэкапа в случае неожиданных проблем.

Новички, как правило, большим количеством вопросов не задаются: «Пишу программу для собственного использования, в одиночку, на своей операционной системе, с помощью своей IDE, пользоваться этой программой буду только я». Всё просто.

Если же вы будете работать над чем-нибудь посерьёзнее, то стоит ещё подумать над планом бэкапа вашей программы/проекта. Это не просто скопировать код в другую папку ноутбука (хотя это уже лучше, чем ничего). Если ваша ОС «сломается», то вы потеряете все данные. Хорошая стратегия резервного копирования включает в себя создание копии вашего кода вне вашей операционной системы, например:

   Отправить самому себе E-mail с кодом (прикрепить как файл).

   Скопировать в Dropbox или в любое другое облако.

   Перенести на внешнее запоминающее устройство (например, на портативный жёсткий диск).

   Скопировать на другой компьютер в локальной сети.

   Воспользоваться системами контроля версий (например: GitHub, GitLab или Bitbucket).

Шаг №3: Деление проблемы на части

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

Рассмотрим это на примере. Допустим, нам нужно написать доклад о картошке. Наша иерархия задач в настоящее время выглядит следующим образом:

   Написать доклад о картошке

Это довольно большая задача, давайте разделим её на подзадачи:

   Написать доклад о картошке

   Поиск информации о картошке

   Создание плана

   Заполнение каждого пункта плана подробной информацией

 Заключение

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

   Написать доклад о картошке

   Поиск информации о картошке

   Сходить в библиотеку за книжками о картошке

   Поискать информацию в Интернете

   Делать заметки на соответствующие разделы из справочного материала

   Создание плана

   Информация о выращивании

   Информация об обработке

   Информация о добавках

   Заполнение каждого пункта плана подробной информацией

   Заключение

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

Есть ещё один способ создания иерархии — от малого к большому. Рассмотрим пример:

Большинство из нас вынуждены ходить на работу (школу/университет) в будние дни. Предположим, что нам нужно решить проблему «от постели к работе». Если бы вас спросили, что вы делаете перед тем, как добраться на работу, вы бы ответили примерно следующее:

   Выбрать одежду

   Одеться

   Позавтракать

   Ехать на работу

   Почистить зубы

   Встать с постели

   Приготовить завтрак

   Принять душ

Используя метод от малого к большому, мы можем сгруппировать задания и создать иерархию:

   От постели к работе

   Спальня

   Встать с постели

   Выбрать одежду

   Одеться

   Ванная

   Принять душ

   Почистить зубы

   Завтрак

   Сделать завтрак

   Позавтракать

   Транспорт

   Ехать на работу

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

Шаг №4: Определение последовательности событий


Теперь, когда ваша программа имеет структуру, пришло время ответить на вопрос: «А как же связать все эти пункты вместе?». Первый шаг заключается в определении последовательности событий. Например, когда вы просыпаетесь утром, в какой последовательности вы выполняете дела выше? Скорее всего, в следующей:

   Встать с постели

   Выбрать одежду

   Принять душ

   Одеться

   Приготовить завтрак

   Позавтракать

   Почистить зубы

   Ехать на работу

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

   Получить первое значение от пользователя

   Получить математическую операцию от пользователя

   Получить второе значение от пользователя

   Вычислить результат

   Вывести результат

Этот список определяет содержимое функции main():

Или, в случае с калькулятором:

Шаг №5: Определение данных ввода/вывода на каждом этапе

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

Например, первая функция из примера выше — getUserInput() — довольно проста. Мы собираемся получить число от пользователя и вернуть его обратно в caller. Таким образом, прототип функции будет выглядеть следующим образом:

В примере с калькулятором, функции calculateResult() требуется 3 ввода данных: два числа и 1 математический оператор. При вызове calculateResult() у нас уже должны быть 3 фрагмента данных, которые мы будем использовать в качестве параметров функции. calculateResult() вычисляет значение результата, но не выводит его. Следовательно, нам необходимо вернуть этот результат в качестве возвращаемого значения обратно в caller, чтобы другие функции также имели возможность его использовать.

Учитывая это, прототип функции становится следующим:

Шаг №6: Детали


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

Например:

Шаг №7: Соединение и перемещение данных ввода/вывода в программе

И, наконец, последний шаг — соединение данных ввода/вывода. Например, вы можете отправить выходные данные функции calculateResult() во входные данные функции printResult(), чтобы вторая функция могла вывести результат. Чаще всего в таких случаях используются промежуточные переменные для временного хранения результата и его перемещения между функциями. Например:

Согласитесь, вариант выше читабельнее варианта без использования временных переменных (см. ниже):

Рассмотрим готовую версию программы-калькулятора, её структуру и перемещение данных:

Здесь есть несколько концепций, которые мы ещё не рассматривали: условное ветвление с операторами if и использование оператора равенства == для сравнения двух элементов. Не беспокойтесь, если вы это не понимаете — мы всё детально рассмотрим в следующих уроках.

Советы

Пускай ваши первые программы будут простыми. Очень часто новички ставят слишком высокие планки для своих первых более-менее серьёзных программ. Например, «Я хочу написать игру с графикой, звуком, монстрами, подземельями и городом, в котором можно будет продавать найденные вещи». Если вы попытаетесь написать что-нибудь подобное в начале вашего пути в программировании, то очень скоро у вас пропадёт любое желание программировать. Вместо этого, пускай ваши первые цели/задания/программы будут попроще. Например, «Я хочу написать программу, которая отображала бы 2D поле на экране».

Добавляйте новый функционал со временем. Как только вы написали простенькую программу, которая работает (даже без сбоев), то только тогда можно будет добавлять новые возможности. Например, когда вы можете отображать 2D поле на экране — добавьте персонажа, который сможет ходить по этому полю. После того, как вы уже сможете ходить — добавьте стены, которые будут препятствовать вашему движению. После того, как у вас будут стены — постройте из них город. После того, как у вас будет город — добавьте персонажей-продавцов. При таком подходе на вас не наваливается всё сразу и вы знаете с чего начинать, что делать дальше, в какой последовательности и т.д.

Фокусируйтесь только на одном задании в определённый промежуток времени. Не пытайтесь сделать всё и сразу, не распыляйтесь на несколько задач одновременно. Сосредоточьтесь на одном. Лучше иметь одно выполненное задание и пять невыполненных, нежели шесть частично выполненных заданий. Если вы рассеиваете своё внимание в нескольких направлениях, то и ошибок будет соответственно.

Тестируйте каждую новую часть кода. Начинающие программисты часто пишут программу за один присест. Затем, при компиляции проекта, получают сотни ошибок. Поэтому, при написании определённой части кода — сразу компилируйте и тестируйте её. Если ваш код не будет работать, то вы будете знать, где находится проблема, и исправить её будет намного легче. Как только вы убедились, что ваш код рабочий — переходите к написанию следующей части, а затем repeat. Тестирование может занять больше времени, но, в конечном итоге, ваш код будет работать так, как вам нужно.

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

Оценить статью:

Звёзд: 1Звёзд: 2Звёзд: 3Звёзд: 4Звёзд: 5 (240 оценок, среднее: 4,99 из 5)
Загрузка...

Комментариев: 18

  1. Аватар Михайло:

    Но как в програме калькулятор одние функции знают о переменних с других функций у них же локальная область видимости.

    1. Аватар Cerberus:

      Функции знают ровно то, что им передано в качестве аргументов. Где-то этот принцип нарушается, на Ваш взгляд?

  2. Аватар Денис:

    Я немного иначе, по простому сделал, может и не правильно, но работает. Из следующих уроков ничего нет, только базовые знания этого курса:) Спасибо за доходчивую статью:)

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

  3. Аватар Вячеслав:

    вот посмотрите, что скажете?

    1. Аватар Alexey:

  4. Аватар Вячеслав:

    у меня проблем нет с калькулятором все работает как швейцарские часы

    1. Аватар ThatSameGuy:

      Прямо как часы ?
      i.imgur.com/5erlMgw.png
      (Фикситься очевидно превращением a и b в float)

  5. Аватар Виктор:

    Здравствуйте. При написании калькулятора я решил подключить кириллицу. Прописал так как вы писали. Можете объяснить что означают эти строки:

    И, еще я чет не могу догнать когда нужно использовать int, а когда void. Можете как-то популярнее мне объяснить? И, посмотрите на мои комментарии строк, правильно ли я все понимаю. Заранее спасибо за ответ.

    1. Аватар Константин:

      Виктор, каждое второе if выбросить, а взамен блок:

      и тип int поставь перед переменной result, т.е. д.б.

      а вообще и так всё работает, и понятие есть А 1251 это, видимо, какой-то параметр, который включает кирилицу во встроенных функциях ввода и вывода в — , на — консоль.

    2. Аватар Константин:

      Даже не так: 1251 — что-то радикальнее, чем просто ввод-вывод кирилицы на экран, делает — меняет кодировку проекта (хотя деталей этого я не знаю)

  6. Аватар Наиль:

    Написал примерно такой же калькулятор.первое число принимается,операция принимается,второе число принимается,и дальше ничего ответ не выдаётся что делать?

  7. Аватар Дима:

    Супер) Все как в жизни

  8. Аватар painkiller:

    Хорошая статья. Интуитивно со всем согласен.
    Было некое уныние от непонимания концепций заголовочных файлов и header guards, но, к счастью, преодолел себя.

    1. Юрий Юрий:

      Спасибо, главное — не останавливаться и продолжать дальше.

  9. Аватар Семён:

    Спасибо , огромное !
    Конечно , кое что не понятно , НО пока . С таким объяснением , а точнее перевод , понять не будет сложно , всё постепенно !

    1. Юрий Юрий:

      Пожалуйста 🙂

  10. Аватар Иван:

    Красава, сразу видно что сам наступал на грабли и решил нас предостеречь, от лишних хлопот. мало того что умеешь объяснить, так ещё и убедить! Не возникает желание зделать принципиально не так! Спасибо автор.

    1. Юрий Юрий:

      Автор не я, но со всем этим согласен 🙂

Добавить комментарий

Ваш E-mail не будет опубликован. Обязательные поля помечены *