Яку стратегію ви використовуєте для іменування пакетів у проектах Java і чому? [зачинено]


88

Я думав про це деякий час тому, і нещодавно він знову з’явився, коли мій магазин робить свою першу справжню веб-програму Java.

Як вступ, я бачу дві основні стратегії іменування пакетів. (Щоб бути зрозумілим, я не маю на увазі всю частину цього "domain.company.project", я говорю про умову пакета під нею.) У будь-якому випадку, я бачу наступні правила іменування пакетів:

  1. Функціональні: Присвоєння імен вашим пакетам відповідно до їх архітектурної функції, а не від ідентичності відповідно до ділового домену. Іншим терміном для цього може бути найменування відповідно до "шару". Отже, у вас буде пакет * .ui та * .domain та * .orm пакет. Ваші пакунки - це горизонтальні фрагменти, а не вертикальні.

    Це набагато частіше, ніж логічне іменування. Насправді, я не вірю, що коли-небудь бачив або чув про проект, який це робить. Звичайно, це змушує мене скупити (щось на зразок думки, що ти придумав рішення проблеми NP), оскільки я не дуже розумний, і я припускаю, що кожен повинен мати серйозні причини робити це так, як це робить. З іншого боку, я не проти, щоб люди просто сумували за слоном у кімнаті, і я ніколи не чув реального аргументу для того, щоб робити імена пакетів таким чином. Це, здається, фактично стандарт.

  2. Логічно: присвоєння імен вашим пакетам відповідно до ідентичності їх бізнес-домену та включення кожного класу, який пов’язаний із цим вертикальним фрагментом функціональності, до цього пакету.

    Я ніколи не бачив і не чув про це, як я вже згадував раніше, але для мене це має сенс.

    1. Я схильний підходити до систем вертикально, а не горизонтально. Я хочу зайнятися розробкою системи обробки замовлень, а не рівня доступу до даних. Очевидно, є велика ймовірність, що я торкнуся рівня доступу до даних при розробці цієї системи, але справа в тому, що я не думаю про це так. Що це означає, звичайно, це те, що коли я отримую замовлення на зміну або хочу впровадити якусь нову функцію, було б непогано, коли б не довелося їздити на риболовлі в купу пакетів, щоб знайти всі пов’язані класи. Натомість я просто заглядаю в пакет X, тому що те, що я роблю, пов’язане з X.

    2. З точки зору розвитку, я розглядаю як головний виграш, якщо ваші пакети документують ваш бізнес-домен, а не вашу архітектуру. Я відчуваю, що домен - це майже завжди та частина системи, яку важче продирати, де, оскільки архітектура системи, особливо на даний момент, стає майже повсякденною у її реалізації. Той факт, що я можу прийти до системи з таким типом домовленостей про іменування, і миттєво з іменування пакетів знаю, що вона має справу із замовленнями, клієнтами, підприємствами, продуктами тощо, здається надзвичайно зручним.

    3. Здається, це дозволить вам набагато краще скористатися модифікаторами доступу Java. Це дозволяє набагато чіткіше визначати інтерфейси в підсистемах, а не в рівнях системи. Отже, якщо у вас є підсистема замовлень, яка хоче бути прозорою стійкою, теоретично ви ніколи не могли б повідомити нічому іншому, що вона стійка, не створюючи загальнодоступних інтерфейсів до своїх класів стійкості на рівні дао, а замість цього упаковуючи клас дао в лише з класами, якими він займається. Очевидно, що якщо ви хочете розкрити цю функціональність, ви можете надати для неї інтерфейс або зробити її загальнодоступною. Просто здається, що ви втрачаєте багато цього, маючи вертикальний зріз функцій вашої системи, розділений на кілька пакетів.

    4. Я припускаю, що одним недоліком, який я бачу, є те, що він ускладнює виривання шарів. Замість того, щоб просто видалити або перейменувати пакет, а потім скинути новий на місце за допомогою альтернативної технології, вам доведеться зайти і змінити всі класи у всіх пакетах. Однак я не бачу, що це велика справа. Можливо, це пов’язано з відсутністю досвіду, але я повинен уявити, що кількість разів, коли ви замінюєте технології, блідне порівняно з тим, скільки разів ви входите та редагуєте вертикальні фрагменти об’єктів у вашій системі.

