![]()
Главная Обратная связь Дисциплины:
Архитектура (936) ![]()
|
Инструментальные средство UNIX, работающие в среде DOS
[URL 30] The UWIN Development Tools www.gtlinc.com/Products/Uwin/uwin.html Фирма Global Technologies, Inc., Old Bridge, NJ Пакет UWIN предоставляет библиотеки динамической компоновки (DLL) Windows, которые эмулируют большую часть библиотечного интерфейса уровня Unix С. Используя данный интерфейс, фирма Global Technologies, Inc. перенесла большое число инструментальных средств из командной строки Unix в систему Windows. См. также [URL 31]. [URL 31] The Cygnus Cygwin Tools www.sourceware.cygnus.com/cygwin/ Фирма Cygnus Solutions, Sunnyvale, CA Пакет Cygnus также эмулирует интерфейс библиотеки Unix С и предоставляет большой набор инструментальных средств, работающих в режиме командной строки Unix, при работе в операционной системе Windows. [URL 32] Perl Power Tools www.perl.com/language/ppt/ Данный проект посвящен повторной реализации классического набора команд Unix на языке Perl, что дает возможность их использования при работе со всеми платформами, поддерживающими Perl (их довольно много). Средствауправленияисходнымтекстомпрограмм [URL 33] RCS – Revision Control System www.cyclic.com Система управления исходным текстом программ GNU для Unix и Windows NT. [URL 34] CVS – Concurrent Version System www.cyclic.com Система управления исходным текстом программ для Unix и Windows NT, распространяемая бесплатно. Расширяет возможности Revision Control System, поддерживая модель «клиент-сервер» и параллельный доступ к файлам. [URL 35] Aegis Transaction-Based Configuration Management www.canb.auug.org.au/"mil!erp/aegis.html Инструментальное средство управления версиями (ориентированное на процесс), которое применяет к ним существующие стандарты проекта (например, проверку прохождения тестов для возвращаемых программных кодов). [URL 36] ClearCase www.rational.com Управление версиями программы, рабочей областью и полной сборкой программы, управление процессом. [URL 37] MKS Source Integrity www.mks.com Управление версиями и конфигурацией. Некоторые версии включают средства, позволяющие удаленным пользователям-разработчикам одновременно работать над одними и теми же файлами. [URL 38] PVCS Configuration Management www.merant.com Система управления исходным текстом программ, очень популярная при работе в Windows. [URL 39] Visual SourceSafe www.microsoft.com Система управления версиями, интегрируемая с инструментами визуальной разработки фирмы Microsoft. [URL 40] Perforce www.perforce.com Менеджер конфигурирования программного обеспечения "клиент-сервер". Прочие инструментальные средства [URL 41] Winzip – Archive Utility for Windows www.winzip.com Фирма Nico Mak Computing, Inc., Mansfield, CT Утилита архивирования файлов, работающая в среде Windows. Поддерживает форматы zip и tar. [URL 42] The Z Shell www.sunsite.auc.dk/zsh Оболочка, предназначенная для интерактивной работы и содержащая мощный язык сценариев. В оболочку zsh было включено много полезных средств из оболочек bash, ksh и tcsh и добавлен ряд оригинальных элементов. [URL 43] A Free SMB Client for Unix Systems www.samba.anu.edu.au/pub/samba/ Дает возможность совместного использования файлов и других ресурсов из операционных систем Unix и Windows. Samba включает в себя: • Сервер SMB, предоставляющий средства для работы с файлами и для печати (схожие со средствами, предоставляемыми Windows NT и LAN Manager) клиентам SMB, в роли которых могут выступать Windows 95, Warp Server, smbfs и др. • Сервер имен Netbios, обеспечивающий, кроме всего прочего, поддержку функций браузера. По желанию пользователя Samba может быть главным браузером в локальной сети. • Клиент SMB (схожий с клиентом ftp), позволяющий получать доступ к ресурсам ПК(дискам и принтерам) из Unix, Netware и других операционных систем.
Статьи и публикации
[URL 44] The comp.object FAQ www.cyberdyne-object-sys.com/oofaq2 Солидный, четко организованный список часто задаваемых вопросов по группе новостей comp.object. [URL 45] extreme Programming www.Xprogramming.com Цитата с интернет-сайта: "При создании команды, способной быстро создать исключительно надежное, эффективное, четко структурированное программное обеспечение, в ХР используется весьма легковесное сочетание методик. Многие из методик ХР создавались и опробовались в части проекта СЗ фирмы «Крайслер», представляющего собой весьма успешную систему расчета заработной платы, написанную на языке Smalltalk". [URL 46] Alistair Cockburn's Home Page www.members.aol.com/acockburn Стоит посмотреть раздел "Structuring Use Cases with Goals" и так называемые шаблоны сценариев использования. [URL 47] Martin Fowler's Home Page www.ourworld.compuseimcom/homepages/martinjowler Мартин Фаулер является автором книги "Analysis Patterns" и соавтором книг "UML Distilled" и "Refactoring: Improvingthe Design of Existing Code". На домашней странице автора обсуждаются его книги и работа с UML. [URL 48] Robert С. Martin's Home Page www.objectmentor.com/home Неплохое собрание статей ознакомительного плана по объектно-ориентированным методам, включая анализ зависимости и метрики. [URL 49] Aspect-Oriented Programming www.parc.xerox.com/csl/projects/aop/ Описывается методика придания функциональности программному коду с позиций ортогональности и описательности. [URL 50] JavaSpaces Specifications www.java.sun.com/products/javaspaces Linda-подобная система для Java, поддерживающая распределенное сохранение состояния объекта и распределенные алгоритмы. [URL 51] Netscape Source Code www.mozilla.org Исходный текст браузера Netscape. [URL 52] The Jargon File www.jargon.org Eric S. Raymond Определения дня многих общих (и не очень общих) терминов, применяемых в компьютерной индустрии, сдобренные хорошей дозой соответствующего фольклора. [URL 53] Eric S. Raymond's Papers www.tuxedo.org/~esr Статьи Эрика Раймона "The Cathedral and the Bazaar" и "HomesteadingNoosphere", в которых описаны психосоциальные основы и смысл движения Open Source. [URL 54] The К Desktop Environment www.kde.org Цитата с web-страницы: "KDE представляет собой мощную графическую настольную среду для рабочих станций Unix. KDE является интернет-проектом, открытым в полном смысле этого слова". [URL 55] The GNU Image Manipulation Program www.gimp.org Gimp является бесплатной программой по созданию, композиции и ретушированию изображений. [URL 56] The Demeter Project www.ccs.neu.edu/research/demeter Исследовательский проект, призванный упростить поддержку и развитие программного обеспечения с помощью адаптивного программирования.
Другие источники
[URL 57] The GNU Project www.gnu.org Фонд Free Software Foundation, Boston, MA Фонд "Free Software Foundation" – это некоммерческая благотворительная организация, осуществляющая сбор средств на проект GNU. Целью проекта GNU является создание завершенной, бесплатной UNIX-подобной операционной системы. Многие из попутно разработанных инструментальных средств уже стали отраслевыми стандартами. [URL 58] Web Server Information www.netcraft.com/survey/servers.html Ссылки на домашние страницы, находящиеся более чем на 50 web-серверах. Часть из них является коммерческими продуктами, другие же распространяются бесплатно.
Библиография
[Bak72] F.T. Baker. Chief programmer team management of production programming. IBM Systems Journal, 1 1(1):56–73, 1972. [BBM96] V. Basili, L. Brand, and W.L. Melo. A validation of object-oriented design metrics as quality indicators. IEEE Transactions on Software Engineering, 22(10):751–761, October 1996. [Ber96] Albert J. Bernstein. Dinosaur Brains: Dealing with All Those Impossible People at Work. Ballantine Books, New York, NY, 1996. [Bra95] Marshall Brain. Win32 System Services. Prentice Hall, Englewood Cliffs, NJ, 1995. [Bro95] Frederick P. Brooks, Jr.. The Mythical Man Month: Essays on Software Engineering. Addison – Wesley, Reading, MA, anniversary edition, 1995. [CG90] N. Carriero and D. Gelenter. How to Write Parallel Programs: A First Course. MIT Press, Cambridge, MA, 1990. [CN91] Brad J. Cox and Andrex J. Novobilski. Object-Oriented Programming, An Evolutionary Approach. Addison-Wesley, Reading, MA, 1991. [Coc97a] Alistair Cockburn. Goals and use cases. Journal of Object Oriented Programming, 9(7):35–40, September 1997. [Coc97b] Alistair Cockburn. Surviving Object-Oriented Projects: A Manager's Guide. Addison Wesley Longman, Reading, MA, 1997. [Cop92] James O. Coplien. Advanced С++ Programming Styles and Idioms. Addison-Wesley, Reading, MA, 1992. [DL99] Tom Demarco and Timothy Lister. Peopleware: Productive Projects and Teams, Dorset House, New York, NY, second edition, 1999. [FBB+99] Martin Fowler, Kent Beck, John Brant, William Opdyke, and Don Roberts. Refactoring: Improving the Design of Existing Code. Addison Wesley Longman, Reading, MA, 1999 [Fow96] Martin Fowler. Analysis Patterns: Reusable Object Models. Addison Wesley Longman, Reading, MA, 1996. [FS97] Martin Fowler and Kendall Scott. UML Distilled: Applying the Standard Object Modeling Language. Addison Wesley Longman, Reading, MA, 1997. [GHJV95] Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides. Design Patterns: Elements of Reusable Object-Oriented Software. Addison-Wesley, Reading, MA, 1995. [Gla99a] Robert L. Glass. Inspections – Some surprising findings. Communications of the ACM, 42(4): 17–19, April 1999. [Gla99b] Robert L. Glass. The realities of software technology payoffs. Communications of the ACM, 42(2):74–79, February 1999. [Hol78] Michael Holt. Math Puzzles and Games, Dorset Press, New York, NY, 1978. [Jac94] Ivar Jacobson. Object-Oriented Software Engineering: A Use-Case Driven Approach. Addison-Wesley, Reading, MA, 1994. [KLM+97] Gregor Kiczales, John Lamping, AnuragMendhekar, Chris Maeda, Cris-tina Videira Lopes, Jean-Marc Loingtier, and John Irwin. Aspect-oriented programming. In European Conference on Object-Oriented Programming (ECOOP), volume LNCS 1241. Springer-Verlag, June 1997. [Knu97a] Donald Ervin Knuth. The Art of Computer Programming: Fundamental Algorithms, volume 1. Addison Wesley Longman, Reading, MA, third edition, 1997. [Knu97b] Donald Ervin Knuth. The Art of Computer Programming: Seminumeri-cal Algorithms, volume 2. Addison Wesley Longman, Reading, MA, third edition, 1997. [Knu98] Donald Ervin Knuth. The Art of Computer Programming: Sorting and Searching, volume 3. Addison Wesley Longman, Reading, MA, second edition 1998. [KP99] Brian W. Kernighan and Rob Pike. The Practice of Programming. Addison Wesley Longman, Reading, MA, 1999. [Kru98] Philippe Kruchten. The Rational Unified Process: An Introduction. Addison Wesley Longman, Reading, MA, 1998. [Lak96] John Lakos. Large-Scale С++Software Design. Addison Wesley Longman, Reading, MA, 1996. [LH89] Karl J. Lieberherr and Ian Holland. Assuring good style for object-oriented programs. IEEE Software, pages 38–48, September 1989. [Lis88] Barbara Liskov. Data abstraction and hierarchy. SIGPLAN Notices, 23(5), May 1988. [LMB92] John R. Levine, Tony Mason, and Doug Brown. Lex and Yacc. O'Reilly & Associates, Inc., Sebastopol, CA, second edition, 1992. [McC95] Jim McCarthy. Dynamics of Software Development. Microsoft Press, Redmond, WA, 1995. [Mey96] Scott Meyers. More Effective С++: 35 New Ways to Improve Your Programs and Designs. Addison-Wesley, Reading, MA, 1996. [Mey97a] Scott Meyers. Effective С++: 50 Specific Ways to Improve Your Programs and Designs. Addison Wesley Longman, Reading, MA, 1997. [Mey97b] Bertrand Meyer. Object-Oriented Software Construction. Prentice Hall, Englewood Cliffs, NJ, second edition, 1997. [Pet 98] Charles Petzold. Programming Windows, The Definitive Guide to the Win32 API. Microsoft Press, Redmond, WA, fifth edition, 1998. [Sch95] Bruce Schneier. Applied Cryptography: Protocols, Algorithms, and Source Code in C. John Wiley & Sons, New York, NY, 1995. [Sed83] Robert Sedgewick. Algorithms. Addison-Wesley, Reading, MA, 1983. [Sed 92] Robert Sedgewick. Algorithms in С++. Addison-Wesley, Reading, MA, 1992. [SF96] Robert Sedgewick and Phillipc Flajolet. An Introduction to the Analysis of Algorithms. Addison-Wesley, Reading, MA, 1996. [Ste92] W. Richard Stevens. Advanced Programming in the Unix Environment. Addison-Wesley, Reading, MA, 1992. [Ste98] W. Richard Stevens. Unix Network Programming, Volume I: Networking APIs: Sockets andXti. Prentice Hall, Englewood Cliffs, NJ, 1998. [Ste99] W. Richard Stevens. Unix Network Programming, Volume 2: Interprocess Communications. Prentice Hall, Englewood Cliffs, NJ, second edition, 1999. [Str35] James Ridley Stroop. Studies of interference in serial verbal reactions. Journal of Experimental Psychology, 18:643–662, 1935. [WK82] James Q. Wilson and George Kelling. The police and neighborhood safety. The Atlantic Monthly, 249(3):29–38, March 1982. [YC86] Edward Yourdon and Larry L. Constantine. Structured Design: Fundamentals of a Discipline of Computer Program and Systems Design. Prentice Hall, Englewood Cliffs, NJ, second edition, 1986. [You95] Edward Yourdon. Managing projects to produce good-enough software. IEEE Software, March 1995.
Приложение В Ответы к упражнениям
Упражнение 1 из раздела "Ортогональность"
Ответ: По нашему разумению, более ортогональным является класс Split2. Он сосредоточен на собственной задаче – расщеплении строк и игнорирует подробности, связанные с источником обрабатываемых им строк. Это не только упрощает разработку программы, но и придает ей большую гибкость. Класс Split2 может расщеплять строки, считываемые из файла, сгенерированные другой программой или передаваемые через операционную среду.
Упражнение 2 из раздела "Ортогональность"
Ответ: Если все сделано корректно, то, по всей вероятности, немодальное. Система, которая использует немодальные диалоговые окна, испытывает меньшее беспокойство о том, что происходит в любой конкретный момент времени. Скорее всего, она будет обладать лучшей инфрастуктурой взаимодействия между модулями по сравнению с модальной системой, которая может содержать встроенные предположения о состоянии системы – предположения, которые могут привести к большему связыванию и уменьшению ортогональности.
Упражнение 3 из раздела "Ортогональность"
Ответ: Здесь есть элемент лукавства. Объектная технология может обеспечить наличие более ортогональной системы, но поскольку она имеет больше средств, которые могут эксплуатироваться с нарушением режима, в реальности легче создать неортогональную систему, используя объекты, чем создавать ее при помощи процедурного языка. Ее особенности – множественное наследование, исключительные ситуации, перегрузка операторов и переопределение родительского метода (через механизм подклассов) – предоставляют достаточные возможности для увеличения связанности не столь очевидными способами. Применяя объектную технологию и приложив небольшое дополнительное усилие, вы можете добиться наличия более ортогональной системы. И хотя вы всегда можете написать неструктурированную программу на процедурном языке, объектно-ориентированные языки, используемые в малых дозах, могут сделать ее более насыщенной.
Упражнение 4 из раздела "Прототипы и памятные записки"
Ответ: Для спасения ситуации прибегнем к устаревшим технологиям! Нарисуйте на лекционной доске несколько картинок – автомобиль, телефон и дом – с помощью фломастера. Для этого не нужно быть великим художником, вполне достаточно условных изображений. Поместите на доску памятные записки, описывающие содержимое целевых страниц в активных областях экрана. В ходе встречи вы можете совершенствовать рисунки и менять расположение памятных записок.
Упражнение 5 из раздела "Языки, отражающие специфику предметной области"
Ответ: Поскольку мы хотим, чтобы язык был расширяемым, сделаем таблицу синтаксического анализатора управляемой. Каждый элемент таблицы содержит символ команды, флаг, говорящий о необходимости аргумента, и имя подпрограммы, вызываемой для обработки этой конкретной команды. typedef struct { char cmd; /* the command letter */ int hasArg; /* does it take an argument */ void (*func)(int, int); /* routine to call */ } Command; static Command cmds[] = { {'P', ARG, doSelectPen}, ('V', NO_ARG, doPenUp}, {'D', NO_ARG, doPenDown}, {'N, ARG, doPenDir}, {'E', ARG, doPenDir}, {'S', ARG, doPenDir}, {'W', ARG, doPenDir} }; Основная программа довольно проста: считать строку, отыскать команду, при необходимости принять аргумент, затем вызвать функцию обработчика. while (fgetsfbuff, sizeof(buff), stdin)) { Command *cmd = findCommand(*buff); if (cmd) { int arg = 0; if (cmd->hasAr&&!getArg(buff+1, &arg)) { fprintf(stderr," %с' needs an argument", *buff); continue; } cmd->func(*buff, arg); } } Функция, которая ищет команду, исполняет последовательный перебор таблицы, возвращая либо совпадающий элемент, либо NULL. Command *findCommand(int cmd) { int i; for (i = 0; i<ARRAY.SIZE(cmds); i++) { if (cmds[i].cmd==cmd) return cmds + i; } fprintf(stderr, "Unknown command %c'", cmd); return 0; } И наконец, считывание числового аргумента довольно просто, если использовать подпрограмму sscanf. int getArg(const char *buff, int 'result) { return sscanf(buff, "%d", result) == 1; }
Упражнение 6 из раздела "Языки, отражающие специфику предметной области"
Ответ 6: При использовании BNF спецификация времени могла бы выглядеть следующим образом: <tlme>::= <hour> <ampm> | <hour>: <minute> <ampm> | <hour>: <minute> <ampm>::= am|pm <hour>::=<digit> | <digit>::=<digit> <mlnute>::=<digit><digit> <digit>::= 0|1|2|3|4|5|6|7|8|9
Упражнение 7 из раздела "Языки, отражающие специфику предметной области"
Ответ: В нашем примере мы составили программу, используя генератор bison, который представляет собой GNU-версию генератора уасс. Для ясности здесь показано только тело программы синтаксического анализатора. Полная версия есть на сайте www.pragmaticprogrammmer.com. time: spec EOF { if ($1>= 24*60) yyerror("Time is too large"); printf("%d minutes past midnight", $1); exit(0); } ; spec: hour: minute { $$ = $1 + $3; } | hour: minute ampm { if ($1>11*60) yyerrorf "Hour out of range"); $$ = $1 + $3 + $4; } | hour ampm {if ($1>11*60) yyerror("Hour out of range"); $$ = $1 + $2; } ; hour: hour_num {if ($1>23) yyerror("Hour out of range"); $$ = $1 * 60; }; minute: DIGIT DIGIT {$$ = $1*10 + $2; if ($$> 59) yyerrorf "minute out of range"), }; ampm: AM {$$ = AM_MINS;} | PM {$$ = PM_MINS;) ; hour num: DIGIT {$$ = $1;) | DIGIT DIGIT {$$ = $1*10 + $2;} ;
Упражнение 8 из раздела "Языки, отражающие специфику предметной области"
Ответ: $_ = shift; /"(?)(am|pm)$/ && doTime($1, 0, $2, 12); /"(?):()(am|pm)$/ && doTime($1, $2, $3, 12); /"(?):()$/ && doTime($1, $2, 0, 24); die "Invalid time $_"; # # doTime(hour, min, ampm, maxHour) # sub doTime($$$$) { my ($hour, $min, $offset, $maxHour) = @_; die "Invalid hour: $hour" if ($hour>= $maxHour); $hour += 12 if ($offset eq "pm") print $hour*60 + $min, " minutes past midnight"; exit(0); }
Упражнение 9: из раздела "Оценка"
Ответ: Ответ должен быть изложен, исходя из нескольких допущений: • Лента содержит информацию, которую необходимо передать. • Известна скорость ходьбы человека. • Известно расстояние между компьютерами. • Временем, необходимым для переноса информации на ленту и с ленты, можно пренебречь. • Потери данных при хранении на ленте примерно равны их потерям при передаче по каналу связи.
Упражнение 10 из раздела "Оценка"
Ответ: Учитывая допущения ответа 9: Объем информации, содержащейся на стриммерной кассете (4 Гбайт), составляет 32 х 10^9 бит, так что передача эквивалентного объема по каналу со скоростью 1 Мбайт/с заняла бы около 32000 сек. (примерно 9 ч). Если человек движется с постоянной скоростью 3,5 мили в час, то, для того чтобы канал связи превзошел курьера, два компьютера должны располагаться друг от друга на расстоянии не менее 31 мили. Если это расстояние меньше, то победа остается за человеком.
Упражнение 11 из раздела "Обработка текста"
Ответ: Ответ к данному упражнению составлен на языке Perl. my @consts; my $name = <>; die "Invalid format – missing name" unless defined($name); chomp $name; # Read in the rest of the file while (<>) { chomp; s/"*//; s/*$//; die "Invalid line: $_" unless /"(+)$/; push @consts, $_; } # Now generate the file open(HDR, ">$name.h") or die "Can't open $name.h: $!"; open(SRC, ">$name.c") or die "Can't open $name.c: $!"; my $uc_name = uc($name); print HDR "/* File generated automatically – do not edit */"; print HDR "extern const char *$ {ucjiame)_name[];"; print HDR "typedef enum {"; print HDR join",", @consts; print HDR ") $uc_name;"; print SRC "* File generated automatically – do not edit */"; print SRC "const char *$ {uc name}_name[] = {"; print SRC join ",", @consts; print SRC "};"; close(SRC); close(HDR); Используя принцип DRY, мы не будет вырезать и вклеивать этот вновь написанный файл в нашу программу. Вместо этого мы «включим» его – данный плоский файл является главным источником этих констант. Поэтому нам понадобится файл сборки для восстановления заголовка при изменении файла. Следующий фрагмент содержится в системе отладки в исходном дереве (имеется на web-сайте). etest.c etest.h: etest.inc enumerated.pl perl enumerated.pl etest.inc
Упражнение 12 из раздела "Обработка текста"
Ответ: Вот ответ, написанный на языке Perl. my $dir = shift or die "Missing directory", for my Sfile (glob(u$dir/*.pr)) { open(IP, "$file") or die "Opening $file: $!"; undef $/; # Turn off input record separator - my Scontent = <IP>; # read whole file as one string. close(IP); if (Scontent Гrusestrict/m) { rename Sfile, "$file.bak" or die "Renaming $file: $!"; open(OP, ">$file") or die "Creating $file: $!"; # Put 'use strict' on first line that # doesn't start # Scontent =" sr(V.#)/strict;/m', print OP Scontent; close(OP); print "Updated $file"; ) else { print "Sfile already strict": ) }
Упражнение 13 из раздела "Генераторы исходных текстов"
Ответ: Решение реализовано на языке Perl. В программе происходит динамическая загрузка модуля для генерации требуемого языка, так что добавление новых языков не представляет труда. Главная программа загружает внутреннюю часть (основанную на параметре командной строки), затем считывает ее входные данные и вызывает подпрограммы генерации текста, основанные на содержимом каждой из строк. Мы особенно не суетимся, если речь идет об обработке ошибок: если что-то не так, узнаем об этом довольно быстро. my lang = shift or die "Missing language"; $lang.= "_cg.pm"; require <$lang> or die "Couldn't load $lang"; # Read and parse the file my $name; while (<>) { chomp; if (/^ *$/) {CG::blankLine();) elsif ((/^ (.*)/) {CG::comment($1);} elsif ((/^M*(.+)/) {CG::startMsg($1); $name = $1;} elsif ((/^E/) {CG::endMsg($name);} elsif (/^F*(+)+(+)$/) {CG::simpleType($1,$2);} elsif (/^F*(+)+(+)(+)$/) {CG::arrayType $1,$2,$3);} else { die "Invalid line: $ "; } } Написание языковой серверной части не составит труда: создайте модуль, который реализует шесть точек входа. Вот генератор текста на языке С: #!/usr/bin/perl – w package CG; use strict; # Code generator for 'C' (see cg_base.pl) sub blankLine() {print ""; } sub comment() {print "/*$_[0] */"; } sub startMsg() {print "typedef struct {"; } sub endMsg() {print "} $_[0];"; } sub arrayType() { my ($name, $type, $size) = @_; print " $type $name$size];": } sub simpleType{) { my ($name, $type) = @_; print " $type $пате;"; } 1;
А вот генератор текста на языке Pascal: #!/usr/bin/perl – w package CG; use strict; # Code generator for 'Pascal' (see cg_base.pl) sub blankLine() {print "V;) sub comment() {print "{$_[0] }";) sub startMsg() {print "$_[0] = packed record"; } sub endMsg() {print "end;"; } sub arrayType() { my ($name, $type, $size) = @_; $size-; print" $name: array[0…$size] of $type;"; ) sub simpleType() { my ($name, $type) = @_; print" $name: $type;, } 1;
Упражнение 14 из раздела "Проектирование по контракту"
Ответ: Этот пример на языке Eiffel удачен. Мы требуем передачи непустых данных и гарантируем, что семантика циклического двунаправленного списка будет соблюдена. Это также способствует нахождению сохраненной строки. Поскольку это некий отложенный класс, то действительный класс, его реализующий, допускает использование любого основного механизма по своему усмотрению. Он может использовать указатели или массив, или что-то еще; пока он соблюдает контракт, мы не беспокоимся.
Упражнение 15 из раздела "Проектирование по контракту"
Ответ: Это неудачно. Математическое действие в индексном выражении (index-1) не будет работать с граничными условиями, подобными первой точке входа. Постусловие предполагает определенную реализацию; контракты должны быть более абстрактными по сравнению с указанным выше.
Упражнение 16 из раздела "Проектирование по контракту"
Ответ 16: Это удачный контракт, но неудачная реализация. Здесь высовывает свою уродливую голову ошибка типа «Heisenbug» [URL52]. Вероятно, программист допустил опечатку – набрал pop вместо top. Хотя это простой и надуманный пример, весьма трудно диагностировать побочные эффекты в утверждениях (или в любом, самом неожиданном месте в программе).
Упражнение 17 из раздела "Проектирование по контракту"
Ответ: Мы продемонстрируем функциональные сигнатуры на языке Java, обозначая предусловия и постусловия в соответствии с iContract. Сначала инвариант для класса: /** * @invariant getSpeed() >0 * implies isFull() // Не запускать пустое * @invariant getSpeed()>=0 && * getSpeed() <10 // Проверка границ */ Затем предусловия и постусловия: /** * @pre Math.abs(getSpeed() – х) <= 1 // Единственный выбор * @рге х>= 0 && х > 10 // Проверка границ * @post getSpeed() == х // Проверка скорости */ public void setSpeed (final int x) /** * @pre!isFull() // Heзаполнять дважды * @post isFull() // Убедитесь, что было выполнено */ void fill() /** * @pre isFull() // He очищатьдважды * @post!isFull() // Убедиться, что выполнено */ void empty()
Упражнение 18 из раздела "Проектирование по контракту"
Ответ: В этом ряду содержится 21 число. Если вы ответили «20», то допустили так называемую ошибку "поста охраны".
Упражнение 19 из раздела "Программирование утверждений"
Ответ: 1. В сентябре 1752 г. было всего лишь 19 дней. Это было сделано с целью синхронизации при переходе с юлианского на григорианский календарь. 2. Каталог мог быть удален другим процессом, у вас нет прав доступа на его чтение, выражение &sb может быть недопустимым – вы все уловили. 3. Мы проявили малодушие, не указав типов а и b. Во время перегрузки операторов могло случиться так, что поведение знаков +, =, или!= стало непредсказуемым. Кроме того, а и b могут быть псевдонимами одной и той же переменной, так что при втором присвоении произойдет перезапись значения, сохраненного во время первого. 4. В неевклидовой геометрии сумма углов треугольника не будет составлять 180°. Подумайте о треугольнике, отображаемом на поверхности сферы. 5. Минуты, приходящиеся на високосный год, могут состоять из 61 или 62 секунд. 6. Переполнение может оставить результат операции а+1 отрицательным (это также может произойти в языках С и С++).
Упражнение 20 из раздела "Программирование утверждений"
Ответ: Мы решили реализовать очень простой класс с единственным статическим методом TEST, который выводит на печать сообщение и след стека, если переданный параметр condition является ложным. package com.pragprog.util; import java.lang.System; //для exit() import java.lang.Thread; //для dumpStack() public class Assert { /** Write a message, print a stack trace and exit if * our parameter is false. */ public static void TEST(boolean condition) { if (Icondition) { System.out.println("==Assertion Failed=="); Thread.dumpStack(); System.exit(1); } } // Testbed. If our argument is 'okay', try an assertion that // succeeds, if 'fail' try one that fails public static final void main(String args[]) { if (args[0].compareTo("okay") == 0) { TEST(1 == 1); } else if (args[0].compareTo("fail") == 0) { TEST(1 == 2); } else { throw new RuntimeException("Bad argument"), } } }
Упражнение 21 из раздела "Случаи, когда используются исключения"
Ответ: Нехватка памяти является исключительным состоянием, поэтому мы полагаем, что в случае (1) должно возбуждаться исключение. Невозможность отыскания точки входа – вполне нормальная ситуация. Приложение, которое вызывает наш класс-набор, может написать программу, которая проверяет наличие точки входа, перед тем как добавить потенциальный дубликат. Мы полагаем, что в случае (2) нужно просто осуществить возврат ошибки. Случай (3) более проблематичен – если указатель null играет существенную роль в приложении, его добавление к контейнеру может быть оправдано. Но если для хранения пустых значений нет веских оснований, то, по всей вероятности, необходимо возбудить исключительную ситуацию.
Упражнение 22 из раздела "Балансировка ресурсов"
Ответ: В большинстве реализаций языков С и С++ отсутствуют способы проверки того, что указатель действительно указывает на допустимый блок памяти. Обычная ошибка состоит в освобождении блока памяти и организации ссылки на этот блок далее в тексте программы. К тому времени этот блок памяти уже может быть перераспределен для других целей. Обнуляя указатель, программисты надеются предотвращать эти инородные ссылки – в большинстве случаев разыменование указателя null генерирует ошибку в ходе выполнения программы.
Упражнение 23 из раздела "Балансировка ресурсов"
Ответ: Обнуляя ссылку, вы уменьшаете число указателей на упомянутый объект на единицу. Как только этот счетчик становится равным нулю, объект получает право на сбор «мусора». Обнуление ссылок может играть существенную роль в продолжительных по времени программах, где программистам приходиться удостоверяться, что использование памяти со временем не возрастает.
Упражнение 24 из раздела "Несвязанность и закон Деметера"
Ответ: Файл заголовка предназначен для определения интерфейса между соответствующей реализацией и внешним миром. Сам по себе файл заголовка не обязан обладать информацией о внутренней организации класса Date – от него лишь требуется сообщить компилятору о том, что конструктор принимает класс Date в качестве параметра. Поэтому, если файл заголовка не использует Dates в подставляемых функциях, второй фрагмент будет работать просто замечательно. А что же с первым фрагментом? Если он используется в небольшом проекте, то все нормально, за исключением того, что вы без особой надобности заставляете все элементы программы, которые используют класс Person1, также включать файл заголовка для класса Date. Как только подобное употребление становится обычной практикой в неком проекте, вскоре обнаружите, что включение одного файла заголовка заканчивается включением большей части системы, что существенно увеличивает время компиляции.
Упражнение 25 из раздела "Несвязанность и закон Деметера"
Ответ: Переменная acct передается в виде параметра, так что вызов getBalance является допустимым. Вызов amt.printFormat() таковым не является. Мы не «владеем» amt, и он не был передан нам. Мы могли устранить связывание showBalance с Money при помощи вставки, подобной представленной ниже: void showBalance(BankAccount b) { b. printBalance(); }
Упражнение 26 из раздела "Несвязанность и закон Деметера"
Ответ: Поскольку класс Colada создает и владеет myBlender и myStuff, то обращения к addlngredients и elements являются допустимыми.
Упражнение 27 из раздела "Несвязанность и закон Деметера"
Ответ: В этом случае processTransaction владеет amt – он создается на стеке. Происходит передача acct, поэтому допустимыми являются как setValue, так и setBalance. Но processTransaction не владеет who, поэтому вызов who->name() является нарушением. Закон Деметера предлагает заменить эту строку на следующую: markWorkflow(acct.name (), SET_BALANCE); Программе в processTransaction не придется узнавать, какой дочерний объект в пределах BankAccount носит это имя – эта информация о структуре не должна разглашаться через контракт BankAccount. Вместо этого мы запрашиваем у BankAccount имя на счете. Он знает, где хранится имя (может быть, в объекте Person, в объекте Business, или в полиморфном объекте Customer).
Упражнение 28 из раздела "Метапрограммирование"
Ответ: Здесь не приводятся категорические ответы – вопросы предназначались в основном для того, чтобы дать вам пищу для размышлений. И вот что мы думаем: 1. Назначения коммуникационного порта. Ясно, что эта информация должна сохраняться в виде метаданных. Но на каком уровне детализации? Некоторые коммуникационные программы системы Windows позволяют выбирать только скорость в бодах и порт (скажем, СОМ1 – COM4). Но вероятно вам придется указать размер слова, четность, стоповые биты, и настройку дуплексной связи. Старайтесь допускать самый мелкий уровень детализации, там где это разумно с практической точки зрения. 2. Поддержка выделения синтаксических конструкций различных языков в программе редактирования. Она должна быть реализована в виде метаданных. Вы же не хотите, чтобы вам пришлось переделывать программу только потому, что в последней версии языка Java было введено новое ключевое слово. 3. Поддержка редактора для различных графических устройств. Эту поддержку было бы трудно реализовать исключительно в виде метаданных. Вам не хотелось бы нагружать приложение многими драйверами устройств только для того, чтобы выбрать один из них во время выполнения программы. Однако вы могли воспользоваться метаданными для указания имени драйвера и динамической загрузки программы. Это еще один аргумент для сохранении метаданных в удобочитаемом формате; если вы используете программу для установки дисфункционального видеодрайвера, то вы не сможете переустановить его, пользуясь этой программой. 4. Конечный автомат для программы синтаксического анализа или сканера. Это зависит от того, анализируете вы или просматриваете. Если анализируете некоторые данные, которые жестко определены в стандартах и скорее всего не будут изменены без одобрения конгресса США, то жесткое кодирование вполне годится. Но если вы сталкиваетесь с более изменчивой ситуацией, то может быть, более выгодным является внешнее определение таблиц состояний. 5. Типовые значения и результаты, используемые в модульном тестировании. Большинство приложений определяет эти значения как встроенные в тестовый стенд, но вы можете добиться большей гибкости, перемещая тестовые данные и определение приемлемых результатов за пределы самой программы.
Упражнение 29 из раздела "Всего лишь представление"
Ответ: В программу Flight мы добавим ряд дополнительных методов душ поддержания двух списков «слушателей»: для уведомления о листе ожидания и о полной загрузке рейса. public interface Passenger { public void waitListAvailable(); } public interface Flight { … public void addWaitListListener(Passenger p); public void removeWaitUstUstener(Passenger p); public void addFullListener(FullListener b); public void removeFullListener(FullListener b); … } public interface BigReport extends FullListener { public void FlightFullAlert(Flight f); } При неудачной попытке добавить Passenger, поскольку рейс полностью забронирован, мы можем (как вариант) поместить Passenger в лист ожидания. При открытии вакансии производится вызов метода waitListAvailable. Затем этот метод может осуществить выбор: либо добавить Passenger автоматически, либо дать указание сотруднику авиакомпании позвонить заказчику и выяснить, заинтересован ли он еще в рейсе, и т. п. Теперь мы обладаем достаточной гибкостью, чтобы избрать линию поведения, исходя из пожеланий клиента. Кроме того, мы хотим избежать ситуаций, при которых BigReport разбирает тонны записей, отыскивая полностью забронированные рейсы. Зарегистрировав BigReport в качестве «слушателя» Flights, каждый индивидуальный Flight может сообщать, когда он полностью (или почти полностью) забронирован. Теперь пользователи могут мгновенно получить оперативные, с точностью до минуты, сообщения из BigReport, а не ожидать часами окончания его работы, как это было раньше.
Упражнение 30 из раздела "Доски объявлений"
Ответ: 1. Обработка изображения. Для простого распределения рабочей нагрузки между параллельными процессами более чем адекватной может оказаться общедоступная очередь работ. Вы можете рассмотреть систему "доска объявлений" при наличии обратной связи, т. е. если результаты обработки одного фрагмента изображения влияют на другие фрагменты так, как это происходит в системах искусственного зрения или сложных трехмерных преобразованиях изображений. 2. Календарное планирование для групп. Для этого "доска объявлений" очень даже пригодится. Вы можете поместить назначенные собрания и готовность на "доску объявлений". Есть объекты, функционирующие автономно; в данном случае очень важна обратная связь, а участники могут приходить и уходить. Можно рассмотреть возможность разделения "доски объявлений" в зависимости от того, кто осуществляет поиск: младший персонал может заботиться только о локальном офисе, отдел кадров интересоваться только англо-говорящими офисами во всем мире, а исполнительный директор – всем сразу. В форматах данных имеется некий элемент гибкости: мы можем проигнорировать форматы или языки, которых не понимаем. Нам придется понимать различные форматы только для тех офисов, которые встречаются друг с другом, и не придется подвергать всех участников полному транзитивному замыканию всевозможных форматов. При этом связанность уменьшается там, где нужно, и мы не имеем искусственных ограничений. 3. Средство мониторинга компьютерной сети. Это весьма сходно с программой обработки заявлений на ипотечный кредит/ссуду, описанной в примере приложения (с. 153). На доску помещаются сообщения о неисправностях, присылаемые пользователями, и автоматические генерируемые статистические данные. Сотрудник (или программный агент) может анализировать "доску объявлений", чтобы осуществлять диагностику неисправностей в сети: две ошибки в линии могут быть отнесены на счет космических лучей, но 20000 ошибок говорят о проблеме в аппаратном обеспечении. Подобно детективам, разгадывающим тайну убийства, вы можете использовать множественные объекты, анализируя и внося свою лепту в решение проблем, связанных с компьютерной сетью.
Упражнение 31 из раздела "Программирование в расчете на стечение обстоятельств"
Ответ: Эта программа представляет ряд потенциальных проблем. Во-первых, она предлагает наличие текстовой среды. Это, может быть, и прекрасно, если предположение истинно, но что, если эта программа вызывается из графической среды, где не открыты ни stderr, ни stdin? Во-вторых, есть проблематичный оператор gets, который будет записывать столько символов, сколько он получит в переданный буфер. Злонамеренные пользователи использовали это, когда им не удавалось проделать бреши типа buffer overrun в защите многих различных систем. Никогда не пользуйтесь gets(). В-третьих, программа предполагает, что пользователь понимает английский язык. И наконец, никто, находясь в здравом уме, не станет прятать средство взаимодействия с пользователем в недра библиотечной подпрограммы.
Упражнение 32 из раздела "Программирование в расчете на стечение обстоятельств"
Ответ: Работа программы strcpy в системе POSIX не гарантируется при наличии перекрывающихся строк. С некоторыми архитектурами она, случается, и работает, но лишь при стечении определенных обстоятельств.
Упражнение 33 из раздела "Программирование в расчете на стечение обстоятельств"
Ответ: Она не будет работать в контексте апплета при наличии ограничений доступа по записи на локальный диск. Если вы можете выбирать, работать ли через графический интерфейс или нет, то, вероятно, захотите осуществить динамический анализ текущей среды. В этом случае вы наверняка захотите поместить файл журнала вне локального диска, если к нему нет доступа.
Упражнение 34 из раздела "Скорость алгоритма"
Ответ: Ясно, что мы не можем давать никаких абсолютных ответов к этому упражнению. Однако можем дать вам пару намеков. Если ваши результаты не ложатся на гладкую кривую, то вы захотите проверить, не используется ли мощность вашего процессора каким-либо другим процессом. По всей вероятности, вы не получите хороших показателей в многопользовательской системе, и даже если окажетесь единственным пользователем, можете заметить, что фоновые процессы периодически отбирают циклы у ваших программ. Вы также можете захотеть проверить использование памяти: если приложение начинает использовать область свопинга, то производительность резко снижается. Интересно поэкспериментировать с различными компиляторами и установочными параметрами оптимизации. Мы обнаружили, что весьма впечатляющее ускорение стало возможно, благодаря использованию агрессивной оптимизации. Мы также обнаружили, что на более распространенных архитектурах типа RISC компиляторы фирмы изготовителя часто превосходили по быстродействию более переносимую GCC. Возможно, изготовитель посвящен в тайны эффективной генерации программ на этих машинах.
Упражнение 35 из раздела "Скорость алгоритма"
Ответ: Программа printTree использует приблизительно 1000 байт стекового пространства для буферной переменной. Для движения вниз по древовидной схеме она рекурсивно вызывает саму себя, и каждый вложенный вызов добавляет еще 1000 байт к стеку. Она также вызывает саму себя, когда добирается до вершин, но заканчивает работу сразу, как только обнаружит, что переданный указатель обнулен. Если глубина дерева равна D, то максимальный объем, необходимый стеку, составляет (грубо) 1000 x(D+ 1). Сбалансированное двоичное дерево содержит вдвое больше элементов на каждом уровне. Дерево глубиной D содержит 1+2+4+8 +… +2^(D-1), или 2^D – 1 элементов. Следовательно, дереву, состоящему из миллиона элементов, будет необходимо [lg(1000001], или 20 уровней. Поэтому мы рассчитываем, что наша подпрограмма будет использовать примерно 21000 байт стекового пространства.
Упражнение 36 из раздела "Скорость алгоритма"
Ответ: На ум приходит несколько процедур оптимизации. Программа printTree вызывает саму себя на вершинах дерева лишь для того, чтобы закончить работу при отсутствии потомков. Этот вызов увеличивает максимальную глубину стека примерно на 1000 байт. Можно также исключить рекурсию хвоста (второй рекурсивный вызов), хотя это и не будет затрагивать использование стека в наихудшем случае. while (node) { if (node->left) printTree(node->left); getNodeAsString(node, buffer); puts(buffer); node = node->right; } Но самая большая выгода возникает при назначении одного-единственного буфера, доступ к которому осуществляется при всех обращениях к printTree. Если передать этот буфер в виде параметра для рекурсивных обращений, то будет назначено всего 1000 байт вне зависимости от глубины рекурсии. void printTreePrivate(const Node *node, char *buffer) { if (node) { printTreePrivate(node->!eft, buffer); getNodeAsStringfnode, buffer); puts(buffer); printTreePrivate(node->right, buffer); } } void newPrintTree(const Node *node) { char buffer[1000]; printTreePrivate(node, buffer); )
Упражнение 37 из раздела "Скорость алгоритма"
Ответ: Это можно сделать двумя путями. Один из них заключается в том, чтобы перевернуть проблему с ног на голову. Если в массиве есть лишь один элемент, мы не осуществляем итерации в цикле. Каждая дополнительная итерация удваивает размер массива, в котором можно осуществлять поиск. Отсюда общая формула размера массива: n = 2^m, где m – число итераций. Если прологарифмировать обе части с основанием 2, получим выражение lg(n) = lg(2^m), которое из определения логарифма превращается в lg(n) =m.
Упражнение 38 из раздела "Реорганизация"
Ответ: Здесь мы могли бы предложить весьма умеренную реструктуризацию: убедитесь, что каждый тест выполняется лишь один раз, и сделайте все вычисления стандартными. Если выражение 2*basis (…)* 1.05 появляется в других местах программы, то, вероятно, его стоит сделать функцией. В данном случае мы этого делать не стали. Мы добавили массив rate_lookup, инициализированный таким образом, что элементам, отличным от Texas, Ohio и Maine, присвоено значение 1. Этот подход облегчает добавление значений для других штатов в будущем. В зависимости от ожидаемой схемы использования мы могли бы сделать поле points также средством поиска в массиве. rate = rate_lookup[state]; amt = base * rate; calc = 2*basis(amt) + extra(amt)*1.05; if (state == OHIO) points = 2;
Упражнение 39 из раздела "Реорганизация"
Ответ: Когда вы видите, что кто-либо использует перечислимые типы (или эквивалентные им в языке Java), для того чтобы провести различие между вариантами некоего типа, во многих случаях вы можете улучшить программу за счет создания подклассов: public class Shape { private double size; public Shape(double size) { this.size = size; } public double getSize() {return size;) } public class Square extends Shape { public Square(double size) { super(size); } public double area() { double size = getSize(); return size*size; } ) public class Circle extends Shape { public Circle(double size) { super(size); } public double area() { double size = getSize(); return Math.PI*size*size/4.0; } } // efc…
Упражнение 40 из раздела "Реорганизация"
Ответ: Этот случай интересен. На первый взгляд, кажется разумным, что у окна должна быть ширина и высота. Однако стоит подумать о будущем. Представим, что мы хотим обеспечить поддержку окон произвольной формы (что будет весьма трудно, если класс Window обладает всей информацией о прямоугольниках и их свойствах). Мы бы предложили абстрагировать форму окна из самого класса Window. public abstract class Shape { //… public abstract boolean overlaps (Shape s); public abstract int getArea(); } public class Window { private Shape shape; public Window(Shape shape) { this.shape = shape; … } public void setShape(Shape shape) { this.shape = shape; … } public boolean overlaps(Window w) { return shape.overlaps(w.shape); } public int getArea() { return shape.getArea(); } } Заметим, что в этом подходе мы предпочли делегирование созданию подклассов: окно не является «разновидностью» формы – окно «имеет» форму. Оно использует форму для выполнения своей работы. Вы убедитесь, что во многих случаях делегирование оказывается полезным для реорганизации. Мы могли бы расширить этот пример, внедрив интерфейс Java, указывающий на методы, которые должны поддерживаться неким классом для поддержания функций формы. Эта удачная идея означает, что, когда вы расширяете принцип формы, компилятор предупредит вас о классах, которые вы затронули. Мы рекомендуем использовать интерфейсы подобным способом при делегировании всех функций какого-либо другого класса.
Упражнение 41 из раздела "Программа, которую легко тестировать"
Ответ: Вначале добавим подпрограмму main, которая будет действовать как ведущий элемент модульного тестирования. В качестве аргумента она примет простой мини-язык: <Е> будет означать опорожнение блендера, <F> – его наполнение, цифры 0–9 будут задавать скорость вращения ротора, и т. д. public static void main(String args[]) { // Create the blender to test dbc_ex blender = new dbc_ex(); // And test it according to the string on standard input try { int a; char c; while ((a = System.in.read())!= -1) { с = (char)a; if (Character.isWhitespace(c)) { continue; } if (Character.is Digit(с)) { blender.setSpeed(Character.digit(c, 10)); } else { switch (c) { case 'F': blender.fi!l(); break; case 'E': blender.empty(); break; case 's': System.out.printlnfSPEED: " + blender.getSpeed()); break; case 'f': System.out.println(<FULL> + blender.isFull()); break; default: throw new RuntimeException( "Unknown Test directive"); } } } catch (java.io.lOException e) { System.err.println("Tesf jig failed: " + e.getMessage()); } System.err.println("Completed blending"); System.exit(0); }
Затем появится сценарий оболочки для управления тестированием. #!/bin/sh CMD="java dbc.dbc_sx" failcount=0 expect okay() { if echo "$*" | $CMD #>/dev/null 2>&1 then … else echo "FAILED! $*" failcount='expr $failcount + 1 fi } expect_fail() { if echo "$*" | SCMD>/dev/null 2> &1 then echo "FAILED! (Should have failed): $*" failcount='expr $failcount + 1 fi } report() { if [$failcount – gt 0] then echo – e "*** FAILED $failcount TESTS" exit 1 # In case we are part of something larger else exit 0 # In case we are part of something larger fi } # # Start the tests # expect_okay F12345678987654321OE # Should run thru expect_fail F5 # Fails, speed too high expect_fail 1 # Fails, empty expect_fail F10E1 # Fails, empty expect_fail F1238 # Fails, skips expect_okay FE # Never turn on expect_fail F1E # Emptying while running expect_okay F10E # Should be ok report # Report results При тестировании проверяется, не имеют ли место недопустимые переходы в скорости вращения ротора, если вы пытаетесь опорожнить работающий блендер, и т. д. Мы помещаем эту процедуру в сборочный файл, так что можно провести компиляцию и запустить регрессионный тест, просто введя команду: % make % make test Обратите внимание на то, что мы выходим из процедуры тестирования с 0 иди 1, так что можем использовать это и как часть более обширного теста. В требованиях ничего не говорилось о запуске данного компонента через сценарий или даже с использованием языка. Конечные пользователи этого не увидят. Но у нас есть мощный инструмент, который можно использовать для быстрого и исчерпывающего тестирования нашей программы.
Упражнение 42 из раздела "Ошибка в определении требований" Ответ:
1. Эта инструкция похожа на реальное требование: имеются ограничения, налагаемые на приложение со стороны операционной среды. 2. Это может быть корпоративным стандартом, но не требованием. Его лучше сформулировать так: "Фон диалогового окна должен настраиваться конечным пользователем. При поставке заказчику цвет будет серым". Еще лучше было бы сформулировать его более широко: "Все визуальные элементы приложения (цвета, шрифты и языки) должны настраиваться конечным пользователем". 3. Эта формулировка не является требованием, это архитектура. Когда вы сталкиваетесь с подобным, вам придется копать очень глубоко, чтобы понять, что же думает пользователь. 4. Основное требование, вероятно, выглядит примерно так: "Система предотвращает ввод пользователем недопустимых значений в поля и предупреждает пользователя, если ввод этих значений имеет место". 5. Эта формулировка, по всей вероятности, является жестким требованием. Решение головоломки с четырьмя точками, приведенной в разделе "Разгадка невероятных головоломок".
[1] При этом можно утешаться изречением, приписываемым контр-адмиралу д-ру Грэйсу Хопперу: "Легче просить прощения, чем получать разрешение".
[2] Это, конечно шутка!
[3] Истекающий актив представляет собой некий актив, чья стоимость со временем уменьшается. Примерами могут послужить склад, доверху заполненный бананами, и билет на бейсбол.
[4] В эру Интернета, многие люди, кажется, забыли о настоящих библиотеках, в которых имеется штат сотрудников и научные материалы.
[5] В оригинале английское слово annoy происходит от старофранцузского enui что также означает "наскучить".
[6] Применение функций средств доступа дополняет книгу Мейера "Uniform Access principle" [Mey97b], в которой говорится, что "все службы, обеспечиваемые неким модулем, должны быть доступны за счет универсальной системы обозначений, которая отличается надежностью независимо от того, хранятся ли эти службы в памяти или вычисляются".
[7] В вертолете имеется четыре основных органа управления. Рычаг управления циклическим шагом несущего винта находится справа от пилота. При его перемещении вертолет движется в соответствующем направлении. Слева от пилота расположен рычаг управления общим шагом несущего винта. Если потянуть за него, то произойдет увеличение шага на всех лопастях и вертолет начнет подниматься. На конце рычага управления общим шагом расположен дроссель. И наконец, есть две ножных педали, которые изменяют тягу на рулевом винте и способствуют повороту вертолета.
[8] В действительности, это наивно. Лишь при очень большом везении большинство требований из реальной жизни не окажут воздействие на многие функции системы. Тем не менее, в идеале каждое функциональное изменение обязано затрагивать лишь один-единственный модуль.
[9] Возьмем нелинейную или хаотическую систему и внесем небольшое изменение в один из входных параметров. Можно получить серьезный и зачастую непредсказуемый результат. Классический пример: взмах крылышек бабочки в Токио может стать началом цепочки событий, приводящих к возникновению смерча в Техасе. Не напоминает ли это явление некоторые известные вам проекты?
[10] Если быть педантичным, то существует много способов стрельбы из пулемета в темное время суток, включая стрельбу с закрытыми глазами (поливая свинцом все вокруг). Но это лишь аналогия, и авторам позволительны некоторые вольности.
[11] При исследовании абсолютной (в противовес относительной) рабочей характеристики, необходимо придерживаться некоего языка, близкого по характеристикам к целевому языку.
[12] Нормальная форма Бэкуса-Наура (BNF) позволяет осуществлять рекурсивное определение контекстно-свободных грамматик. В любой толковой книге по проектированию компиляторов или синтаксическому анализу имеется подробная спецификация формы BNF.
[13] Авторы благодарят Эрика Вота за этот пример.
[14] На самом деле можно приобретать инструментальные средства, поддерживающие только этот способ написания сценариев. Кроме того, можно изучить пакеты с простым исходным текстом (типа Expect), в которых имеются подобные возможности [URL 24]) делается без компиляции. Это существенно упрощает сопровождение в области динамической области приложения.
[15] Для законодателей вполне достаточно значения 3. В законопроекте № 246 Законодательного собрания штата Индиана (1897) была сделана попытка установить, что отныне число «пи» будет равно 3. Во втором чтении законопроект был отложен на неопределенное время, так как некий профессор математики указал, что власть законодателей не распространяется на законы природы.
![]() |