Чи приховується інформація більше, ніж умова?


20

У Java, C # та багатьох інших сильно типізованих статично перевірених мовах ми звикли писати такий код:

public void m1() { ... }
protected void m2() { ... }
private void m2() { ... }
void m2() { ... }

Деякі динамічно перевірені мови не містять ключових слів, щоб виразити рівень "приватності" даного члена класу, а натомість покладаються на умови кодування. Python, наприклад, префікси приватних членів із підкресленням:

_m(self): pass

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

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

Зважаючи на це, моє питання:

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

Чи можна його використовувати для захисту таємного стану класу від нападу? Чи може відображення перекрити цей механізм? Що було б корисно для компілятора, щоб забезпечити приховування інформації?


10
Вибачте, Ерік Ліпперт у відпустці :)
Benjol

Ваше питання трохи важко зрозуміти. Ви в основному просто запитуєте, чи хтось може отримати доступ до приватного члена ззовні?
Morgan Herlocker

1
Питання, пов’язані з цим: programmers.stackexchange.com/questions/92380/…
користувач281377

@ironcode: Я можу сказати, що я якось не висловлююсь досить чітко з деяких відповідей. Чи можете ви сказати, що конкретно ускладнює розуміння? Спробую уточнити.
блека

2
"Дурниця надавати інформацію під час компіляції, а потім перевіряти її лише під час виконання" - справді? Краще скажіть це Microsoft, тому що саме на цьому ґрунтується значна частина поточної системи .NET: вибіркове відключення або відмова від статичного набору тексту. Я не думаю, що це дійсно те, що ти маєш на увазі; питання неодноразово говорить про "статичну" проти "динамічну" перевірку, але це характеристики типової системи; Тут справді йдеться про час компіляції та прив'язку часу виконання .
Aaronaught

Відповіді:


4

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

Я працював з python, і під час моєї навчальної поїздки я чув, що в python існує умова, оскільки люди, які працюють з цим, повинні знати, що це означає і як їх застосовувати. Це _m(self): passозначає, що підкреслення застерігає мене, щоб я не псувався з цим полем. Але чи всі дотримуватимуться цієї конвенції? Я працюю з javascript, і мушу сказати, вони цього не роблять . Іноді мені потрібно перевірити проблему, і причина полягала в тому, що людина робила щось, чого він не повинен був робити ...

читайте цю дискусію щодо підкреслення провідного пітона

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

З того, що я сказав, так.

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

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

РЕДАКТИРОВАНО Так, рефлексія може, перевірити коментарі

Останнє питання цікаве, і я готовий прочитати відповіді на нього.


3
Відображення зазвичай може обійти захист доступу. Для Java та C # вони обидва можуть отримати доступ до приватних даних.
Марк H

Спасибі! Відповіді тут: stackoverflow.com/questions/1565734/… поясніть це!
wleao

1
Культура Javascript дуже відрізняється від культури python. У Python є pep-08, і майже всі розробники python дотримуються цих умов. Порушення PEP-08 часто розглядаються як помилка. Тому я думаю, що досвід JavaScript / php / perl / ruby ​​дуже мало перетворює досвід python в цьому аспекті: _private дуже добре працює в python.
Майк Коробов

1
У деяких (але не всіх) мовах програмування приховування інформації може використовуватися для захисту від ворожого коду. Приховування інформації не може використовуватися для захисту від ворожих користувачів.
Брайан

2
@Mike, якщо порушення PEP-08 так часто "розглядаються як помилка", і жоден розробник Python не мріяв би не дотримуватися конвенцій, то ви також можете застосувати їх до мови! Чому довічно працювати, коли мова може це робити автоматично?
Андрес Ф.

27

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

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

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

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

Отже, короткий підсумок:

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

3
Що ще важливіше, будь-яке (легко впізнаване, що є випадком, наприклад, провідні підкреслення), що не застосовується домовленостей щодо "деталей щодо впровадження, підлягають зміні", також уникає приватного використання приватних членів. Наприклад, в Python, єдиний раз, коли здоровий програміст пише код, використовуючи приватного члена ззовні (і навіть тоді він нахмурився), коли це майже неминуче, він точно знає, що робить, і приймає потенційний злом у майбутніх версіях . Тобто ситуація, в якій, наприклад, програмісти Java використовуватимуть роздуми.

3
@Simon Stelling - ні, я кажу, що оригінальний реалізатор класу, який зробив щось приватне, говорить вам "не використовуйте цього, будь-яка поведінка тут може змінитися в майбутньому". Наприклад, приватна змінна класу класу, яка спочатку містить відстань між двома точками, пізніше може містити відстань між двома точками в квадраті з міркувань продуктивності. Все, що б покладалося на стару поведінку, зламалось би мовчки.
Joris Timmermans