Тож я думаю, тоді питання постане перед вами, як ви називаєте свої пакунки і чому? Зрозумійте, будь-ласка, я не обов’язково думаю, що тут я натрапив на золоту гуску. Я досить новий у всьому цьому з переважно академічним досвідом. Однак я не можу помітити дірок у своїх міркуваннях, тому сподіваюся, що ви всі можете, щоб я міг рухатися далі.


Те, що я чув до цього часу, мабуть, свідчить про те, що це свого роду виклик суду. Однак більшість відповідей не зосереджуються на практичних міркуваннях. Це більше те, що я шукаю. Однак дякую за допомогу!
Тім Вішер,

Я не думаю, що це вирок. Спочатку поділ за шаром, а потім за функціональністю - це, безумовно, шлях. Я оновлюю свою відповідь.
eljenso

@eljenso: скажіть це хлопцям із Eclipse :) У eclipse перший розділ - це "особливості", які є одиницями розгортання, а також функціональністю. Усередині "функції" є "плагіни", які, як правило, поділяються за шарами, але плагіни всередині однієї "функції" завжди повинні бути розгорнуті разом. Якщо у вас є лише один блок розгортання, тоді поділ спочатку на шар, а потім лише на функціонал може мати сенс. З кількома модулями розгортання ви не хочете розгортати лише презентаційний шар - вам потрібна додаткова функціональна можливість.
Peter Štibraný

У мене є конкретне запитання стосовно бізнес-рівня програми, якою має бути конвенція про іменування?
Bionix1441

Відповіді:


32

Що стосується дизайну упаковки, я спочатку поділяю по шару, потім за якоюсь іншою функціональністю.

Існує кілька додаткових правил:

  1. шари складаються від найбільш загальних (знизу) до найбільш конкретних (зверху)
  2. кожен шар має загальнодоступний інтерфейс (абстракція)
  3. шар може залежати лише від загальнодоступного інтерфейсу іншого шару (інкапсуляція)
  4. шар може залежати лише від більш загальних шарів (залежності зверху вниз)
  5. шар переважно залежить від шару безпосередньо під ним

Отже, для веб-програми, наприклад, ви можете мати такі рівні на рівні програми (зверху вниз):

  • презентаційний рівень: генерує інтерфейс, який буде відображатися на рівні клієнта
  • прикладний рівень: містить логіку, яка є специфічною для програми, має статус
  • сервісний рівень: групує функціональність за доменом, без громадянства
  • рівень інтеграції: забезпечує доступ до серверного рівня (db, jms, email, ...)

Для отриманого макета пакунку, це деякі додаткові правила:

  • корінь кожного імені пакета - <prefix.company>.<appname>.<layer>
  • інтерфейс шару додатково розділений за функціональністю: <root>.<logic>
  • приватна реалізація шару має префікс private: <root>.private

Ось приклад макета.

Презентаційний рівень розділений за технологією перегляду та, за бажанням, (за групами) додатків.

com.company.appname.presentation.internal
com.company.appname.presentation.springmvc.product
com.company.appname.presentation.servlet
...

Рівень програми розділений на варіанти використання.

com.company.appname.application.lookupproduct
com.company.appname.application.internal.lookupproduct
com.company.appname.application.editclient
com.company.appname.application.internal.editclient
...

Сервісний рівень розділений на бізнес-домени, на які впливає логіка домену в серверному рівні.

com.company.appname.service.clientservice
com.company.appname.service.internal.jmsclientservice
com.company.appname.service.internal.xmlclientservice
com.company.appname.service.productservice
...

Рівень інтеграції поділяється на "технології" та об'єкти доступу.

com.company.appname.integration.jmsgateway
com.company.appname.integration.internal.mqjmsgateway
com.company.appname.integration.productdao
com.company.appname.integration.internal.dbproductdao
com.company.appname.integration.internal.mockproductdao
...

