OberonCore https://forum.oberoncore.ru/ |
|
Статья "Клиника плохого кода" https://forum.oberoncore.ru/viewtopic.php?f=57&t=4931 |
Страница 1 из 1 |
Автор: | Илья Ермаков [ Пятница, 10 Январь, 2014 14:08 ] |
Заголовок сообщения: | Статья "Клиника плохого кода" |
http://web.archive.org/web/200906180318 ... dcode.html Начинается с потрясной реальной истории о том, как из примитивной задачи могут раздуть десятки тысяч строк кода. В середине немного воды, которую может быть скучновато читать, может показаться спорным сравнение с шахматами (типа, "перебор вариантов"). Но, в конечном счёте, если подумать, сходство в анализе ситуации есть - а дальше совершенно правильный вывод, что избежать взрыва вариантов можно только дисциплиной проектирования. Цитата: Лечение: локализация и минимизация
... Лечение: архитектура Кто-то из математиков сказал: если имеется нерешаемая задача, сначала ее надо разбить на подзадачи, решение которых известно. Это есть сущность арихитектуры: для того, чтобы система оставалась управляемой и maintainable для разработчика, ее следует разбить на части и определить интерфейсы и протоколы взаимодействия этих частей. В теории часто говорят о модульности, однако по какой-то непонятной причине наиболее модульные языки, как Паскаль и Ада, постепенно вышли из моды. А ведь они прививали дисциплину стройной древовидной модульности и дисциплину мышления в терминах интерфейс-реализация. Оглядываясь назад, могу сказать, что практика программирования на Turbo Pascal и Delphi заменила мне чтение всевозможных умных книжек по архитекруре. (Ах, да, пресловутые begin...end вместо фигурных скобок - вот что потопило эти замечательные языки.) Но былого не вернешь, и сегодня большинство пишут либо на Си++, где нет понятия модуля, либо на Java/C#, где есть некое подобие модулей, но нет деления на интерфейс и реализацию, хотя бы даже как в Си++. И куда катится этот мир? Полагаю, катится он в сторону какого-то хорошего нового языка, с хорошей модульностью, с лямбда-исчислением и ООП одновременно, и прочими крутыми штуками, - языка, которого пока еще нет. То, что большинство разработчиков и архитекторов (никогда не понимал смысл этой специальности - человек, который не кодирует, но указывает как это надо делать) чаще всего упускают из виду, это следующая важная мысль: функции, особенно часто используемые, становятся частью языка программирования, и следовательно к их дизайну следует подходить примерно с такой же серьезностью, как к дизайну языка. Когда мы излагаем мысль на человеческом языке, мы по сути мыслим понятиями этого языка; аналогично, писать программу на алгоритмическом языке с использованием какого-то набора функций означает излагать мысль на этом формальном языке. Когда мы предлагаем другим разработчикам нашу библиотеку, мы навязываем им некий набор понятий и образ мышления. В реальности же у большинства разработчиков цикл создания библиотеки примерной такой: реализуется какая-то функциональность, и "наружу" выдается набор точек доступа к этой функциональности. При этом считается хорошим тоном выдать наружу как можно больше возможностей на все случаи жизни. Итак, главная дилемма архитектуры - это должны ли интерфейсы каждого модуля быть всеобъемлющими, или наоборот, они должны экономить понятия и давать минимальный набор гибких средств? Если спросить пользователей библиотек, они проголосуют за второе, но - парадокс! - перелезая в шкуру разработчика библиотеки, нам начинает казаться, что "правильнее" первое. Есть о чем подумать, не правда ли? Я вам собираюсь показать, как несколькими легкими движениями можно сильно сократить или даже и вовсе избавиться от довольно громоздкого программного интерфейса. Возьмем Windows Registry. Его предназначение - хранить дерево каких-то числовых и строковых значений, предположительно для хранения конфигурации приложений и самой системы. Эта функциональность описана в виде интерфейса с 41 функциями (!), примерно от 3 до 7 аргументов каждая, плюс какие-то структуры, и как водится, куча констант. ... Какие на самом деле функции нужны для работы с деревом значений? ... И тогда интерфейс работы с Registry сведется к следующим четырем глаголам: create, write, read, delete Но у меня есть еще такая домашняя заготовка, которой мы нанесем Windows Registry удар ниже пояса. Мы решим задачу хранения конфигурационных данных в юниксоидном стиле. Представьте себе, что вы установили в своей UNIX-системе некий продукт под названием UNIX Registry. Вы сразу открываете документацию, чтоб понять как с этим делом работать, и ожидая сотни страниц умного текста, обнаруживаете следующий параграф: Здравствуйте, я ваш путеводитель по UNIX Registry. UR - это специальная файловая система, предназначенная для эффективной работы с очень маленькими файлами. Приложения могут использовать UR для хранения своих конфигурационных данных в виде дерева значений. По соглашению, эта файловая система маунтируется под /var/reg. Каждое приложение создает свое поддерево (напр. /var/reg/xcalendar), в котором рекомендуется также создать отдельные поддеревья для каждого пользователя. Права доступа регулируются как обычно; естественно, в директориях UR вы можете использовать все стандартные файловые утилиты, например find. Для удобства программирования, флаг "x" на файле в UR означает, что файл может хранить только числовое значение. Приятного отдыха. Вот и всё. Всё! Позволю себе дать еще три кратких совета по архитектуре и протоколам: во-первых, используйте технологии Интернета насколько это возможно, например для обмена данными - протокол HTTP. Это дает такую солидную кучу преимуществ, что для их описания понадобилась бы отдельная глава. Попробуйте сами, выберите правильный инструментарий, и поймете о чем речь. В конце концов, не зря технологии Интернета уже победили все остальные технологии. Во-вторых, избегайте XML где возможно решить задачу более простыми текстовыми форматами в юниксоидном стиле. XML is a pain in the ass. Реально, он едва ли что-то упрощает в нашей жизни. Впрочем, может вам как раз надо усложнить? В-третьих, для решения задачи выберите такой язык и такие библиотеки, чтобы основной код состоял исключительно из логики решения этой задачи, и ничего лишнего. Другими словами, никакого метапрограммирования, когда, например, приходится буквально нянчиться с COM/DCOM или же описывать крутые Си++ шаблоны, о которые сам черт ногу сломает. Нужно ли оно вам? Словом, выбирайте такие интерфейсы и протоколы, чтобы пришлось меньше писать кода и зависеть от меньшего количества внешних компонент. Какая простая и очевидная мысль, и как часто мы выбираем в точности противоположную стратегию! ... |
Автор: | Alexey Veselovsky [ Пятница, 10 Январь, 2014 14:30 ] |
Заголовок сообщения: | Re: Статья "Клиника плохого кода" |
Цитата: Но былого не вернешь, и сегодня большинство пишут либо на Си++, где нет понятия модуля, либо на Java/C#, где есть некое подобие модулей, но нет деления на интерфейс и реализацию, хотя бы даже как в Си++. Либо пишут на Обероне или КП, на котором также нет деления на интерфейс и реализацию модуля, увы. (автогенерация оного интерфейса не считается - это и для java/c# есть, и это совершенно, абсолютно не то что нужно) |
Автор: | Иван Кузьмицкий [ Пятница, 10 Январь, 2014 14:37 ] |
Заголовок сообщения: | Re: Статья "Клиника плохого кода" |
Alexey Veselovsky писал(а): Либо пишут на Обероне или КП, на котором также нет деления на интерфейс и реализацию модуля, увы. (автогенерация оного интерфейса не считается - это и для java/c# есть, и это совершенно, абсолютно не то что нужно) Если считать деление на интерфейс и реализацию тем, чем оно и является, то - есть. Интерфейсом пользуются внешние компоненты, реализация недоступна извне.
|
Автор: | Madzi [ Пятница, 10 Январь, 2014 14:39 ] |
Заголовок сообщения: | Re: Статья "Клиника плохого кода" |
У Java есть полноценные интерфейсы. |
Автор: | Alexey Veselovsky [ Пятница, 10 Январь, 2014 20:13 ] |
Заголовок сообщения: | Re: Статья "Клиника плохого кода" |
Иван Кузьмицкий писал(а): Alexey Veselovsky писал(а): Либо пишут на Обероне или КП, на котором также нет деления на интерфейс и реализацию модуля, увы. (автогенерация оного интерфейса не считается - это и для java/c# есть, и это совершенно, абсолютно не то что нужно) Если считать деление на интерфейс и реализацию тем, чем оно и является, то - есть. Интерфейсом пользуются внешние компоненты, реализация недоступна извне.Я уже много на эту тему писал, так что ввязываться в дискуссию не буду. Просто повторю еще раз - в некоторых случаях (например в случаях небольших программ) действительно удобней писать сразу реализацию модуля, а затем по нему генерить спецификацию. Это один юзкейс. Но довольно часто бывает, что первична спецификация пакета, а его реализация вторична. Так что руками пишется в первую очередь именно спецификация, а реализация может быть даже сгенерирована автоматом (набор заглушек). Эдакие specification driven development. При групповой разработке это бывает оправдано. Я наверно примерно поровну писал на языках где спецификация и реализация разделена, и где не разделена (или спецификация генерируется по реализации), и да, действительно если писать в одиночку и небольшие программы, то в среднем удобней когда отдельной рукописной спецификации на пакет/модуль нет - банально меньше писанины. Но когда людей в проекте чуть больше, и проект сам больше, то рукописная спека (не дока, а именно спека - её понимает компилятор и на этапе компиляции проверяет соответствие реализации и спецификации) становится просто очень удобной. Поэтому например подавляющее большинство шаблонного кода в С++ мне читать не удобно - там спеку и реализацию не разделяют (хотя это возможно сделать). Да и разрабатывать в таком стиле не удобно. Та же беда с java/Go/python/js и так далее. КП с Обероном тут не одиноки. А вот Модула (и 2 и 3) и Ада - реально хороши. |
Автор: | Alexey Veselovsky [ Пятница, 10 Январь, 2014 20:14 ] |
Заголовок сообщения: | Re: Статья "Клиника плохого кода" |
Madzi писал(а): У Java есть полноценные интерфейсы. Это не те интерфейсы. |
Автор: | Madzi [ Пятница, 10 Январь, 2014 20:39 ] |
Заголовок сообщения: | Re: Статья "Клиника плохого кода" |
Alexey Veselovsky писал(а): Madzi писал(а): У Java есть полноценные интерфейсы. Это не те интерфейсы. Ну почему же не те: Код: public interface IScanner { /** * Получение очередного токена. * * @return токен */ Token getToken(); /** * Сброс сканера в исходное состояние */ void reset(); } А дальше используем в коде Код: public class Parser { private IScanner scanner; ... scanner.reset(); ... Token token = scanner.getToken(); ... } При этом можем иметь одну или несколько реализаций, которые пишем сами, либо кто-то пишет по указанному выше интерфейсу. И эти реализации можно при желании менять на лету. |
Автор: | Alexey Veselovsky [ Пятница, 10 Январь, 2014 20:41 ] |
Заголовок сообщения: | Re: Статья "Клиника плохого кода" |
Да, кстати, это была одна из причин почему я отказался от использования D. Да еще и в плюсах некоторые энтузиасты из clang хотят сделать нечто подобное, вместо нормальной модульности. Вообще это смахивает на банальную восторженную недальновидность компиляторщиков - мы теперь МОЖЕМ сделать модули без руками писанной спецификации, значит таким им и быть! Компилятору спеки больше не нужны! А то, что они (рукописные спеки) нужны в первую очередь программисту - их волнует мало. Ведь это ж фича! СМОГЛИ! Тьху! |
Автор: | Alexey Veselovsky [ Пятница, 10 Январь, 2014 20:43 ] |
Заголовок сообщения: | Re: Статья "Клиника плохого кода" |
Madzi писал(а): Alexey Veselovsky писал(а): Madzi писал(а): У Java есть полноценные интерфейсы. Это не те интерфейсы. Ну почему же не те: Код: public interface IScanner { /** * Получение очередного токена. * * @return токен */ Token getToken(); /** * Сброс сканера в исходное состояние */ void reset(); } А дальше используем в коде Код: public class Parser { private IScanner scanner; ... scanner.reset(); ... Token token = scanner.getToken(); ... } При этом можем иметь одну или несколько реализаций, которые пишем сами, либо кто-то пишет по указанному выше интерфейсу. И эти реализации можно при желании менять на лету. Во первых да, это минус - то, что их можно менять на лету (точнее - что нельзя запретить и дать гарантии что на лету их никто не подменит) Во-вторых модуль/пакет экспортирует не только функции, следовательно и спецификация не может содержать только функции. |
Автор: | Madzi [ Пятница, 10 Январь, 2014 21:35 ] |
Заголовок сообщения: | Re: Статья "Клиника плохого кода" |
Первый вопрос решаем. Хотя не вижу особых проблем, если модуль соответствует интерфейсу. Второй момент спорный. Во-первых, можно экспортировать константы. Во-вторых, нужно ли давать доступ к переменным модуля напрямую? Это ведь можно сделать через гетер/сестер. |
Автор: | Иван Кузьмицкий [ Пятница, 10 Январь, 2014 21:46 ] |
Заголовок сообщения: | Re: Статья "Клиника плохого кода" |
Alexey Veselovsky писал(а): Я уже много на эту тему писал, так что ввязываться в дискуссию не буду. Просто повторю еще раз - в некоторых случаях (например в случаях небольших программ) действительно удобней писать сразу реализацию модуля, а затем по нему генерить спецификацию. Это один юзкейс. Я прекрасно понимаю о чём речь, я сам как-то писал на Модуле. Считаю, что, во-первых, не стоит "авторитетно" утверждать вещи, которые во многом субъективны (удобно-неудобно относится в первую очередь к принятому в конторе developing style).Во-вторых, считаю, что выражаться стоит аккуратнее, а не в стиле "В обероне\КП нет того и этого", потому что прочесть можно двояко. Ну, это я больше про мимоходящих, которых сбивает с толку очередной гуру А всякие технические моменты читать и обновлять в памяти интересно, да. Так что умолкаю, извините, что вмешался |
Автор: | Info21 [ Пятница, 10 Январь, 2014 22:51 ] |
Заголовок сообщения: | Re: Статья "Клиника плохого кода" |
Alexey Veselovsky писал(а): Эдакие specification driven development. При групповой разработке это бывает оправдано. Пож., напомните, почему нельзя в качестве интерфейса модуля в таких случаях использовать (предположительно, для передачи коллеге) вариант модуля реализации с пустыми телами процедур etc.
|
Автор: | Jordan [ Воскресенье, 12 Январь, 2014 17:38 ] |
Заголовок сообщения: | Re: Статья "Клиника плохого кода" |
Статья интересная. Особенно понравился пример с реестром. Цитата: Все что должна была делать эта программка - это копировать файлы с одной Windows-машины на другую. Эта задача была решена в 80,000 строк кода на Си++ (функциональная часть) и в 55,000 строк кода на VB (GUI часть). Всё это переписали в 10 строк кода. Всё же не верю, что такое возможно. Или по мимо копирования нужно ещё, что то делать, к примеру организовать визуальное представление и оперирование файлами. Но почему гуи занимает 55 тысяч. Если поразмышлять, что могло быть написано в остальных 80 тысяч строк? Разруливание прав доступа в windows. Как я вижу задачу, пишется функция с прототипом. FileSend(куда, что, откуда передаём файл) Плюс гуи для удобства. Выбрать файл. Я понимаю, что я намеренно упрощаю. Но разговор идёт о 135 тысяч строк бессмысленного кода. |
Автор: | Alexey Veselovsky [ Воскресенье, 12 Январь, 2014 17:59 ] |
Заголовок сообщения: | Re: Статья "Клиника плохого кода" |
Jordan писал(а): Статья интересная. Особенно понравился пример с реестром. Цитата: Все что должна была делать эта программка - это копировать файлы с одной Windows-машины на другую. Эта задача была решена в 80,000 строк кода на Си++ (функциональная часть) и в 55,000 строк кода на VB (GUI часть). Всё это переписали в 10 строк кода. Всё же не верю, что такое возможно. Или по мимо копирования нужно ещё, что то делать, к примеру организовать визуальное представление и оперирование файлами. Но почему гуи занимает 55 тысяч. Если поразмышлять, что могло быть написано в остальных 80 тысяч строк? Разруливание прав доступа в windows. Как я вижу задачу, пишется функция с прототипом. FileSend(куда, что, откуда передаём файл) Плюс гуи для удобства. Выбрать файл. Я понимаю, что я намеренно упрощаю. Но разговор идёт о 135 тысяч строк бессмысленного кода. Ну представь себе, что ты хочешь абстрагироваться от хост-системы. Поэтому ты пишешь мегалибу-фреймворк, которая абстрагирует конкретные механизмы низлежащей ОСи и твоя программа становится, таким образом, кроссплатформенной. А потом ты реализуешь аж целые 10 строк кода уже конкретной задачи. Ну, грубо говоря, чтобы реализовать подобное на КП мы вначале пишем компилятор КП, пишем ББ, а затем реализуем нужную прикладную задачу. Суммарно получится явно больше 10 строк кода. Это один из вариантов когда раздувают код. То есть мелкая контора/конкретный программист вместо того чтобы решать прикладные задачи начинает лепить фреймворки да мегалибы которые, когда-нибудь, возможно, позволят сделать что-то такое, что прям ух! Кстати подобным страдают абсолютно все, вне зависимости от применяемого ЯП. Ну, разве что не страдают те, кто совсем уж на DSL пишут - они просто не могут на этом мегалибу/мегафреймворк сделать, ибо язык то узкоспециализированный и выпрыгнуть из своей песочницы никак не может. |
Автор: | Comdiv [ Понедельник, 13 Январь, 2014 12:01 ] |
Заголовок сообщения: | Re: Статья "Клиника плохого кода" |
Alexey Veselovsky писал(а): Цитата: Но былого не вернешь, и сегодня большинство пишут либо на Си++, где нет понятия модуля, либо на Java/C#, где есть некое подобие модулей, но нет деления на интерфейс и реализацию, хотя бы даже как в Си++. Либо пишут на Обероне или КП, на котором также нет деления на интерфейс и реализацию модуля, увы. (автогенерация оного интерфейса не считается - это и для java/c# есть, и это совершенно, абсолютно не то что нужно) И это правильно, в самом языке синтаксического разделения нет, но его можно сделать небольшим расширением для тех проектов компиляторов, авторы которых посчитают это нужным, никак при этом не задев основной язык. |
Автор: | Иван Кузьмицкий [ Понедельник, 13 Январь, 2014 12:38 ] |
Заголовок сообщения: | Re: Статья "Клиника плохого кода" |
Alexey Veselovsky писал(а): Это один из вариантов когда раздувают код. То есть мелкая контора/конкретный программист вместо того чтобы решать прикладные задачи начинает лепить фреймворки да мегалибы которые, когда-нибудь, возможно, позволят сделать что-то такое, что прям ух! Легко узнаваемая форма абсолютного всемогуторства, присущего многим программистам Задача подталкивает к копанию в предметной области, а когда в результате копания программер вдруг начинает хорошо видеть онтологию предметки, у него появляется вполне нормальное желание наклепать всякую-разную поддержку этой самой онтологии. Отчего бы не наклепать, когда ЯП для этого и предназначен, собс-но говоря.Alexey Veselovsky писал(а): Кстати подобным страдают абсолютно все, вне зависимости от применяемого ЯП. Ну, разве что не страдают те, кто совсем уж на DSL пишут ... Ну вот, да, а DSL уже опираются на готовые элементы онтологической инфраструктуры.
|
Автор: | Alexey Veselovsky [ Понедельник, 13 Январь, 2014 13:26 ] |
Заголовок сообщения: | Re: Статья "Клиника плохого кода" |
Иван Кузьмицкий писал(а): Alexey Veselovsky писал(а): Это один из вариантов когда раздувают код. То есть мелкая контора/конкретный программист вместо того чтобы решать прикладные задачи начинает лепить фреймворки да мегалибы которые, когда-нибудь, возможно, позволят сделать что-то такое, что прям ух! Легко узнаваемая форма абсолютного всемогуторства, присущего многим программистам Задача подталкивает к копанию в предметной области, а когда в результате копания программер вдруг начинает хорошо видеть онтологию предметки, у него появляется вполне нормальное желание наклепать всякую-разную поддержку этой самой онтологии. Отчего бы не наклепать, когда ЯП для этого и предназначен, собс-но говоря.Самое смешное, что бывает так (но это конечно не про данный пример из статьи), что предметная область сложная, там копать и копать, и нужно таки сильно вложиться в проект в интеллектуальном плане. И хорошо замотивированный программист таки вкладывается по полной. Но не в предметную область, а в ту область к которой он привык и в которой у него получается, идет по накатанной дорожке. Обычно начинает архитектуру паттернить. Ну то есть еще даже алгоритма нет (и не известно будет ли!) который будет решать задачу (скажем какую-нибудь задачу по компьютерному зрению), предметка не изучена и по сути задача не поставлена, но зато кода уже написано... МНОГО. Ибо архитектура, паттерны! Одна из форм прокрастинации, полагаю. |
Автор: | Рыжий [ Четверг, 23 Январь, 2014 01:04 ] |
Заголовок сообщения: | Re: Статья "Клиника плохого кода" |
А мне не понравилось. Пример: объект GET в Clipper-e имеет два "интерфейса" настолько отличные друг от друга по механизмам использования и ..микроскопичности..., что пропадает желание рассуждать на эту тему. Один из "интерфейсов" вполне может служить "реализацией" другого, у одного и того же объекта. Так можно легко дойти до маразма. Это разделение (если не рассматривать его, как часть семантики и синтаксиса языков конкретного типа) сугубо условно, не упирается ни во что снизу, а сверху и по бокам - только в пределы воображения авторов объекта. Можно, конечно, порассуждать об изоляции интерфейса от его реализации, только вот зачем? |
Автор: | Рыжий [ Четверг, 23 Январь, 2014 01:45 ] |
Заголовок сообщения: | Re: Статья "Клиника плохого кода" |
Jordan писал(а): Всё это переписали в 10 строк кода. Всё же не верю, что такое возможно. В две строчки можно: Цитата: net use ..... xcopy %1 %2 /Y Чистое отделение интерфейса от реализации. Батник вызывай чем хочешь. Правда там есть одна маленькая тонкость, но то все лажа. |
Страница 1 из 1 | Часовой пояс: UTC + 3 часа |
Powered by phpBB® Forum Software © phpBB Group https://www.phpbb.com/ |