1
@MadKeithV: Тоді як ключове слово на рівні мови говорить "не чіпай, тому що ...", що відрізняється від конвенції, що означає те саме? Тільки компілятор виконує це, але потім ми повертаємося до старого статичного та динамічного обговорення.

7
@Simon Stelling (і Делнан) - мені начебто запитують "як обмежувач двигуна відрізняється від знаку обмеження швидкості".
Joris Timmermans

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

11

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


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

6
Так, але публічна документація класу, написана динамічною мовою, також не кидає у вас цих 36 приватних частин (принаймні, не за замовчуванням).

3
@Simon Заява, що це "просто конвенція", вводить в оману, оскільки має реальну користь. "Просто умовність" - це щось на зразок фігурних дужок на наступному рядку. Конвенція з перевагами - це щось на зразок використання значущих імен, які, я б сказав, зовсім інше. Чи налаштування чогось приватного перешкоджає комусь бачити вас «таємними методами»? Ні, ні, якщо вони визначені.
Морган Херлокер

1
@ Simon-, лише виявлення безпечних у використанні методів збільшує ймовірність помилки, що користувач не зламає щось при спробі використання класу. Тут можна було легко використовувати методи, які могли б зламати веб-сервер, якщо його викликати тисячу разів. Ви не хочете, щоб споживачі API ви могли це зробити. Абстракція - це не просто умова.
Морган Херлокер

4

Я б запропонував, щоб задля передумови почати з читання про інваріанти класів .

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

Давайте скористаємося справді простим прикладом C #:

public class EmailAlert
{
    private readonly List<string> addresses = new List<string>();

    public void AddRecipient(string address)
    {
        if (!string.IsNullOrEmpty(address))
            addresses.Add(address);
    }

    public void Send(string message)
    {
        foreach (string address in addresses)
            SendTo(address, message);
    }

    // Details of SendTo not shown
}

Що тут відбувається?

  • Член addressesініціалізується на побудові класу.
  • Це приватне, тому ззовні нічого не може торкнутися.
  • Ми також зробили це readonly, тому нічого зсередини не може торкнутися його після будівництва (це не завжди правильно / потрібно, але тут корисно).
  • Тому Sendметод може зробити припущення такого, addressesякого ніколи не буде null. Він не повинен виконувати цю перевірку, оскільки немає можливості змінити значення.

Якщо іншим класам було дозволено записувати в addressesполе (тобто, якби це було public), то це припущення більше не було б дійсним. Кожен інший метод у класі, який залежить від цього поля, повинен був би робити явні перевірки нуля або ризикувати збоєм програми.

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

До цих інших питань:

Чи можна його використовувати для захисту таємного стану класу від нападу?

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

Чи може відображення перекрити цей механізм?

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

Що було б корисно для компілятора, щоб забезпечити приховування інформації?

Компілятор вже виконує це. Так само, як і час виконання в .NET, Java та інших таких середовищах - опкод, який використовується для виклику методу, не вдасться, якщо метод приватний. Єдині способи навколо цього обмеження вимагають довіреного / підвищеного коду, і підвищений код завжди може просто записувати безпосередньо в пам'ять програми. Він виконується настільки, наскільки це може бути застосовано, не вимагаючи спеціальної операційної системи.


1
@Simon: Нам потрібно уточнити "незнання" тут. Префіксація методу за _допомогою договору, але не виконує його. Це може ускладнити невігластво договору, але це не ускладнює розрив договору, особливо не в порівнянні з набридливими і часто обмежувальними методами, такими як Рефлексія. Конвенція говорить, "ви не повинні цього порушувати". Модифікатор доступу говорить: "Ви не можете цього зламати". Я не намагаюся сказати, що один підхід кращий, ніж інший - вони обидва чудово залежать від вашої філософії, але все-таки вони дуже різні підходи.
Aaronaught

2
Як щодо аналогії: модифікатор доступу private/ protectedдоступу - це як презерватив. Вам не доведеться використовувати його, але якщо ви не збираєтеся, то вам краще бути чортом впевненим у своїх термінах та ваших партнерах. Це не завадить зловмисному діянню і, можливо, навіть не спрацює щоразу, але, безумовно, знизить ризики від необережності і зробить це набагато ефективніше, ніж сказати "будь ласка, будьте уважні". О, і якщо у вас є такий, але не використовуйте його, тоді не чекайте від мене жодної симпатії.
Aaronaught

3

Приховування інформації - це набагато більше, ніж просто умова; намагання обійти його може фактично порушити функціональність класу у багатьох випадках. Наприклад, досить поширена практика зберігати значення в privateзмінній, виставляти її за допомогою protectedабо publicвластивості того ж часу, а в getter перевіряти на нуль і робити будь-яку необхідну ініціалізацію (тобто, ліниве завантаження). Або збережіть щось у privateзмінній, виставіть це за допомогою властивості та в сетері перевірте, чи змінилося значення та пожежа PropertyChanging/ PropertyChangedподії. Але не бачачи внутрішньої реалізації, ти ніколи не дізнаєшся все, що відбувається за лаштунками.


