Основы мастерства

    Боритесь со сложностью


    Как известно, мозг человека может одновременно рассматривать 7±2 элемента. Поэтому очень важно стремиться к снижению сложности ПО. Вот некоторые конкретные рекомендации:
    • Разделите систему на подсистемы на уровне архитектуры, чтобы концентрироваться в каждый конкретный момент времени на меньшей части системы.
    • Тщательно определяйте интерфейсы классов, чтобы можно было игнорировать
      внутреннее устройство классов.
    • Поддерживайте абстракцию, формируемую интерфейсом класса, чтобы не
      запоминать ненужных деталей.
    • Избегайте глобальных данных, потому что их использование значительно увеличивает процент кода, который нужно удерживать в уме в любой момент
      времени.
    • Избегайте глубоких иерархий наследования, потому что они предъявляют
      высокие требования к интеллекту.


    • Избегайте глубокой вложенности циклов и условных операторов, поскольку
      их можно заменить на более простые управляющие структуры, позволяющие
      бережнее расходовать умственные ресурсы.
    • Избегайте операторов goto, так как они вносят в программу нелинейность, за
      которой большинству людей трудно следовать.
    • Тщательное определите подход к обработке ошибок, вместо того чтобы использовать произвольную комбинацию разных методик.
    • Систематично используйте встроенный механизм исключений, поскольку он
      может стать нелинейной управляющей структурой, которую при недисциплинированном применении понять почти так же трудно, как и операторы goto.
    • Не позволяйте классам превращаться в монстров, достигающих размера целых
      программ.
    • Поддерживайте методы короткими.
    • Используйте ясные, очевидные имена переменных, чтобы не вспоминать детали вроде «xx — это индекс счета, а yy — индекс клиента или наоборот?».
    • Минимизируйте число параметров, передаваемых в метод, или, что еще важнее, передавайте только те параметры, которые нужны для поддержания абстракции, формируемой интерфейсом метода.
    • Используйте соглашения, чтобы не запоминать произвольные, несущественные различия между разными фрагментами кода.

    Анализируйте процесс разработки


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

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

    Преждевременная оптимизация — еще один изъян процесса разработки. Эффективный процесс подразумевает, что вы выполняете грубую работу в начале и тонкую
    в конце. Если бы вы были скульптором, вы придавали бы композиции общую форму
    и только потом начинали бы работать над отдельными деталями. Преждевременно выполняя оптимизацию, вы тратите время на полирование фрагментов кода,
    которые полировать не нужно. Всегда спрашивайте себя: «Делаю ли я это в правильном порядке? Что изменилось бы при изменении порядка?».

    Пишите программы в первую очередь для людей и лишь во вторую — для компьютеров



    Компьютерам все равно, насколько удобочитаем ваш код. Они вообще лучше читают двоичные команды, а не операторы высокоуровневых языков. Удобочитаемый код нужно писать для того, чтобы он был понятен людям. Читабельность
    положительно влияет на такие аспекты программы, как:
    • понятность;
    • легкость выполнения обзоров;
    • уровень ошибок;
    • удобство отладки;
    • легкость изменения;
    • время разработки — следствие всего вышеперечисленного;
    • внешнее качество — следствие всего вышеперечисленного.


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

    Программируйте с использованием языка, а не на языке


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

    Концентрируйте внимание с помощью соглашений


    Общие преимущества соглашений:
    • Соглашения избавляют программистов от необходимости снова и снова отвечать на те же вопросы и принимать все те же произвольные решения.
    • Конвенция лаконично сообщает важную информацию.
    • Соглашения защищают от известных опасностей.
    • Соглашения делают более предсказуемыми низкоуровневые задачи.
    • Соглашения могут компенсировать недостатки языков.

    Программируйте в терминах проблемной области


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

    Высокоуровневый код не должен включать подробных сведений о файлах, стеках, очередях, массивах, символах и подобных объектах, имеющих имена вроде
    i,j и k. Высокоуровневый код должен описывать решаемую проблему. Он должен
    быть наполнен описательными именами классов и вызовами методов, ясно характеризующими выполняемые действия, а не подробными сведениями о том, что файл
    открывается в режиме «только для чтения». Высокоуровневый код не должен быть
    загроможден комментариями, гласящими, что «здесь переменная i представляет
    индекс записи из файла о сотрудниках, а чуть позже она используется для индексации файла счетов клиентов».

    Это неуклюжая методика программирования. На самом высоком уровне программы
    не нужно знать, что данные о сотрудниках представлены в виде записей или хранятся в файле. Информацию, относящуюся к этому уровню детальности, надо скрыть. На самом высоком уровне вы не должны иметь понятия о том, как хранятся данные. Вы не должны читать комментарии, объясняющие роль переменной / и то, что она используется с двойной целью. Вместо этого вы должны видеть две переменные с выразительными именами, такими как employeelndex и clientlndex.

    Разделение программы на уровни абстракции


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

    Опасайтесь падающих камней


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

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

    Итерируйте, итерируйте и итерируйте


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

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

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

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

    Говорят, инженерное дело — это умение сделать за 10 центов то, что любой может сделать за доллар. Итерация на более поздних этапах — это трата двух долларов на то, что любой может сделать за один. Фред Брукс советует «планировать выбросить один вариант программы, потому что это придется сделать в любом случае». Хитрость разработки ПО в том, чтобы создавать выбрасываемые части как можно быстрее и дешевле — это и есть суть итерации на ранних этапах разработки.

    Стив Макконнелл
    Ads
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More

    Comments 32

      +1
      прогоните хоть через ворд текст ,а потом еще самостоятельно перечитайте. Например:
      В целом боритесь по мере возможности с тем, что в главе 5 было названо «не- «несущественной сложностью».
        0
        Спасибо, эту ошибку не заметил, исправил. Я перечитал текст 5 раз, но, как известно, глаз замыливается.
          +2
          Тогда попытаюсь помочь не замыленным глазом :)
          Они вообще лучше чи- читают двоичные команды, а не операторы ...
          Удобочитае- Удобочитаемый код нужно писать для того, чтобы он был понятен людям ...
            0
            Исправил, спасибо за коммент.
        –2
        Простите, а зачем Вы привели этот текст?
          +2
          затем чтобы его прочитали :)
            0
            Дык, книга же есть...
              +2
              людей, которые готовы читать 1000 страниц текста (или тем более платить до 1000 рублей за книгу), в разы меньше, чем тех кто готов иногдп прочитать четыре листа А4 виесто 20-50 листов в книге :)
                0
                К моему сожалению я не нашел книгу ни в одном магазине, даже в интернете с доставкой (живу в провинции :( ).
                По этому рад всем таким статьям, где для моего понимания перевод :)
            0
            за GOTO программистам вообше руки отрывать надо (если они конечно не на asmе пишут)
              0
              10 PRINT("Меня клинит !")
              20 GOTO 10

              Самый простой и совершенный бесконечный цикл не может обойтись без GOTO. :)

              P.S. Кстати, во многих старых Бейсиках (особенно прошитых в ПЗУ) не было понятия подпрограмм (SUB) и без GOTO там ну совсем никак.
                0
                самый простой бесконечный цыкл делается так
                while (true)
                {
                }
                слава богу на вышеописаных бейсиках сей4ас уже не пишут
                  0
                  Нет, это не самый простой и вот почему... Переведем на асм:

                  Вариант 1 (GOTO):
                  _______________________________
                  lbl:
                  mov ah,9
                  mov dx,offset Message
                  int 21h
                  jmp short lbl

                  Вариант 2 (WHILE):
                  _______________________________
                  lbl:
                  mov ah,9
                  mov dx,offset Message
                  int 21h
                  mov bh,0
                  cmp bh,0
                  je short lbl

                  while - это операция сравнения и мы получаем +2 бессмысленных оператора (+4 байта)...
                    0
                    я с точки зрения красивости кода имел ввиду.
                    конечно 4 байта во времена террабайтов сыграют большую разницу :))
                      0
                      Нет, самый красивый и простой бесконечный цикл делается в 5 символов на Haskell:
                      [1..]
                        0
                        Это не будет же циклом. Штука ничего не делает, пока к ней не обратятся. А с обращением будет уже не всё так тривиально :) и букффочки полезут.
                        0
                        С точки зрения красивости кода - for(;;);
                        8)
                          0
                          #define ever ;;
                          for(ever);

                          :)
                        +1
                        Так ведь
                        jmp $
                        ещё короче, или я уже подзабываю школу? :)
                          0
                          включите в своем компиляторе оптимизацию и посмотрите внимательно еще раз
                            0
                            Так это у вас компилятор глупый. Нормальные компиляторы давным давно умеют такие while'ы заменять прямыми jmp'ами.
                        +1
                        Не так давно был поражён, увидев такую странную организацию ветвления (пример на Перле):


                        goto LABEL1 unless <условие 1>;

                        <блок кода>

                        LABEL1:

                        <ещё блок кода>

                        goto LABEL2 unless <условие 2>;

                        <блок кода>

                        LABEL2:


                        Неужели человек таким образом хотел сократить вложенность кода, которая и без того была меньше 2?!
                          0
                          а что, `goto` ещё где-то остался?
                          но иногда он бывает необходим для выхода из вложенных циклов.
                          приходится замещать `goto` установкой и проверкой флагов.
                          +1
                          Как известно, мозг человека может одновременно рассматривать 7±2 элемента. Поэтому очень важно стремиться к снижению сложности ПО.

                          Вокруг проблемы сложности ПО существует огромная масса недоразумений и заблуждений. Часть этих недоразумений вошла в жизнь разработчиков с лёгкой руки классиков, таких как Фредерик П. Брукс и Гради Буч. Часть этих недоразумений строится на непонимании разработчиками ПО природы сложности с которой они сталкиваются.

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

                          Начать я думаю нужно с того, что существует много видов сложности, и для каждого вида сложности будут свои методы борьбы с нею. К видам сложности относятся:

                          1. Сложность объёма работ. Сюда-же относится и невозможность воспринимать более чем 7±2 элемента. Из всех видов сложности эта является самой безобидной, и преодолевается простым распаралеливанием работ между работниками.

                          2. Математическая сложность. Преодолевается при помощи математического анализа.

                          3. Алгоритмическая сложноть. Преодолевается при помощи алгоритмического анализа.

                          4. Архитектурная сложность. Преодолевается при помощи архитектурного анализа, архитектурной декомпозиции системы.

                          5. Сложность предметной области. Реашается при помощи декомпозиции предметной области и абстрагирования.

                          И так далее.

                          Для борьбы со сложностью необходимо понимать с какой именно сложностью мы хотим бороться и применять соответствующие методы уже в зависимости от обстоятельств.
                            +1
                            как-то вы сложно написали...
                              0
                              6. Сложность сепуления. Преодолевается сепулярным анализом.

                              Часто способы решения той или иной сложности становятся в разы сложнее, чем исходная сложность.
                                0
                                > Часто способы решения той или иной сложности становятся в разы сложнее, чем исходная сложность.

                                Я хотел сказать совершенно не это. Я хотел сказать что алгоритм qsort сложен, но эту сложность безполезно преодолевать при помощи декомпозиции алгоритма на составные части. Декомпозиция нужна для преодоления другого вида сложности - архитектурной. Точно так же сложность алгоритма qsort бесполезно преодолевать при помощи абстрагирования. Абстрагирование предназначено для преодоления сложности предметной области.
                            • UFO just landed and posted this here
                                0
                                угу, 3 раза прочитал... так и не понял, что имелось ввиду. Хотя подозреваю, что это всяческие фрагменты кода подразумевающие неявное знание реализации. Например:

                                Метод возвращает вектор из N первых слов в строке. Если передать -1 в качестве N, то он вернет вектор из всех слов в строке. -1, в качестве параметра, описано где-то в комментакриях, но пользуясь банальной логикой, сложно прийти к выводу, что можно передавать -1 для получения всех слов.

                                Ииенно таких (зачастую принятых в С/С++) конструкций, предлагает избежать автор...

                                =) Все ИМХО
                                0
                                Э-э, а как на счёт "Деталей мастерства" :)? Что-нибудь в продолжении будет? А то как-то правда одни "основы". Мне вот например нравится проектирование через шаблоны, разработка через тестирование а у вас как-то про это вообще ничего :(
                                  0
                                  это уже методики разработки. по таким вещам, как XP, agile dev и т.д. есть целые книги :)
                                  но буду освещать эти темы. уже, Видимо, на новом хабре :)
                                  0
                                  без примеров текст не имеет смысла. Для меня почти все банальности, новичок не поймет вашу мысль или не дай бог заучит буквально.

                                  Only users with full accounts can post comments. Log in, please.