Приховування / відключення функцій для деяких користувачів


11

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

Чи існує схема перемикання доступності функцій на основі прапора, який завантажується під час запуску (наприклад, безкоштовно / оплачено)?

Мені не подобається ідея про те, щоб скрізь були такі кодові блоки:

if(isFreeVersion){
    // ...
} else {
    // ...
}

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

Чи є спосіб це зробити, зберігаючи єдину базу коду і не засмічуючи код умовними висловлюваннями, які перевіряють безкоштовний / оплачений прапор?

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

Ми використовуємо Android / Java.



@gnat tnx, приємна знахідка. Але я хотів би обговорити варіанти, які не потребують окремих гілок та підтримання декількох баз коду
Tadija Bagarić

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

@BartvanIngenSchenau Я вважаю, що це в основному ifчеки, щоб приховати елементи контролю заборонених функцій або мати спливаюче діалогове вікно, коли користувач намагається робити те, що йому не дозволяється. Я сподіваюся знайти спосіб уникнути багатьох умов у коді
Tadija Bagarić

2
Використовуйте поліфоризм. Вам ніколи не доведеться запитувати себе про це, якщо заява знову, і це буде ЛОГО легше підтримувати!
Стів Чамайлард

Відповіді:


9

Якщо вам не подобаються if/elseблоки, тоді ви можете перефактурувати їх на використання у спадок (див. Замінити умовне поліморфізмом із книги Рефакторинга Маріна Фаулера ). Це буде:

  • Складіть трохи простіше міркувати про свій код.

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

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


3
Думаю, вам може бути зрозуміліше, що для цього не потрібно успадковувати реалізацію . Ще одна перевага полягає в тому, що безкоштовний додаток можна доставити без преміум-функцій. Змінення байтового коду Java, щоб зробити умови if справді справжніми, не дуже складно.
JimmyJames

15

Умовний подібний if(isFreeVersion)повинен виникнути лише один раз у коді. Це не шаблон, але я впевнений, що ви вже знаєте його назву: він називається принципом DRY . Якщо у коді є код типу " if(isFreeVersion)" у кількох місцях, це означає, що ви повторили цей рядок / логіку в ньому, а значить, його слід переробити, щоб уникнути повторення.

" if(isFreeVersion)" слід використовувати для настройки списку параметрів внутрішньої конфігурації для різних функцій. Отриманий код може виглядати приблизно так:

 if(isFreeVersion)
 {
      feature1Enabled=false;
      feature2Enabled=false;
      maxNoOfItems=5;
      advertisingStrategy=new ShowLotsOfAdvertisementsStrategy();
      // ...
 } 
 else
 {
      feature1Enabled=true;
      feature2Enabled=true;
      maxNoOfItems=int.MaxValue; // virtually unlimited
      advertisingStrategy=new ShowMinimalAdvertisementsStrategy();
 }

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

Тепер ви керуєте тим, що є у безкоштовній версії, а що в платній версії в одному місці, що робить підтримку цієї логіки досить простою. Ви все ще повинні бути обережними, щоб ваш код не захаращений великою кількістю if(feature1Enabled)висловлювань (дотримуючись принципу DRY), але тепер підтримка цих перевірок вже не така болісна. Наприклад, ви набагато краще контролюєте те, що потрібно змінити, коли ви хочете зробити наявну платну функцію безкоштовно (або навпаки).

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

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

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


5
Ви в основному замінили IsFreeVersion на FeaturexEnabled, ви не зменшили кількість дзвінків. Хоча у мене не було саме такого випадку, я завжди обробляв подібні речі, створюючи меню, відключаючи ті параметри, які користувач не повинен бачити. Здебільшого це створено для форми, але мені іноді доводилося це робити під час підготовки спливаючого меню.
Лорен Печтел

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

6

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

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

Є також деякі бібліотеки, які підтримують цю схему. У мене був досвід роботи з FF4J на Java, але я б здогадався, якщо ви введете:

feature toggle <whatever language you prefer>

... у будь-якій пошуковій системі ви отримаєте кілька рішень.


2

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

Якщо ви подивитеся на сервлетів, JAMES Mailets і навіть плагінів IDE, всі вони використовують концепцію архітектури плагінів:

  • Визначте інтерфейс, який ваш додаток вміє використовувати. Цей інтерфейс повинен передбачити спосіб введення себе в навігацію вашої програми та будь-який інший додаток для підключення точок дотику.
  • Налаштуйте шлях, який ваш додаток прочитає при запуску (керування плагінами значно складніше)
  • Якщо плагін існує (як файл Java Jar), ​​додаток або зчитує маніфест, щоб знайти реалізацію інтерфейсу плагіна, або сканує клас, який реалізує інтерфейс.
  • Після того, як цей клас буде знайдений, він інстанціюється та викликаються відповідні методи інтеграції нових функцій.

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

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

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