Переваги поділу пакунків, як цей, полягають у тому, що простіше управляти складністю, а це збільшує перевірочність та повторне використання. Хоча це здається великою кількістю накладних витрат, на мій досвід це насправді дуже природно, і кожен, хто працює над цією структурою (або подібною), бере її за лічені дні.

Чому я вважаю, що вертикальний підхід не такий хороший?

У багатошаровій моделі кілька різних модулів високого рівня можуть використовувати один і той же модуль нижчого рівня. Наприклад: ви можете побудувати кілька подань для одного додатка, кілька програм можуть використовувати одну і ту ж службу, кілька служб можуть використовувати один і той же шлюз. Фокус тут полягає в тому, що при переміщенні по шарах рівень функціональності змінюється. Модулі в більш конкретних шарах не відображають 1-1 на модулях із більш загального шару, оскільки рівні функціональності, які вони виражають, не відображають 1-1.

Коли ви використовуєте вертикальний підхід для дизайну упаковки, тобто спочатку ви ділитеся за функціональністю, тоді ви змушуєте всі будівельні блоки з різними рівнями функціональності в одну і ту ж «функціональну оболонку». Ви можете розробити свої загальні модулі для більш конкретного. Але це порушує важливий принцип, що більш загальний шар не повинен знати про більш конкретні шари. Наприклад, сервісний рівень не повинен моделюватися на основі концепцій рівня додатків.


"Переваги поділу пакунків, подібних до цього, полягають у тому, що простіше управляти складністю, а це підвищує перевірочність і повторне використання". Ви справді не вникаєте в причини, чому це так.
mangoDrunk

1
Ви не вникаєте в причини, чому це не так. Але як би там не було ... правила організації досить чіткі та зрозумілі, тому це зменшує складність. Це більш перевіряється та багаторазове використання через саму організацію. Кожен може спробувати, а згодом ми можемо погодитися чи не погодитися. Я коротко пояснюю деякі недоліки вертикального підходу, неявно вказуючи причини, чому, на мою думку, горизонтальний підхід простіший.
eljenso

8
Ця стаття цілком приємно пояснює, чому краще використовувати пакет за функцією, а не пакет за шаром .
Том,

@eljenso "Ви не вникаєте в причини, чому це не так", намагаючись перекласти тягар доказування? Я думаю, що стаття, опублікована Томом, дуже гарно пояснює, чому пакетна функція краща, і мені важко сприймати "Я не думаю, що це виклик судження. Спочатку поділ на рівень, а потім за функціональністю, безумовно, спосіб йти "серйозно.
pka

18

Я відчуваю, що дотримуюся принципів дизайну упаковки дядька Боба . Коротше кажучи, класи, які слід повторно використовувати разом і змінювати разом (з тієї ж причини, наприклад, зміна залежності або зміна фреймворку), слід помістити в один і той же пакет. ІМО, функціональний розподіл мав би більше шансів досягти цих цілей, ніж вертикальний / бізнес-розподіл у більшості додатків.

Наприклад, горизонтальний зріз об’єктів домену може бути повторно використаний різними видами інтерфейсів або навіть програм, і горизонтальний зріз інтерфейсу веб-інтерфейсу, ймовірно, зміниться разом, коли потрібно змінити базовий веб-фреймворк. З іншого боку, легко уявити ефект пульсацій цих змін у багатьох пакетах, якщо класи в різних функціональних областях згруповані в цих пакетах.

Очевидно, що не всі види програмного забезпечення однакові, і вертикальний розподіл може мати сенс (з точки зору досягнення цілей повторного використання та близькості до змін) у певних проектах.


Дякую, це дуже зрозуміло. Як я вже сказав у питанні, я відчуваю, що кількість випадків, коли ви замінюєте технології, набагато менше, ніж ви б переходили навколо вертикальних фрагментів функціональності. Чи це не був ваш досвід?
Тім Вішер,

Справа не лише в технологіях. Пункт №1 вашого оригінального допису має сенс лише у тому випадку, якщо вертикальні зрізи є незалежними програмами / службами, що взаємодіють між собою через якийсь інтерфейс (SOA, якщо хочете). далі нижче ...
Буу Нгуєн

