Красивый код Всех приветствую. Я - админ с 12-летним стажем. Лет 10 назад писал на c++, делфи, даже ассемблере, но все успешно забыл. После этого писал только скрипты (perl, bash). Решил выучать java. При чем, качественно выучить, со всеми бестпрактисами. Пока читаю книгу по написанию "hello world", я параллельно практикуюсь - пишу программу, анализирующую состояние сервера (для aix, но это почти то же самое, что для linux). И тут возник вопрос(собственно, постановка задачи): я прочитал, что каждый метод должен помещаться на одном экране. У меня есть метод "собрать информацию с сервера". Он читает разные конфиги, запускает программы и заносит различную информацию в различные переменные(которые будут проанализированы в другом методе). Метод, мягко говоря, немаленький и я не понимаю, как правильно его уменьшить. Естественно, все второстепенное (открыть файл, распарсить в соответствии со структурой, вынутьзначение) оформлено второстепенными приватными методами. Логика метода весьма проста: 1. Получить список сетевых интерфейсов, запомнить их названия 2. Для каждого из сетевых интерфейсов получить их (список параметров) и запомнить 3. Получить список дисков ... Подскажите пожалуйста, какие есть "способы" разделить метод на более маленькие? Или в этом нет ничего страшного? Разделять "по контенту"(диски, сетевые адаптеры, ...) считаю не очень разумным: делаю ведь одно и то же. |
>Логика метода весьма проста: >1. Получить список сетевых интерфейсов, запомнить их названия >2. Для каждого из сетевых интерфейсов получить их (список параметров) и запомнить >3. Получить список дисков >... очевидно, что самые простой вариант - объявить интерфейс подобный InfoProvider<T> ** void getInfo(Callback<T> receiver) ** который и дергать в "основном методе" а получение спсика интерфейсов и их параметров в один класс реализующий сей интерфейс, для дисков другой причем там в каждом классе отдельно выделить получение списка интерфейсов, отдельно получение их параметров просто потому что все это неплохо бы оттестировать, да и наверняка некоторые вещи будет неплохо кешировать |
Сферический совет в вакууме: если хочется лучших практик, почитайте за паттерны и рефакторинг. Фаулер, Банда четырёх там, Макконнелл, всякое такое. Но аккуратно, культа не делайте. |
0-Добрых дел мастер > Т.к. нет полной картины что делает этот чудо-метод, будем крутить коня в томате. 1. Познать ООП, потому что ты пытаешься писать на bash "словами" из java. 2. Разделять и властвовать: каждый твой пункт вынести запределы метода, любым приемленмым способом. см 1 3. Пиши бейби-код, так чтоб любой сторонний человек знающий java смог быстро понять о чем речь. 4. Пиши камменты и тесты, поможет в 3 П.с. полезно смотреть код других проектов, github в помощь |
[quote=wayerr;37073244] очевидно, что самые простой вариант - объявить интерфейс подобный InfoProvider ** void getInfo(Callback receiver) ** который и дергать в "основном методе" а получение спсика интерфейсов и их параметров в один класс реализующий сей интерфейс, для дисков другой причем там в каждом классе отдельно выделить получение списка интерфейсов, отдельно получение их параметров[/quote] Главная проблема в том, что трудно провести границу между интерфейсами. Например, изучив список файловых систем, хочется понять что за диски, может быть они находятся на внешней СХД, подключенной по iSCSI, что ведет нас к изучению сетевых адаптеров... [quote=kowalski;37073370] почитайте за паттерны и рефакторинг. Фаулер, Банда четырёх там, Макконнелл, всякое такое.[/quote] Я пока-что не дочитал "Java: A Beginner's Guide". Дальше по плану - TDD. Паттерны и рефакторинг, насколько я понял, это уже на несколько уровней выше. Метаться не хочется воизбежание каши в голове, но хочется хотя бы "не укоренять самые крупные ошибки". Поэтому прочитал пару статей по рефакторингу, но вопросов возникло больше, чем ответов. [quote=40KHYTbIU;37074734]Познать ООП, потому что ты пытаешься писать на bash "словами" из java.[/quote] Есть такое. Ну почти. Раньше я писал на c++ и делфи, так что слова class и try..catch мне знакомы. [quote=40KHYTbIU;37074734]3. Пиши бейби-код, так чтоб любой сторонний человек знающий java смог быстро понять о чем речь.[/quote] А что такое бейби-код? Гугл ничего не сказал. |
>Главная проблема в том, что трудно провести границу между интерфейсами. это не проблема красоты кода, а проблема проектирования |
Рефакторинг... Скока раз порывался свой код улучшить, а то и переписать заново. Вынести нящки в классы, функции, развернуть свой git-реп итд. Став "нассяльника" - пытался заставить сделать это подчиненных. Короче... - это несбыточно. Работает - и фиг с ним. Не надо ничего уменьшать, ведь и художники бывают многословными... |
[quote=wayerr;37077135]это не проблема красоты кода, а проблема проектирования [/quote] а есть что-нибудь короткое, где описано, как правильно проектировать приложение? Нормальные книги я, конечно, прочту, но это будет позже. [quote=economist;37077941]Короче... - это несбыточно. Работает - и фиг с ним. Не надо ничего уменьшать, ведь и художники бывают многословными... [/quote] Так речь не о рефакторинге, а о том, чтобы сразу учиться хорошему. |
>а есть что-нибудь короткое, где описано, как правильно проектировать приложение? не встречал, можно почитать про базовые ошибки напр. тут [url]https://ru.wikipedia.org/wiki/Антипаттерн#.D0.90.D0.BD.D1.82.D0.B8.D0.BF.D0.B0.D1.82.D1.82.D0.B5.D1.80.D0.BD.D1.8B_.D0.B2_.D0.BF.D1.80.D0.BE.D0.B5.D0.BA.D1.82.D0.B8.D1.80.D0.BE.D0.B2.D0.B0.D0.BD.D0.B8.D0.B8_.D0.9F.D0.9E[/url] но там все описано уже затейливое терминологогией |
> Скока раз порывался свой код улучшить, а то и переписать заново. Вынести нящки в классы, функции, развернуть свой git-реп итд. Став "нассяльника" - пытался заставить сделать это подчиненных. ээ, да вам нужны Программисты, а не программисты, может даже тимлид просто нормальный который таки умеет рефакторить код, ведь это тривиально. |
6-economist >Плюсану, идеального кода нет. Если код работает годами и заказчик доволен работой, то это и есть идеальный код. И пофигу как там внутри. Потом, как часто бывает, заказали одно, потом резко под конец решили что-то поменять, а сроки оставили прежними. И вот какой тут будет идеальный код можете догадаться. |
>И пофигу как там внутри. потому в краснодаре и нет софтверных контор, некоторые даже без VCS работают |
[quote=wayerr;37079087]не встречал, можно почитать про базовые ошибки напр. тут [url]https://ru.wikipedia.org/wiki/Антипа...8_.D0.9F.D0.9E[/url] но там все описано уже затейливое терминологогией [/quote] Очень непонятно описано. Но ладно, поищу что-нибудь. [quote=ipp;37079591]люсану, идеального кода нет. Если код работает годами и заказчик доволен работой, то это и есть идеальный код. [/quote] Как я писал выше, дело ведь не в результате, а в обучении. Наговнокодить я всегда успею, но хотя бы стремиться я должен к чему-то правильному. |
>Очень непонятно описано ну я говорил про терминологию, кроме того там одно и тоже разными словами упоминается, и есть вещи верные только в контексте (а не всегда) в случае : >Логика метода весьма проста: >1. Получить список сетевых интерфейсов, запомнить их названия >2. Для каждого из сетевых интерфейсов получить их (список параметров) и запомнить >3. Получить список дисков основной косяк - это то что логически разные вещи делаются в одном методе, но это я уже повторяюсь, и ты сам упоминаешь три пункта, т.е. понимаешь, что это разные задачи. так хороший код для того кто думает процедурами будет (вместо одного метода): netdevs = get_networking_devices(); for(dev: netdevs) ** __attrr = get_netdevice_attrs(dev); __save_attrs(dev, attrr) ** strdevs = get_storage_devices(); for(dev: strdevs) ** __get_storage_attrs(dev); ** школьники только постигшие ооп, напишут так netdevs = NetDevsService.list(); for(dev: netdevs) ** __attrr = dev.getAttrs(); __PeristentService.save(dev, attrr) ** strdevs = StorageService.list(); for(dev: strdevs) ** __attrr = dev.getAttrs(); ** более опытные индусы будут получать "сервисы" через IoC контейнер и накрутят интерфейсов |
да, это будет лучше чем один жЫрный метод, но все равно не идеал, просто потому что сервисы получающие список устройств в принципе можно объединить одним интерфейсом, и перечислять их в цикле, т.к. в некоторых случаях они могут быть не в виде линейного списка, а в виде дерева\иерархии (usb устройства, контроллер-диск-разделы, или контроллер-диски и контроллер-рейд-разделы) то перечислять их стоит в колбек (для примитивных языков программирования тут вылезает паттерн visitor) и куча других тонкостей, это все требует вдумчивого подхода к проектированию, анализа требований (в т.ч. к отображению результатов) и т.п. |
Даже не знаю. Я попробую, сравню... в этом ведь суть обучения... Дело в том, что я не считаю эти задачи такими уж разными. Это всего-лишь сбор данных. Мне кажется, если я буду отдельно реализовывать методы для каждой отдельной железки - будет намного больше дублированного кода. Но я попробую. |
>методы для каждой отдельной железки суть была не в этом |
15-Добрых дел мастер >Жирный метод желательно конечно разбить. [quote] Мне кажется, если я буду отдельно реализовывать методы для каждой отдельной железки - будет намного больше дублированного кода. [/quote] Не плоди сущностей больше чем необходимо. А многократное дублирование кода - это еще большее зло, так как при изменениях обязательно где нибудь что нибудь забудешь обновить. Но, если хочется можешь создать некий базовый класс и в нем реализовать нечто общее для всех, а далее создать наследников от него для каждой железяки с учетом ее особенностей. А можно объявить простой интерфейс для работы с железякой, а потом просто в классах для работы с конкретной железякой реализовывать поддержку этого интерфейса. А тот кто захочет получить инфу о железяке будет использовать этот интерфейс для работы. Только при объявлении интерфейса не переборщи, это должно быть нечто простое и понятное. |
0-Добрых дел мастер > "[em]я прочитал, что каждый метод должен помещаться на одном экране. [/em]" - теория хорошая штука, но не стоит воспринимать ее буквально, как многие местные гуру. :) |
Текущее время: 04:36. Часовой пояс GMT +3. |