ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 30.10.2023
Просмотров: 424
Скачиваний: 1
ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
СОДЕРЖАНИЕ
Думайте как программист 241
проекти рования, что не оставляет достаточно времени на факти- ческую реализацию выбранного дизайна. Кроме того, иногда из-за этого решение получается чрезмерно разработанным. То есть ино- гда решение оказывается более элегантным, расширяемым и надеж- ным, чем необходимо. Поскольку каждый проект ограничен в плане времени и денег, лучшее решение должно сбалансировать стремле- ние к высокому качеству программного обеспечения с необходимо- стью экономии ресурсов.
Я считаю, что моя самая сильная сторона в программировании заключается в том, что я хорошо усваиваю новые концепции и люб- лю учиться. В то время как некоторым программистам нравится сно- ва и снова использовать одни и те же навыки, мне нравится работать над проектом, на котором я могу научиться чему-то новому, и я всегда с радостью принимаю вызов.
Далее представлен мой мастер-план для нового проекта, учиты- вающий мои сильные и слабые стороны.
Чтобы справиться со своей основной слабой стороной в области дизайна, я строго ограничу свое время на этапе проектирования или ограничу количество различных версий дизайна, которые я буду рас- сматривать, прежде чем двигаться дальше. Некоторым читателям это может показаться опасной идеей. Разве мы не должны потратить максимально возможное количество времени на этапе проектирова- ния, прежде чем переходить к кодированию? Разве не правда, что большинство проектов терпят неудачу из-за того, что на начальных этапах было потрачено недостаточно времени, что привело к необ- ходимости многочисленных компромиссов в конце? Это правомер- ные опасения, однако помните, что моей целью не являлось созда- ние общего справочника по разработке программного обеспечения.
Я создаю свой личный мастер-план для решения проблем програм- мирования. Моя слабая сторона заключается в чрезмерной, а не в не- достаточной разработке, поэтому правило, ограничивающее время на этапе проектирования, является для меня актуальным. Для друго- го программиста такое правило может оказаться катастрофическим, а некоторым программистам может понадобиться правило, застав- ляющее их тратить больше времени на разработку.
После завершения своего первоначального анализа я собираюсь посмотреть, предоставляет ли проект возможность для изучения но- вых методов, библиотек и т.д. Если да, я собираюсь написать неболь- шую пробную версию программы, чтобы опробовать эти новые на- выки, прежде чем пытаться включить их в разрабатываемое мною решение.
Чтобы справиться с чрезмерным рвением, я мог бы включить небольшой этап для обзора кода после завершения этапа кодиро- вания каждого модуля. Тем не менее это потребует от меня приме- нения силы воли — после завершения модуля мне захочется опро- бовать его. Просто надеяться на то, что я смогу всякий раз себя
242 Глава 8
уговорить, — это все равно, что оставить открытый пакет с карто- фельными чипсами рядом с голодным человеком и удивиться, когда пакет опустеет. Лучше попытаться справиться со слабыми сторона- ми с помощью плана, который не требует от программиста борьбы с собственными инстинктами. Итак, что, если я создам две версии проекта: приблизительную версию, с которой можно делать все что угодно, и отшлифо ванную версию, которую можно сдать заказчику?
Если я позволю себе поиграть с первой версией по своему усмотре- нию, но не позволю себе включать код в отшлифованную версию до тех пор, пока он не будет полностью проверен, я с большей вероят- ностью преодолею свой недостаток.
Решение любой задачи
Теперь, когда у нас есть мастер-план, мы готовы ко всему. В конеч- ном счете, суть этой книги сводится к следующему: начните с задачи, с любой задачи, и найдите способ ее решения. Во всех предыдущих главах описания задач подталкивали нас в определенном направле- нии, однако в реальном мире большинство задач не подразумева- ет требований, связанных с использованием массива или рекурсии или инкапсуляцией части функций программы в класс. Эти решения принимает программист по ходу рабочего процесса.
Поначалу может показаться, что меньшее количество требо- ваний делает задачу более простой. В конце концов, требование к дизайну является ограничением, а разве ограничения не затрудня- ют решение задачи? Хотя это верно, верно и то, что все задачи под- разумевают ограничения, просто в некоторых случаях они изложе- ны более четко, чем в других. Например, если вам не было сказано, что конкретная задача требует динамически выделяемой структуры, не означает, что это решение является бесполезным. Более общим ограничениям задачи, касаются ли они производительности, моди- фицируемости, скорости разработки или чего-то еще, может быть сложнее или вообще невозможно удовлетворить, если мы сделаем неправильный выбор в плане дизайна.
Представьте, что группа друзей попросила вас выбрать фильм для совместного просмотра. Если один из друзей определенно хочет посмотреть комедию, другой не любит старые фильмы, а третий пе- речисляет пять фильмов, которые он недавно видел, поэтому не хо- чет смотреть их снова, то эти ограничения затруднят выбор. Однако если ни у кого нет никаких пожеланий, кроме «просто какого-нибудь хорошего фильма», ваша задача становится еще более сложной, и вы, скорее всего, выберете то, что вообще не понравится по край- ней мере одному человеку из группы.
Поэтому крупные, пространно определенные, слабо ограничен- ные задачи являются самыми трудными из всех. Тем не менее к ним применимы рассмотренные в этой книге методы; их решение про-
Думайте как программист 243
сто требует чуть большего количества времени. Знания этих мето- дов и ваш мастер-план помогут вам решить любую задачу.
Чтобы продемонстрировать суть того, о чем я говорю, я прове- ду вас по первым этапам программы, которая играет в классическую детскую игру «Виселица», но с подвохом.
Прежде чем перейти к описанию задачи, давайте рассмотрим основные правила этой игры. Первый игрок выбирает слово и го- ворит второму игроку, сколько в этом слове букв. Второй игрок пы- тается угадать букву. Если названная буква присутствует в слове, пер- вый игрок показывает, в каком месте слова эта буква находится; если эта буква встречается в слове более одного раза, указываются все ее положения. Если названная буква в слове отсутствует, первый игрок добавляет фрагмент к рисунку повешенного. Если второй игрок уга- дывает все буквы в слове, то он побеждает, если первый игрок за- вершает рисунок, то побеждает он. Существуют разные правила относительно количества фрагментов, составляющих рисунок пове- шенного, поэтому в общем случае мы можем сказать, что игроки за- ранее договариваются о том, сколько «промахов» должен допустить второй игрок, чтобы первый выиграл.
Теперь, когда мы обговорили основные правила, давайте рассмо- трим конкретную задачу, включая подвох.
: « & »
Напишите программу, которая будет Игроком 1 в текстовой версии игры «Виселица»
(то есть на самом деле вам не нужно рисовать повешенного, нужно только отслеживать количество неправильных догадок). Игрок 2 будет задавать уровень сложности игры, указывая длину слова, которое требуется угадать, а также количество неправильных догадок, которые приведут к проигрышу.
Подвох заключается в том, что программа будет жульничать. Вместо того чтобы вы- бирать слово в начале игры, программа может избегать выбора слова так, что, когда
Игрок 2 проиграет, программа отобразит слово, соответствующее всей информации, предоставленной Игроку 2. Правильно угаданные буквы должны указываться в соот- ветствующих им положениях, а неправильно угаданные буквы вообще не могут по- явиться в этом слове. Когда игра закончится, Игрок 1 (программа) сообщит Игроку 2 слово, которое было выбрано. Поэтому Игрок 2 никогда не сможет доказать, что игра его обманывает; просто вероятность выигрыша для Игрока 2 низкая.
Это не слишком крупная задача по стандартам реального мира, однако она достаточно велика, чтобы на ее примере можно было продемонстрировать проблемы, с которыми мы сталкиваемся при решении задачи программирования, которая обозначает результа- ты, но не содержит никакой методологии. Основываясь на описа- нии задачи, вы можете запустить свою среду разработки и начать пи- сать код с любого места. Это, конечно, было бы ошибкой, потому что нам всегда следует создавать код по плану, поэтому я собираюсь применить свой мастер-план к этой конкретной ситуации.
244 Глава 8
Первая часть моего мастер-плана ограничивает количество вре- мени, которое я трачу на этапе проектирования. Чтобы реализовать это, мне нужно тщательно продумать дизайн, прежде чем приступать к созданию кода. Тем не менее я считаю, что в данном случае для на- хождения решения этой задачи мне понадобится провести несколь- ко экспериментов. Мой мастер-план также позволяет мне создать два проекта — грубый прототип и окончательное отшлифованное решение. Поэтому я позволю себе начать кодирование прототипа в любое время до начала реальной работы над дизайном, но не при- ступлю к кодированию итогового решения, пока не удостоверюсь в том, что дизайн разработан так, как нужно. Это не гарантирует того, что я буду полностью удовлетворен дизайном второго проекта, но максимизирует вероятность этого.
Теперь пришло время разделить задачу на части. В предыдущих главах мы иногда перечисляли все подзадачи, необходимые для ито- гового решения задачи, поэтому я хотел бы провести инвентариза- цию подзадач. Тем не менее на данном этапе это было бы сложно сделать, поскольку я не знаю, что программа сделает на самом деле, чтобы обмануть второго игрока. Мне нужно более подробно иссле- довать этот вопрос.
Нахождение возможности для жульничества
Обман в игре «Виселица» достаточно специфичен, поэтому я не ожидаю найти какое-либо руководство в обычных источниках с ком- понентами; там вряд ли есть шаблон под названием БесчестнаяСтра-
тегия. На данном этапе у меня есть лишь смутное представление о том, как можно сжульничать в этой игре. Я думаю, что загадаю исход- ное слово и буду придерживаться его, пока Игрок 2 выбирает буквы, которые отсутствуют в этом слове. Как только Игрок 2 назовет бук- ву, которая на самом деле есть в этом слове, я выберу другое слово, если можно будет найти такое, в котором нет ни одной из названных до сих пор букв. Другими словами, я буду стараться как можно доль- ше отказывать Игроку 2 в правильности его догадки. Это идея, но мне нужно нечто большее, чем идея, — мне нужно что-то, что я могу реали зовать.
Чтобы развить свои идеи, я разберу пример на бумаге, взяв на себя роль Игрока 1 и работая со списком слов. Чтобы не усложнять, я предположу, что Игрок 2 запросил слово, состоящее из трех букв, и что полный список известных мне трехбуквенных слов представлен в первом столбце табл. 8.1. Я предполагаю, что первым загаданным мной словом является первое слово в списке — bat. Если Игрок 2 назо- вет любую букву, кроме b, a или t, я скажу «нет», и мы подойдем на один шаг ближе к завершению рисунка повешенного. Если Игрок 2 угадает букву в слове, то я выберу другое слово, которое не содержит эту букву.
Тем не менее, глядя на свой список, я не уверен, что эта страте- гия является лучшей. В некоторых ситуациях она, вероятно, име-
Думайте как программист 245
ет смысл. Предположим, что Игрок 2 называет букву b. Ни одно из оставшихся в списке слов не содержит букву b, поэтому я могу вы- брать в качестве загаданного слова любое из них. Это также означа- ет, что я минимизировал ущерб; я исключил из своего списка только одно возможное слово. Но что, если Игрок 2 назовет букву a? Если я просто скажу «нет», мне придется исключить все слова, содержа- щие букву a, при этом останется только три слова во втором столбце табл. 8.1, из которых я смогу выбрать. Если бы вместо этого я решил признать наличие буквы a в загаданном слове, у меня осталось бы пять слов на выбор, как показано в третьем столбце. Однако заметь- те, что этот расширенный выбор существует только потому, что все пять слов содержат букву a в одном и том же положении. Как только я признаю догадку правильной, я должен буду точно указать, где в слове находится буква. Я буду чувствовать себя гораздо спокойнее, если у меня будет больше вариантов слов, среди которых я могу сде- лать выбор в ответ на будущие догадки.
Табл. 8.1. Образец списка слов
“ “%"=
q%"= Kƒ K3"/ a
q%"= K3"%L a
bat dot bat car pit car dot top eat eat saw pit tap saw tap top
Кроме того, даже если мне удастся избежать раскрытия букв в нача- ле игры, мне следует ожидать того, что Игрок 2 в конечном итоге сде- лает правильное предположение. Например, Игрок 2 может начать с перечисления всех гласных. Поэтому в какой-то момент мне нужно бу- дет решить, что делать, когда буква будет открыта, и, судя по моему экс- перименту с образцом списка, мне нужно будет найти местоположение
(или местоположения), в которых эта буква появляется чаще всего. Это наблюдение заставило меня понять, что я неправильно подошел к обду- мыванию возможного обмана. Мне никогда не следует загадывать сло- во, даже на время, мне нужно просто отслеживать все возможные сло- ва, из которых при необходимости я мог бы выбрать одно.
Имея в виду эту идею, я могу теперь по-другому определить спо- соб обмана: следует хранить как можно больше слов в списке слов- кандидатов. При каждой высказанной Игроком 2 догадке программа должна принять решение. Признает ли она догадку правильной или не правильной? Если догадка правильная, то, в каком месте слова на- ходится угаданная буква? Я сделаю так, что моя программа будет по- стоянно сокращать список слов-кандидатов и после каждой выска- занной догадки принимать решение, при котором в этом списке остается максимальное количество слов.