Тепер, коли ви переходите до деталей кожного з тих детальних додатків / сервісів, які мають свій власний графічний інтерфейс / бізнес / дані, я навряд чи уявляю, що зміни у вертикальному зрізі, будь то технологія, залежність, правило / робочий процес, реєстрація , безпека, стиль інтерфейсу, може бути повністю ізольований від інших фрагментів.
Буу Нгуєн

Мені буде цікаво ваш відгук про мою відповідь
i3ensays

@BuuNguyen Посилання на принципи дизайну упаковки порушено.
johnnieb

5

Зазвичай є обидва рівні поділу. Зверху є підрозділи розгортання. Вони називаються "логічно" (по-вашому, подумайте про функції Eclipse). Усередині модуля розгортання у вас функціональний розподіл пакетів (думаю, плагіни Eclipse).

Наприклад, функція є com.feature, і вона складається з com.feature.client, com.feature.coreі com.feature.uiплагінів. Всередині плагінів у мене дуже мало поділу на інші пакети, хоча це теж незвично.

Оновлення: До речі, Юрген Холлер чудово розповідає про організацію коду на InfoQ: http://www.infoq.com/presentations/code-organization-large-projects . Юрген - один з архітекторів Spring, і він знає багато про це.


Я не зовсім слідую. Зазвичай ви можете побачити com.apache.wicket.x, де x є функціональним або логічним. Зазвичай я не бачу com.x. Думаю, ви кажете, що хотіли б використовувати структуру com.company.project.feature.layer? У вас є причини?
Тім Вішер,

Причина полягає в тому, що "com.company.project.feature" - це одиниця розгортання. На цьому рівні деякі функції є необов’язковими і можуть бути пропущені (тобто не розгорнуті). Однак усередині функції все не є необов’язковим, і ви, як правило, хочете, щоб усі вони були. Тут є сенс пірнати по шарах.
Peter Štibraný

4

Більшість java-проектів, над якими я працював, спочатку нарізають пакети java функціонально, а потім логічно.

Зазвичай частини є досить великими, щоб їх можна було розбити на окремі артефакти збірки, де ви можете помістити основні функціональні можливості в одну банку, apis в іншу, веб-інтерфейс у військовий файл тощо.


Як це може виглядати? domain.company.project.function.logicalSlice?
Тім Вішер,

достатньо! egdcpweb.profiles, dcpweb.registration, dcpapis, dcppersistence тощо, як правило, працює досить добре, ваш пробіг може відрізнятися. залежить також, якщо ви використовуєте моделювання доменів - якщо у вас кілька доменів, можливо, вам спочатку потрібно розділити за доменами.
Бен Харді,

Я особисто віддаю перевагу протилежному, логічному тоді функціональному. яблука.rpc, яблука.модель, а потім банан.модель, банан.магазин
.

Існує більша цінність у можливості згрупувати всі яблучні речі разом, ніж групувати всі веб-матеріали разом.
мП.

3

Пакети повинні бути складені та розподілені як цілісні одиниці. Розглядаючи, які класи належать до пакету, одним із ключових критеріїв є його залежності. Від яких інших пакетів (включаючи сторонні бібліотеки) залежить цей клас. Добре організована система буде кластеризувати класи з подібними залежностями в пакеті. Це обмежує вплив зміни в одній бібліотеці, оскільки від неї буде залежати лише кілька чітко визначених пакетів.

Схоже, ваша логічна, вертикальна система може мати тенденцію "розмивати" залежності у більшості пакунків. Тобто, якщо кожна функція упакована як вертикальний зріз, кожен пакет буде залежати від кожної сторонній бібліотеки, яку ви використовуєте. Будь-яка зміна бібліотеки, швидше за все, розіб’є всю вашу систему.


Ага. Отже, одне, що робить горизонтальні зрізи, це захищати вас від реальних оновлень у використовуваних вами бібліотеках. Я думаю, ви маєте рацію, що вертикальні зрізи змащують кожну залежність вашої системи у кожному пакунку. Чому це така велика справа?
Тім Вішер,

