Предисловие к курсу
1.1 История создания
Имея долгий опыт совместной разработки и сопровождения программ, постоянно сталкиваюсь с одними и теми же проблемами в методологии разработки. Несколько лет назад решил задачу по преодолению указанных проблем для себя и для отдельно взятого предприятия. Метод прост – систематическое обучение и контроль усвоения материала.
Со временем понял, что проблема имеет большие чем я ожидал масштабы и постоянно усугубляется. Размышления над данным явлением вылились в настоящую исследовательскую работу, результаты которой, я не планирую публиковать в чистом виде, так как это послужит лишь для удовлетворения академического интереса небольшой части коллег. Полученные материалы я решил использовать для переработки своего учебного курса и последующей его публикации для широкой аудитории.
В этой лекции будут рассмотрены основные принципы определения хорошей программы, проблемные зоны качества и зоны его роста.
Каждая последующая лекция будет посвящена определенной теме. Структура курса построена по принципу возрастания доли практики. Если первые лекции посвящены теоретическому анализу, кристаллизации большого массива практического опыта в краткие формулировки, то последующие будут посвящены решению конкретных проблем с использованием предложенной методологии. Таким образом курс можно условно разделить на теоретическую и практическую часть. Был большой соблазн начать именно с практической части, как наиболее интересной и доступной, но это бы противоречило базовым концепциям, о первичности понимания принципов, над знанием отдельных фактов. Нельзя слепо копировать даже успешный опыт. Ведь любой практический опыт ценен лишь в конкретном контексте заданного момента времени, тогда как понимание общих принципов позволит в разных контекстах применять правильные решения… в том числе путем копирования :-)
1.2 Цели курса
- Повысить общую грамотность разработчиков
- Улучшить среднее качество программ.
1.3 Дополнение к редакции 2021 года
Из-за принципиальных и сложно устранимых различий, полностью переложить курс очных лекций и практических занятий не удалось, поэтом формат данного курса приведен к конспекту лекций.
2 Об истоках
Современные средства разработки, многократно умножили возможности программистов. Даже «деревянный» конфигуратор 1с, это отличный многофункциональный инструментарий по сравнению с примитивным текстовым редактором. Поэтому «то, о чем всё время говорили большевики» наконец свершилось - даже домохозяйка может писать код. Нет я ничего не имею против «домохозяек». Даже за. Даже на проекте (это спойлер).
Но это стало вызывать проблемы. Проблемы стандартные для любой технологической революции – отсутствие достаточного количества обученных кадров, носителей производственной культуры. Поэтому общие методики их преодоления позаимствованы у предков – наставничество, систематическое обучение, контроль качества. Вообще, анализируя проблемы современности, мне постоянно приходилось обращаться в прошлое и находить там или истоки проблем, или их предыдущие инкарнации с набором правильных, неправильных и приемлемых решений. Что не удивительно, ведь природа человека меняется не так быстро, а законы физики в обозримом интервале времени вообще не меняются, поэтому в сходных ситуациях люди будут вести себя примерно одинаково независимо от эпохи и уровня технологий.
В те времена, когда компьютеры были большие, а программистов было мало, написание программ считалось чуть ли не магией, а о программистах в экстренных ситуациях, вручную вводивших машинные коды напрямую в процессор, ходили легенды, и они вполне могли быть реальностью. Программы были маленькими, за пределы НИИ и заводов не выходили, операций было немного и долго работая с тем или иным процессором можно было выучить его инструкции наизусть. Но со стороны, осмысленный ввод двоичных данных выглядел эффектно. Наверное, с тех пор и сложились стереотипы о программистах, кои не без смеха можно было наблюдать в таких характерных художественных фильмах как Хакеры и Матрица.
Разумеется, подобные программисты есть и сейчас, может быть, они также ходят в растянутых свитерах и потертых джинсах, но они прочно заняли свою нишу «программистов микроконтроллеров» и подавляющее большинство населения даже не догадывается об их существовании. Их слава и сопутствующие стереотипы достались в наследство новому поколению высокоуровневых (прикладных) программистов. Но прикладник от железячника отличается примерно так же, как циркуль от паяльника. Если железячник действительно общается с компьютером на его языке (сейчас уже не совсем так, но не сомневаюсь, что могут), то прикладник пишет на вполне себе человеческом языке. Бедном на выразительные средства, очень примитивном и ограниченном, но человеческом языке с приятной и знакомой структурой.
Новички, приходя в профессию с радостью узнают, что «код писать просто», и подчиняясь ложному стереотипу о магичности работы программиста, начинают воспринимать это как профессиональный антураж, подобный аналогичному антуражу, обставляющему работу фокусника-иллюзиониста. Таким образом сакрализация процесса написания кода разрушает нашу современную работу. Ведь это не работа мага или фокусника. Конечно, процесс решения изобретательских задач, внезапные озарения имеют своё магическое очарование, но творческие способности присущи всем людям, и не являются чем-то особенным. И получается, что если отбросить творческий элемент как общий знаменатель, то получится, что написание кода сродни написанию школьного сочинения с требованиями как к содержанию, так и к оформлению.
Отсюда вполне очевидный вывод, что написание прикладных программ должно подчиняться не только математической логике, но и правилам того языка, на котором пишет программист. Повествование должно быть ясным, основная мысль выражена четко, в структуре присутствует завязка, кульминация и эпилог. Таким образом текст, соответствующий школьным требованиям, будет понятен любому человеку, умеющему читать.
3 Базовые принципы
Для начала, определю концепции, которыми я руководствуюсь в работе и которые послужили основой для данного учебного материала. Обязательное изложение концепций — это тоже одна из концепций которой я следую - важнее хорошо и глубоко понимать принципы событий и явлений, чем знать максимально возможное число отдельных «правильных» фактов.
3.1 Помни о реальном мире.
Сама по себе программа является абстрактной надстройкой на данные, оборудование и процессы реального мира. Всегда нужно помнить, что обрабатываться будут реальные данные, на реальном оборудовании, в условиях реального процесса человеческой деятельности.
3.2 Не шифруй, а пиши.
Программа – это книга, которую программист пишет для другого программиста. Идеал - комментарии как эпиграф к главе. Нужны только для отдельных функций или разделов, потому что сам код легко читается и не нуждается в отдельных пояснениях.
3.3 Не поклоняйся фетишу.
Проблема сакрализации труда разработчика, как показывает многолетняя практика одна из самых серьезных. Выделяю три фактора лежащие в основе проблемы.
1. Это не специфическая, а общечеловеческая проблема и причины коренятся в особенностях человеческого мышления, поэтому эффективных мер борьбы фактически не существует. Даже образованный человек, понимающий природу культового сознания, всё равно будет подвержен отдельным его элементам, в силу своей человеческой природы.
2. Проблема усугубляется тем, что разработчики, не являющиеся адептами «культов», избирают их предметом шуток, поэтому сложно отличить культиста, от обычного программиста, и неверующий вполне может распространять культовое мироощущение.
3. Многие адепты вовсе не считают себя таковыми, в их сознании предмет фетиша воспринимается как органичная часть мира, так же как в сознании примитивных людей шаманский обряд являлся непосредственной причиной дождя и лучшим средством от колотья в боку. Итак, перечислим основные профессиональные культы:
«Карго-культ» инструментов разработчика
Ошибка в позиционировании первичности инструмента, над фундаментальными знаниями о предмете. Отсюда споры «в 1с нет ООП», нездоровый ажиотаж вокруг расширений и.т.д. Природа этого явления, очень древняя, возможно одна из самых древних, уходящая корнями ко времени первых орудий труда. Использование орудий труда являлось важнейшим эволюционным фактором в истории человека, и примитивные попытки осознания важности этого события приводили к подмене причины и следствия. Фактически, деятельность человека усложнилась и ему потребовались дополнительные инструменты, которые он изготовил или освоил если речь идет о навыках. Но для обывателя это имело очевидный сакральный смысл. Ведь гораздо проще представить, что заостренный камень ценен сам по себе и является даром богов, чем представить тот колоссальный объем умственной работы, который сопутствовал развитию трудовой деятельности и созданию орудий труда.
Культ «Тайного знания».
Мистификация процесса разработки и работы программ. Представление процесса разработки неким таинством, обрядом. Проблема по генезису аналогичная предыдущему пункту – банальная подмена, где «обряд» или иной фетиш признаётся первичным, по отношению к мыслительной деятельности и результатам реального труда. При этом, как и любая деятельность, требующая длительного сосредоточения внимания, программирование требует предварительной подготовки, втягивания в процесс, что вполне может быть обставлено как магический обряд.
Культы «Святого писания» и «Знания Древних».
Трепетное отношение к ранее написанному коду, как к непреложной истине и боязнь не только вмешательства, но и простого исследования. К старому правилу «работает – не трогай» относится косвенно, но тайные культисты часто используют его для маскировки своей религиозности.
3.4 Контролируй нетерпимость ко «злу».
Нетерпимость ко злу естественное свойство человека. Но так, как и сам человек и наш мир в целом весьма несовершенны, то нетерпимость нужно контролировать и направлять. При этом полный отказ от нетерпимости считаю ошибочным и вредным. Если существует проблема, шерховатость, которую быстро исправить нельзя, а само «зло» маленькое и не проявляет себя, то не нужно тратить время. Лучше запишите свои соображения в специальное место. Если в будущем вам или вашим коллегам придется снова столкнуться с «обителью зла», то она будет уже подписана и возможно даже каталогизирована, что позволит сократить затраты на идентификацию и поиск проблемы. Если зло большое, то об этом нужно в первую очередь уведомить руководство, для оперативной корректировки планов.
Для закрепления приведу пример из жизни, где подобный подход является разумным и обоснованным. Дано: вы командир воинского подразделения и ведете наступление. В ходе продвижения, было обнаружено не выявленное ранее минное заграждение. Ваши передовые подразделения смогли оперативно оценить его протяженность, проделать проход и обеспечить продолжение движения основной группы, следующей жесткому графику наступления. На подходах к минному полю были установлены предупреждающие таблички, безопасный проход был размечен. Имея информацию о проблеме, специально назначенные люди рано или поздно проведут полное разминирование, но главное – никто на этом поле уже не подорвется, а подразделение, обнаружившее проблему, вышло к намеченным пунктам в соответствии с графиком.
3.5 Холодная и горячая голова.
Для понимания этого принципа необходимо предварительно разделить работу программиста на два типа:
- Изложение своих мыслей (написание кода, формальное описание мыслей)
- Творческий поиск (генерация мыслей)
Это принципиально разные виды умственной деятельности, с разными требованиями к состоянию человека.
При написании кода старайтесь всегда соблюдать трезвость сознания. Любые состояния измененного сознания как правило приводят к отвратительному качеству кода. При этом нет разницы, чем именно замутнено ваше сознание: воодушевление и азарт не менее вредны чем уныние и гнев. Написание именно кода – т.е. изложение ваших мыслей на языке программирования должно производиться на трезвую голову. В то же время творческий поиск и мозговой штурм редко бывают удачными в холодной голове. Поэтому важно научиться применять разные состояния для разного типа умственной работы.
3.6 Проверяй свою работу
Нельзя недооценивать способности человека совершать невероятно нелепые ошибки. ВСЕГДА проверяйте свою работу. Даже если вы просто переименовали переменную или поставили разметку. При этом желательно проводить трёхуровневую проверку:
- Прочтение измененных функций. Позволит проверить внутреннюю связность логики.
- Сравнение с предыдущей версией. Это позволит выявить очевидные ошибки в логике и опечатки.
- Тестирование. Это позволит выявить менее очевидные ошибки и опечатки. Если тестирование будет выполняться другим человеком или машиной, результаты будут еще лучше.
4 Определение хорошей программы
Целью курса было объявлено повышение качества программ. Но понятие «хорошая программа» очень неопределенное. Поэтому прежде, чем рассматривать методику достижения качества, необходимо определиться с тем, что такое качество, его определение и методики оценок.
4.1 Ключевые признаки хорошей программы
- Работоспособность.
Программа должна выполнять свою работу, в идеале хорошо, но минимум на достаточном для получения результатов уровне. Под выполнением работы, здесь понимается соответствие результатов работы программы ожиданиям пользователей и/или спецификации на эту программу. То есть определение работоспособности программы чисто функциональное – если программа за ожидаемое время даёт ожидаемый результат, то программа считается работоспособной.
Таких программ очень много. Думаю, что каждый без труда назовет несколько таких.
- Гибкость.
Программа должна быть готова к модификациям. Подобное требование, по логике вещей, является обязательным, но практика показывает, что программ, соответствующих данному критерию меньшинство.
- Сопровождаемость.
Программа должна быть легкой в сопровождении – легкой для понимания, обеспечивающей простой доступ к различным узлам и блокам. С этой частью определения проблемы возникают чаще. Довольно мало программ, которые имеют хорошую документацию, а также внятный и читаемый с первого раза код.
Итак, мы определили три критерия по которым можно определить хорошую программу, при этом легко заметить, что первый признак лишь косвенно зависит от остальных, тогда как второй и третий имеют сильную взаимозависимость. Но так или иначе мы имеем достаточно четкое определение хорошей программы. Следовательно, анализируя соответствие этим признакам, мы легко можем определить качество не только программы в целом, но и отдельных её компонент вплоть до функций и фрагментов кода.
Вооружившись таким простым и мощным средством познания, вы можете на досуге провести оценку сопровождаемых вами программ или их фрагментов. Метод универсальный, и позволяет хорошо структурировать и определить негативные ощущения от работы с плохими программами. Таким образом, ваш обычных гнев мы можем обратить в гнев благородный. Конечно, гнев это само по себе плохо, но нужно с чего-то начинать.
4.2 Методика оценки качества
В этом разделе мы рассмотрим общую логику оценки качества программы по трём ключевым признакам.
Работоспособность.
На первый взгляд самый простой критерий, но существуют и подводные камни. Те самые неявные связи с остальными критериями. Поэтому важным методологическим принципом определения работоспособности является не только выполнение программой своей работы в текущий момент, но и надежность программы в целом. Т.е. программа должна уметь обрабатывать исключительные ситуации внешней и внутренней среды. В качестве экстремального примера могу привести карточный домик. Он выполняет свою функцию - модель домика, хорошо выглядит. Но стоит лишь пройти мимо или неосторожно выдохнуть...
Гибкость.
Свойство не всегда очевидное и далеко не всегда нужное. Основная проблема заключается в том, что знание о необходимости этого свойства приходит внезапно. Следовательно, если нет явных требований по гибкости и модульности, то нет никакой нужды проектировать программу на все случаи жизни. Плата за универсальность, обычно берется ценой и качеством работы программы. Любая нишевая программа по определению лишена гибкости. Поэтому, чтобы исключить возможные спекуляции, определимся с необходимыми требованиями к гибкости.
Программа должна быть готовой к существенным изменениям в пределах своей сферы применения. Никто не упрекнет разработчика, за то, что его специализированная медицинская программа для гинекологической клиники не подходит для ветеринарной службы племенного завода крупного рогатого скота. Но изменение некоторых процессов или добавление смежных направлений деятельности, не должно застать разработчика врасплох. Из последних примеров вспоминается аварийных запуск с космодрома Восточный в конце 2017 года, когда была использована негибкая программа в непривычных для неё условиях и без привычного контролёра, который за ней присматривал и корректировал ошибки.
Сопровождаемость.
Предлагаю совершить мысленный эксперимент и обратиться по памяти к недавнему коду. Его можно просто прочитать или нужно расшифровывать, вооружившись лупой, блокнотом и двумя высшими образованиями? Конечно, человек умеющий читать и обладающий известной степенью усидчивости разберется в любом запутанном алгоритме, но потери времени будут неизбежны. Вспомните сколько времени обычно уходит на перечитывание программы и поиск подводных камней в запутанном и плохо структурированном коде. А ведь от того насколько быстро можно прочитать и понять текст напрямую зависит стоимость поддержки и объем (в том числе вашей) оперативной работы в ущерб проектной.
Несмотря на то, что по этому критерию отсеивается большая часть некачественных программ, у этого признака есть огромный потенциал. Это наиболее понятный и доступный всем практикующим программистам метод оценки. Исключения в моей практике встречались, но они подтверждали правило — это были случайные люди в профессии. Подавляющее же большинство разработчиков, даже производящих некачественный код, могут с различной степенью точности, но определить степень сопровождаемости программы.
При анализе важно не забывать о психологии. Легче всего оценивать чужой код – вы не знаете контекста, хода мыслей и характера другого программиста – вы видите просто код, все ошибки и огрехи в нем. Свой код анализировать намного сложнее. Для облегчения этой задачи есть несколько приёмов:
- Изначально писать так, словно вы рассказываете другому программисту, что, как и зачем вы делаете.
- Если позволяет время, делать паузы между окончанием написания кода и анализом. Как правило, код написанный вчера, воспринимается иначе чем свежеиспеченный.
Этот раздел резюмирую эпиграфом, сознательно вынесенным в эпилог: «Современные средства разработки сделали процесс написания программ понятных компьютеру простейшей и общедоступной задачей. Современный программист должен уметь писать программы понятные другому человеку».
5 Заключение
В рамках данной лекции были сформулированы базовые проблемы, а также их генезис. Были определены ключевые признаки хорошей программы и базовые принципы оценки по этим критериям. Настоятельно рекомендую перед чтением следующей лекции провести некоторую самостоятельную работу и потренироваться в оценке доступных вам программ или их фрагментов. Понимание методики оценки (не данного текста) является необходимым условием для усвоения последующего материала.
Следующая лекция: //infostart.ru/public/835693