[БЕЗ_ЗВУКА] Весь код, который мы до этого писали в нашем курсе, мы всегда помещали в один файл. При этом неважно, насколько этот код был сложный, как много в нем было функций, как много классов — он всегда у нас находился в одном файле. Ну и естественно, по мере роста кодовой базы, по мере роста проекта нахождение всего кода в одном файле начинает приводить к определенным проблемам. Во-первых, для использования одного и того же кода в разных нескольких программах нам приходится его копировать. Ну потому что у нас весь код в одном единственном файле, и если мы хотим в другое место этот код переместить, нам приходится его копировать и вставлять в другое место. Ну а это приводит к дублированию кода, и вы не хуже меня знаете, насколько это плохо. Дальше, даже если у нас весь код в одном файле, то даже самое маленькое изменение кода программы приводит к ее полной перекомпиляции. Я думаю, вы уже заметили, что даже на наших маленьких программах компиляция программ на C++ занимает какое-то заметное время — 2–3 секунды, может быть 5 секунд. Что уже говорить о больших проектах, которые занимают десятки, сотни тысяч строк кода. Их компиляция занимает значительное, заметное время. И мы, естественно, не очень-то хотим ждать по несколько десятков секунд, даже иногда и минут, после каждого изменения программы, даже если мы там лишний пробел удалили. Если у нас весь код лежит в одном файле, то у компилятора нет выбора. Он видит, что файл изменился, и он должен этот файл полностью перекомпилировать. И поэтому если весь код в одном файле, то любое изменение программы приводит к полной перекомпиляции программы. Наконец, как говорит автор языка C++ Бьерн Страуструп в своей книге «Язык программирования C++»: «Разбиение программы на модули помогает подчеркнуть ее логическую структуру и облегчает понимание». И здесь действует тот же принцип, что и при разбиении кода на функции. Когда вы выделяете код в функцию, вы даете этой функции какое-то понятное название, которое позволяет проще понять, что этот код делает. С разбиением программы на файлы — то же самое. Вы берете код, помещаете его в какой-то файл и даете этому файлу какое-то осмысленное имя. И в дальнейшем по этому имени вам проще понять, какой именно код лежит в этом файле, и проще искать те функции или классы, которые вам нужны. А теперь давайте вспомним, что в предыдущем блоке видео мы с вами разработали юнит-тест фреймворк, и этот фреймворк мы применили для тестирования решения задачи «Синонимы». Давайте переключимся в Eclipse, и как раз у меня здесь этот наш фреймворк и решение задачи «Синонимы» представлено. И давайте внимательно посмотрим, что же у нас в итоге в файле с нашей программой есть. На самом деле у нас есть логически не связанные друг с другом вещи. Ну вот смотрите: вот у нас есть функции (3 функции) и синоним для типа, которые относятся к решению нашей задачи. Это вот такой отдельный логический блок нашей программы. Дальше, за ними идут шаблонные операторы вывода, ассерты (вот два — AssertEqual и функция Assert) и класс TestRunner, который управляет запуском юнит-тестов. По сути, это и есть наш юнит-тест фреймворк. И он логически не зависит от функции, которую мы используем в решении нашей задачи. Дальше у нас идут юнит-тесты. Юнит-тесты объединяют в себе юнит-тест фреймворк и тестируемые функции, но сами по себе это тоже логически отдельный компонент программы. Вот наши юнит-тесты. Вот их три. Затем у нас есть функция TestAll, которая объединяет запуск всех юнит-тестов. И наконец, функция main, в которой мы запускаем наши тесты. А дальше у нас есть код, который, собственно, решает нашу задачу. Итак, у нас в программе есть 4 логически обособленных компонента: это функции решения нашей задачи, это юнит-тест фреймворк, это юнит-тесты и, собственно, решение нашей задачи. И логичным было бы отделить эти части друг от друга, поместив их в отдельные файлы. Вот давайте мы это и сделаем, заодно и узнаем, как это делается в Eclipse. Итак, что я делаю? Я уменьшил редактор. Рядом с консолью я открыл у себя вкладку, которая называется C/C++ Projects. Ее можно открыть, зайдя в Window Show View. Вот она. И здесь есть проект Coursera, в котором я и редактирую код. Нажмем на нем правой кнопкой мыши, выберем New и вот здесь выберем пункт Header File. Дальше введем имя файла — test_runner.h Это имя файла, который мы добавляем в наш проект. И по имени этого файла, я думаю, вы догадались, что первым делом мы в отдельный файл вынесем наш тестовый фреймворк. Вот у нас создался файл. Он совершенно пустой. И мы идем в редактор и выделяем все, что относится к тестовому фреймворку, а это операторы вывода, ассерты и TestRunner. Вырезаем их из основного файла и переносим в test_runner.h. Если мы теперь скомпилируем нашу программу, то она не скомпилируется, потому что как минимум мы не знаем, что такое ассерт. Почему мы не знаем, что такое ассерт? Потому что мы вынесли код в отдельный файл, а основному файлу мы никак не рассказали об этом коде. Поэтому мы должны написать include "test_runner.h" Компилируем программу снова, и она компилируется. Можем даже ее запустить и убедиться, что вот у нас все юнит-тесты отработали. Таким образом, мы осуществили первый шаг декомпозиции программы на файлы, мы вынесли тестовый фреймворк в отдельный файл. Продолжим выполнять декомпозицию. И снова добавим в наш проект еще один файл. Назовем его synonyms.h Также он у нас создался. И вынесем в него функции, которые мы покрываем юнит-тестами, и которые, собственно, участвуют в решении нашей задачи. Отлично. Точно так же добавим этот include. Проверим собираемость нашей программы. Отлично она компилируется. Ну и последний шаг — вынесем юнит-тесты также в отдельный файл. Назовем его tests.h Создадим его и вынесем все, что относится к тестам, в отдельный файл. И добавим include. Скомпилируем наши программу. Она компилируется, отлично. Запустим. Мы видим, что тесты выполняются успешно, и дальше мы можем даже вводить запросы, мы можем добавить два синонима, сделать запрос на два слова, и мы видим, что всё — наша программа работает. Таким образом, в этом видео мы с вами смогли разбить нашу исходную программу на 4 файла, выделив по одному файлу для каждого логического блока и поместив в этот файл тот код, который туда логически должен попасть. И кажется, у нас все хорошо. Но на самом деле в этом коде, который у нас получился, и в той организации проекта, которая у нас получилась, достаточно много проблем. И мы посмотрим, что это за проблемы и как их нужно побороть, мы посмотрим в следующем видео.