Для "функції" це не така вже й велика проблема. Вони, як правило, більш мінливі і в будь-якому випадку мають більше залежностей. З іншого боку, цей "клієнтський" код, як правило, має низький рівень повторного використання. Для чогось, що ви маєте намір бути багаторазовою бібліотекою, ізолювати клієнтів від кожної незначної зміни є чудовою інвестицією.
erickson

3

Я особисто віддаю перевагу групуванню класів логічно, тоді всередині цього є підпакет для кожної функціональної участі.

Цілі упаковки

Зрештою, пакети стосуються групування речей - ідея пов’язаних класів живе близько один до одного. Якщо вони живуть в одному пакеті, вони можуть скористатися приватним пакетом, щоб обмежити видимість. Проблема полягає в об’єднанні всього вашого зору та постійних матеріалів в один пакет, що може призвести до того, що багато класів змішаться в одному пакеті. Наступне розумне, що слід зробити, - це, відповідно, створити подання, стійкість, підпакети util та класи рефактора. На жаль, захищений приватний приціл та захист пакета не підтримує концепцію поточного пакета та підпакета, оскільки це допоможе забезпечити виконання таких правил видимості.

Зараз я бачу цінність у розділенні за допомогою функціональних можливостей, оскільки це має значення для групування всіх матеріалів, пов’язаних із видом. Речі у цій стратегії іменування перериваються з деякими класами, у той час як інші залишаються наполегливими тощо.

Приклад моєї логічної структури упаковки

Для ілюстрації давайте назвемо два модулі - не використовуйте модуль імен як концепцію, яка групує класи під певною гілкою дерева пакету.

apple.model apple.store banana.model banana.store

Переваги

Клієнт, що використовує Banana.store.BananaStore, має лише ті функції, які ми хочемо зробити доступними. Версія сплячого режиму - це деталь реалізації, про яку їм не потрібно знати, і вони не повинні бачити ці класи, оскільки вони створюють безлад у операціях зберігання.

Інші логічні v Функціональні переваги

Чим далі до кореня, тим ширшим стає обсяг, і речі, що належать до одного пакету, починають проявляти все більше і більше залежностей від речей, що належать до інших модулів. Якби хтось вивчав, наприклад, модуль "банан", більшість залежностей були б обмежені цим модулем. Насправді на більшість помічників під "бананом" взагалі не буде посилання поза межами цього пакету.

Чому саме функціональність?

Якого значення можна досягти, поєднуючи речі на основі функціональності. Більшість класів у такому випадку не залежать один від одного, мало або зовсім не потрібно використовувати переваги пакетних приватних методів або класів. Рефакторинг їх у власні підпакети мало приносить користь, але допомагає зменшити безлад.

Зміни розробника до системи

Коли розробникам доручається внести зміни, які є трохи більш ніж тривіальними, здається безглуздим, що потенційно вони мають зміни, які включають файли з усіх областей дерева пакетів. З логічним структурованим підходом їх зміни є більш локальними в тій самій частині дерева пакетів, що просто здається правильним.


"Коли розробники [...] файли з усіх областей дерева пакетів." Ви маєте рацію, коли говорите, що це здається дурним. Тому що саме в цьому полягає сенс належного нанесення шарів: зміни не хвилюються по всій структурі програми.
eljenso

Дякую за пораду. Я не впевнений, що я вас чітко розумію. Я вважаю, що ви намагаєтеся сперечатися за логічні пакети, я не зовсім зрозумів, чому. Чи не могли б ви спробувати зробити свою відповідь трохи чіткішою, можливо, переформулюючи? Дякую!
Тім Вішер

3

Як функціональний (архітектурний), так і логічний (функціональний) підходи до упаковки мають місце. Багато прикладних програм (тих, що містяться в підручниках тощо) дотримуються функціонального підходу до розміщення презентацій, бізнес-послуг, картографування даних та інших архітектурних шарів в окремі пакети. У прикладах програм кожен пакет часто має лише кілька або лише один клас.

Цей початковий підхід чудовий, оскільки надуманий приклад часто служить для: 1) концептуального відображення архітектури представленого фреймворку, 2) робиться з однією логічною метою (наприклад, додавання / видалення / оновлення / видалення домашніх тварин з клініки) . Проблема в тому, що багато читачів сприймають це як стандарт, який не має меж.