3

Приховування інформації розвивалося з філософії дизайну зверху вниз. Python називають мовою знизу вгору .

Приховування інформації добре застосовується на рівні класів на Java, C ++ та C #, тому це насправді не умова на цьому рівні. Дуже легко зробити клас «чорним ящиком», з публічними інтерфейсами та прихованими (приватними) деталями.

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

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

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

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

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


1
+1 за цитатою "використання інформації програміста", саме так (хоча у вас є додаткова кома в кінці).
jmoreno

2

У Ruby та PHP є його і застосовувати його під час виконання.

Точка приховування інформації - це фактично показ інформації. "Приховуючи" внутрішні деталі, мета стає очевидною із зовнішньої точки зору. Є мови, які охоплюють це. У Java доступ за замовчуванням доступ до внутрішнього пакету, у haXe до захищеного. Ви прямо заявляєте про них, щоб викрити їх.

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

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


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

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

1
@Simon: чому захаращувати інтерфейс з речами, якими ви не хочете користуватися. Я ненавиджу, що C ++ вимагає, щоб кожен член був присутній у визначенні класу у файлі заголовка (я розумію, чому). Інтерфейси призначені для інших людей, і їх не слід заливати речами, якими вони не можуть користуватися.
phkahler

1
@phkahler: pydocвидаляє _prefixedMembersз інтерфейсу. Захоплені інтерфейси не мають нічого спільного з вибором ключового слова, перевіреного компілятором.
блека

2

Модифікатори Acces, безумовно, можуть робити щось, чого конвенція не може.

Наприклад, у Java ви не можете отримати доступ до приватного члена / поля, якщо не використовуєте відображення.

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

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

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


2

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

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

Якщо у мене є бібліотека

class C {
  public void foo() { ... }

  private void fooHelper() { /* lots of complex code */ }
}

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

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


Що було б корисно для компілятора, щоб забезпечити приховування інформації?

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


Чи може відображення перекрити цей механізм? Що було б корисно для компілятора, щоб забезпечити приховування інформації?

У Java не лише рефлексія може перекрити цей механізм. Є два види privateJava. Вид, privateякий заважає одному зовнішньому класу отримати доступ до privateчленів іншого зовнішнього класу, що перевіряється верифікатором байт-коду, а також privates, які використовуються внутрішнім класом методом синтетичного аксесуара-приватного пакета, як у

 public class C {
   private int i = 42;

   public class B {
     public void incr() { ++i; }
   }
 }

Оскільки клас B(дійсно названий C$B) використовує i, компілятор створює метод синтетичного аксесуара, який дозволяє Bотримувати доступ C.iтаким чином, що проходить повну перевірку байт-коду. На жаль, оскільки ClassLoaderдозволяє створити клас з "a" byte[], досить просто потрапити на приватних осіб, які Cзазнали впливу внутрішніх класів, створивши новий клас у Cпакеті s, який можливий, якщо Cбанку не запечатана.

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


Чи можна його використовувати для захисту таємного стану класу від нападу?

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

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

Joe-E - це підмножина мови програмування Java, розроблена для підтримки захищеного програмування відповідно до дисципліни, що відповідає можливостям об'єкта. Joe-E призначений для полегшення побудови захищених систем, а також для огляду безпеки систем, вбудованих в Joe-E.

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

Забезпечення безпечної інкапсуляції.

Малюнок 1. Додаток для ведення журналу лише для додавання.

public final class Log {
  private final StringBuilder content;
  public Log() {
    content = new StringBuilder();
  }
  public void write(String s) {
    content.append(s);
  }
}

Розглянемо рис. 1, який ілюструє, як можна побудувати об'єкт журналу, що додається. За умови, що інша частина програми написана на Joe-E, переглядач коду може бути впевнений, що записи журналу можна додавати лише та не можуть бути змінені або видалені. Цей огляд практичний, оскільки вимагає лише перевірки Log класу, і не потребує перегляду будь-якого іншого коду. Отже, для перевірки цього властивості потрібні лише локальні міркування щодо коду журналу.


1

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


1

Роблячи захист частиною мови, ви отримуєте щось: розумну впевненість.

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

Тепер існують способи обійти синтаксичний захист? Абсолютно; більшість мов їх. У C ++ ви завжди можете передати клас якомусь іншому типу та натиснути на його біти. У Java та C # ви можете відобразити себе в цьому. І так далі.

Однак зробити це важко . Очевидно, що ти робиш щось, чого ти не повинен робити. Ви не можете це зробити випадково (поза дикими записами в C ++). Ви повинні охоче подумати: "Я торкнусь того, чого мені не сказав моїй упорядник". Ви повинні охоче робити щось нерозумне .

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

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

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

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

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

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