У міру розширення програми для бізнесу, яка включає все більше і більше можливостей, дотримання функціонального підходу стає тягарем. Хоча я знаю, де шукати типи на основі архітектурного рівня (наприклад, веб-контролери під пакетом "web" або "ui" тощо), розробка єдиної логічної функції починає вимагати переходу між багатьма пакунками. Це, як мінімум, громіздко, але гірше, ніж це.

Оскільки логічно пов’язані типи не упаковуються разом, API надмірно розголошується; взаємодія між логічно пов’язаними типами змушена бути „загальнодоступною”, щоб типи могли імпортувати та взаємодіяти один з одним (втрачається можливість мінімізації до стандартної / видимості пакета).

Якщо я будую фреймворкову бібліотеку, мої пакети неодмінно дотримуватимуться функціонального / архітектурного підходу до упаковки. Мої споживачі API можуть навіть зрозуміти, що їх оператори імпорту містять інтуїтивно зрозумілий пакет, названий на честь архітектури.

І навпаки, при створенні бізнес-додатків я буду упаковувати за функціями. У мене немає проблем із розміщенням Widget, WidgetService та WidgetController в одному пакеті " com.myorg.widget. ", А потім скористатися перевагами стандартної видимості (і мати менше операторів імпорту, а також залежностей між пакетами).

Однак є випадки перехресного перетину. Якщо мій WidgetService використовується багатьма логічними доменами (функціями), я можу створити пакет " com.myorg.common.service. ". Існує також велика ймовірність, що я створюю класи з метою повторного використання в різних функціях і в кінцевому підсумку отримую пакети, такі як " com.myorg.common.ui.helpers. " Та " com.myorg.common.util. ". Можливо, я в кінцевому підсумку перекладу всі ці пізніші "загальні" класи в окремий проект і включу їх до свого бізнес-додатку як залежність myorg-commons.jar.


2

Це залежить від деталізації ваших логічних процесів?

Якщо вони автономні, у вас часто є новий проект для них у керуванні джерелами, а не новий пакет.

Проект, яким я займаюся на даний момент, помиляється щодо логічного розбиття, є пакет для аспекту jython, пакет для механізму правил, пакети для foo, bar, binglewozzle тощо. Я розглядаю наявність синтаксичних аналізаторів XML / Writers для кожного модуля в цьому пакеті, а не мати пакет XML (що я вже робив раніше), хоча все одно буде основний пакет XML, куди йде спільна логіка. Однак однією з причин цього є те, що він може бути розширюваним (плагіни), і, отже, кожному плагіну також потрібно буде визначити свій код XML (або бази даних тощо), тому централізація цього може призвести до проблем пізніше.

Врешті-решт здається, що це найбільш доцільно для конкретного проекту. Я думаю, що це легко упакувати відповідно до типової багаторівневої діаграми проекту. У підсумку ви отримаєте поєднання логічної та функціональної упаковки.

Що потрібно, це теговані простори імен. Синтаксичний аналізатор XML для деяких функцій Jython міг би бути позначений як Jython, так і XML, замість того, щоб обирати той чи інший.

А може, я і дрибу.


Я не повністю розумію вашу думку. Я думаю, що ви кажете, що ви просто повинні робити те, що має найбільший сенс для вашого проекту і для вас, що логічно, якщо вкласти трохи функціоналу. Чи є для цього конкретні практичні причини?
Тім Вішер,

Як я вже говорив, у мене будуть плагіни для розширення вбудованої функціональності. Плагін повинен мати можливість аналізу і запису свого XML (і, зрештою, в БД), а також забезпечити функціональність. Тому чи маю я com.xx.feature.xml чи com.xx.xml.feature? Перший здається охайнішим.
JeeBee

2

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

Для мене це набагато простіше підтримувати та візуалізувати у вертикальній системі імен, а не в горизонтальній. якщо component1.display має посилання на component2.dataaccess, що видає більше попереджувальних дзвонів, ніж якщо display.component1 має посилання на dataaccess. компонент2.

Звичайно, компоненти, якими користуються обидва, йдуть у власному пакеті.


Як я вас тоді розумію, ви виступатимете за конвенцію про вертикальні імена. Я думаю, саме для цього призначений пакет * .utils, коли вам потрібен клас із кількох зрізів.
Тім Вішер,

2

Я повністю дотримуюсь і пропоную логічну ("побічну особливість") організацію! Пакет повинен якомога точніше відповідати поняттю "модуль". Функціональна організація може поширити модуль на проект, що призведе до меншої інкапсуляції та схильності до змін у деталях реалізації.

Візьмемо для прикладу плагін Eclipse: розміщення всіх поглядів або дій в одному пакеті було б безладом. Натомість кожен компонент функції повинен переходити до пакету функції або, якщо їх багато, у підпакети (featureA.handlers, featureA.preferences тощо)

Звичайно, проблема полягає в ієрархічній системі пакетів (яку серед інших має Java), що робить обробку ортогональних проблем неможливим або принаймні дуже складним - хоча вони трапляються скрізь!


1

Я особисто піду на функціональне іменування. Коротка причина: це дозволяє уникнути дублювання коду або кошмару залежностей.

Дозвольте трохи детальніше розповісти. Що відбувається, коли ви використовуєте зовнішній файл jar зі своїм власним деревом пакунків? Ви ефективно імпортуєте (скомпільований) код у свій проект, а разом із ним і (функціонально відокремлене) дерево пакетів. Чи було б сенсом використовувати дві конвенції іменування одночасно? Ні, хіба що це було приховано від вас. І воно є, якщо ваш проект досить малий і має одну складову. Але якщо у вас кілька логічних одиниць, ви, мабуть, не хочете повторно реалізовувати, скажімо, модуль завантаження файлу даних. Ви хочете поділитися нею між логічними одиницями, не мати штучних залежностей між логічно не пов’язаними одиницями та не потрібно вибирати, в яку одиницю ви збираєтесь вкласти цей конкретний спільний інструмент.

Я думаю, саме тому функціональне іменування найбільш часто використовується в проектах, які досягають або мають на меті досягти певного розміру, а логічне іменування використовується в конвенціях щодо імен класів для відстеження конкретної ролі, якщо яка-небудь із кожного класу в пакет.

Я спробую більш точно відповісти на кожну з ваших точок щодо логічного іменування.

  1. Якщо вам доведеться їздити на риболовлю в старих класах, щоб змінити функціональні можливості при зміні планів, це ознака поганої абстракції: вам слід побудувати класи, які забезпечують чітко визначену функціональність, яку можна визначити одним коротким реченням. Лише кілька класів вищого рівня повинні зібрати все це, щоб відобразити ваш бізнес-інтелект. Таким чином, ви зможете повторно використовувати більше коду, мати простіше обслуговування, чіткішу документацію та менше проблем із залежністю.

  2. Це головним чином залежить від способу вивчення вашого проекту. Безумовно, логічний та функціональний вигляд є ортогональними. Отже, якщо ви використовуєте одну конвенцію іменування, вам потрібно застосувати іншу до імен класів, щоб зберегти певний порядок або перейти від однієї конвенції іменування до іншої на певній глибині.

  3. Модифікатори доступу - це хороший спосіб дозволити іншим класам, які розуміють вашу обробку, отримати доступ до внутрішніх елементів вашого класу. Логічні відносини не означають розуміння алгоритмічних обмежень або обмежень одночасності. Функціональний може, хоча ні. Я дуже втомився від модифікаторів доступу, крім загальнодоступних та приватних, оскільки вони часто приховують відсутність належної архітектури та абстракції класів.

  4. У великих комерційних проектах зміна технологій відбувається частіше, ніж можна було б повірити. Наприклад, мені довелося змінити вже 3 рази синтаксичний аналізатор XML, 2 рази технологію кешування та 2 рази програмне забезпечення для геолокалізації. Добре, що я заховав усі дрібні деталі у спеціальному пакеті ...


1
Пробачте мене, якщо я помиляюся, але мені здається, що ви більше говорите про розробку фреймворку, призначеного для використання багатьма людьми. Я думаю, що правила змінюються між цим типом розробки та розробкою систем кінцевих користувачів. Я помиляюся?
Тім Вішер,

Думаю, для загальних класів, що використовуються багатьма вертикальними зрізами, має сенс мати щось на зразок utilsпакету. Тоді будь-які класи, яким це потрібно, можуть просто залежати від цього пакету.
Тім Вішер,

Знову ж таки, розмір має значення: коли проект стає досить великим, його повинні підтримувати кілька людей, і відбудеться якась спеціалізація. Щоб полегшити взаємодію та запобігти помилкам, сегментація проекту на частини стає швидко необхідною. І пакет utils скоро стане величезним!
Varkhan

1

Цікавий експеримент - взагалі не використовувати пакети (за винятком кореневого пакета).

Тоді виникає питання, коли і чому має сенс вводити пакети. Імовірно, відповідь буде іншою, ніж відповідь, яку ви відповіли б на початку проекту.

Я припускаю, що ваше питання взагалі виникає, тому що пакети схожі на категорії, і іноді важко визначитися з тим чи іншим. Іноді теги були б більш вдячні, коли повідомляли, що клас можна використовувати в багатьох контекстах.


0

З чисто практичної точки зору конструкції видимості Java дозволяють класам в одному пакеті отримувати доступ до методів та властивостей за допомогою protectedі defaultвидимості, а також доpublic тих. Використання непублічних методів із зовсім іншого шару коду, безумовно, було б великим запахом коду. Тому я схильний поміщати класи з одного шару в один пакет.

Я часто не використовую ці захищені методи або методи за замовчуванням деінде - крім можливо, в модульних тестах для класу, - але коли я використовую, це завжди з класу на тому самому рівні


Хіба це не щось із природи багатошарових систем, щоб завжди залежати від наступного шару вниз? Наприклад, користувальницький інтерфейс залежить від рівня ваших послуг, який залежить від рівня вашого домену тощо. Упаковка вертикальних зрізів разом, здається, захищає від надмірних залежностей між пакетами, ні?
Тім Вішер,

Я майже ніколи не використовую захищені методи та методи за замовчуванням. 99% є державними чи приватними. Деякі винятки: (1) видимість за замовчуванням для методів, що використовуються лише модульними тестами, (2) захищений абстрактний метод, який використовується лише з абстрактного базового класу.
Еско Луонтола

1
Тім Вішер, залежності між пакунками не є проблемою, якщо залежності завжди спрямовані в одному напрямку і на графіку залежностей немає циклів.
Еско Луонтола

0

Це залежить. У моєму напрямі роботи ми іноді розділяємо пакети за функціями (доступ до даних, аналітика) або за класом активів (кредит, акції, процентні ставки). Просто виберіть структуру, яка є найбільш зручною для вашої команди.


Чи є якась причина піти в будь-який бік?
Тім Вішер,

Розбиття за класом активів (загальніше: за діловим доменом) полегшує новим людям шлях до коду. Розбиття за функціями добре для інкапсуляції. Для мене доступ до "пакета" в Java подібний до "друга" в C ++.
quant_dev

@quant_dev Я не погоджуюся з "..by функція хороша для інкапсуляції". Я думаю, ви маєте на увазі повну протилежність. Крім того, не просто вибирайте з «зручності». Для кожного є свій випадок (див. Мою відповідь).
i3ensays

-3

З мого досвіду, повторне використання більше створює більше проблем, ніж вирішення. З найновішими та дешевими процесорами та пам’яттю я б віддав перевагу дублюванню коду, а не щільній інтеграції для повторного використання.


5
Повторне використання коду стосується не ціни на обладнання, а витрат на обслуговування коду.
user2793390

1
Погодьтеся, але виправлення чогось у простому модулі не повинно впливати на весь код. Про які витрати на обслуговування Ви говорите?
Рагху Кастурі,

1
Виправлення помилок у модулі повинно вплинути на весь додаток. Чому ви хочете виправити одну і ту ж помилку кілька разів?
user2793390
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.