Як навчити себе уникати написання «розумного» коду? [зачинено]


75

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

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

Що я можу зробити, щоб протистояти бажанням написати "розумний" код і коли повинен дзвонити дзвін, що я це роблю неправильно ?

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


5
трохи поза темою, але thedailywtf.com/Articles/…

@Joe: це дуже на тему, дякую! Я прочитав статтю, але зараз приємно її знову розкрити.
День

33
Налагоджуйте багато розумного коду ... який повинен зробити трюк.
Dan Olson

@Joe Посилання на базу даних у цій статті має бути вмирати.
jnewman

Коротка відповідь: виграє найкоротший, найпростіший код. Усуньте дублювання, але не додайте шари "просто тому". Рефакторинг Фоулера може дати вам деяке розуміння.
кевін клайн

Відповіді:


54

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

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

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

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

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

Іноді експертна оцінка - це найкращий спосіб добре ознайомитись із власною роботою.


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

7
Немає оглядів коду? Урк. Я б написав щось самоправе і жах, але я працював і в цьому середовищі. Вони забирають багато часу і болять у дупі у кожного, але вони дійсно цінні як для вашого проекту, так і для вашого особистого розвитку. Якщо тема "Чи варто нам робити перевірку коду?" коли-небудь підійде, переконайтесь, що ви вниз, як "Чорт так!" І якщо вони не зіткнулися зі своїми наступаючими термінами, ви можете попросити співпрацівників, яких ви поважаєте, надати роботу, яку ви не впевнені щодо неофіційного коду-огляду-lite.
BlairHippo

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

2
О Боже. Звучить захоплююче - з усіма хорошими та поганими конотаціями, які це слово несе в собі. :-) Удачі, приятелю; ось сподіваюся, що ти на початку чогось великого.
BlairHippo

8
@BlairHippo: Я просто дотримувався вашої поради, заспокоївся і люб’язно попросив колегу, яка вказала на проблему, яку ввели мої зміни, зробити неформальні огляди зі мною, і він погодився. Це також допомогло зняти певну незграбність з нашої розмови (як у "ви пишете складний код, і я мушу це виправити .."). Дякую!
День

20

Найкраще зробити це - пам’ятати про максима Брайана Керніган:

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


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

13
+1 для максимуму, який кожна мавпа з кодом повинен знати напам’ять, але -1 за те, щоб не запропонувати ОП жодного розуміння, як застосувати її до своєї роботи. Таким чином, це все вирівнюється, не клацаючи стрілкою.
BlairHippo

2
Чудова цитата, але насправді не відповідь на питання ОП.
Джим Г.

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

2
-1: Найменше не відповідає на питання ОП.
Томас Едінг

15

Зазвичай існує як мінімум три рішення програмних проблем будь-якого значення: очевидний спосіб, не очевидний складний спосіб (розумний) і не очевидний простий спосіб (елегантний). Цитата про авторів застосовується тут:

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

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

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


3
Це нагадує мені цитату старого математика: "Для кожної проблеми є рішення, яке є простим, елегантним та неправильним".
Joris Timmermans

9

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


Я безумовно намагаюся нав'язувати це собі, коли є час.
jnewman

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

6

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

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

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

Розумний код також має можливість передати більш швидкий для розробки і більш зрозумілий і зрозумілий код команді, яка може не піддаватися новій мовній функції або виклику бібліотеки. Наприклад, коли мене вперше познайомили з Linq молодшим розробником, у мене була негайна огида до неї як до непотрібної, важкої для налагодження, нерозумної та «розумної». Сам погравши з ним і дізнавшись, наскільки корисними та потужними можуть бути запити Linq, я вклав час, щоб вивчити його, і мій DAL-код ніколи не був більш чистим і читабельним, а також простішим налагодженням та розширенням.

Я шкодую, що раніше не мав відкритої думки і хотів би, щоб я не був таким суворим щодо такого «розумного» молодшого розробника.

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

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


6

Якщо 20% (ваш% може відрізнятися) або більше доданих рядків потребує документації - саме час відступити і переосмислити .

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


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

@deadalnix: Непоганий момент. Я підозрюю, що мій% був би більшим, ніж більшість, тому що я зазвичай кодую в іншому випадку мертвою та сильно макромовною мовою складання. Чим важче читати, і кожен новий прокат доводиться вивчати мову, в результаті чого потрібно більше коментарів.
DKnight

2
@deadalnix - незрозуміла документація для пояснення того, наскільки знак є вашим кодом. Документація для пояснення того, чому дуже потрібна. Я бачив надто багато фрагментів коду, щоб я міг зрозуміти, що вони зробили, але не чому вони вирішили зробити це неінтуїтивно. Це дуже важко підтримує.
HLGEM

@HLGEM Це сперечається. Незрозумілість коду може виникати від погано розроблених libs / API, від неясності всередині самої концепції, як поганого розділення проблем. Ми живемо в реальному світі, і наші можливості є обмеженими, тому нам, безумовно, потрібна документація, але кожен раз, коли нам це потрібно, це означає, що хтось написав недосконалий код. Жодна документація - це не те, що ви повинні робити - навіть не думайте про це, але щось над тим, що вам слід думати весь час, щоб продовжувати вдосконалюватися в правильному напрямку.
deadalnix

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

4

Я не можу протистояти спробі чогось розумного.

Тож я роблю це на іграшковому проекті, в свій час, вдома.

Коли новинка зникає - проблема вирішена.


3

Я вважаю, що один із способів з'ясувати, чи ваш код занадто "розумний" - це зробити крок назад і задати собі наступне:

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

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


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

2

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

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

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


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

@BlairHippo HA! "остаточна перевірка здоровості" мені це подобається.
Філіп

2

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

Існують рамки введення залежності з відкритим кодом, для роботи яких потрібно просто попросити Expressionзнання про хитрощі, є F # та чудовий спектр завдань, з яких ви можете спробувати.

Якщо ви займаєтеся математикою (а це агностик мови ), для вас є Project Euler .

І останнє, але не в останню чергу, у світі .NET існує Mono Project, який має багато областей, які потребують уваги розробника , деякі з них досить складні. Як щодо сприяння статичному інструменту аналізатора коду з відкритим кодом .NET ? Там задіяно кілька аналізів ІЛ, а також матеріали високого рівня. Jb Evain завжди працює над чимось цікавим, будь то бібліотека відображення Cecil, Expressionпідтримка чи декомпілятор .NET.

Якщо нічого не підходить, просто запустіть власний глузливий фреймворк :-)


2

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

Немає

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


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

2

Я думаю, що тема вдало обрана. "Класно" написати рядок Perl, який робить десять тисяч речей все одночасно, але потім це смокче, коли доведеться переглянути його.

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

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

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

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

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

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

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


1

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

Редагувати у світлі -1:

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

Я дізнався, бо запитав, чому, і вони вирішили пояснити, тому що вони думали, що я можу щось скласти - LOL ....


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

1

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

Також розумійте, що зосередившись на функціональному програмному забезпеченні, яке вчасно та легко підтримується, ви отримаєте визнання, якого прагнете. До вас звернуться досвідчені розробники і скажуть: "Людина, той модуль, який ви написали, був добре розроблений. Мені довелося реалізувати лише один компонент, щоб підключити його до свого проекту". на відміну від "Мені довелося переробити весь цей модуль, який ви написали просто для того, щоб використовувати його в іншому компоненті? Ви навіть чули про Боба Мартіна або Уорда Каннінгама?"

TLDR: Ви не самотні. Визнання вміння найкраще досягається як побічний продукт вирішення завдань розумним шляхом.


0

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

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

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

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


-2

На додаток до хороших порад, що даються до цього часу (перегляд коду, налагодження, підхід до TDD), вам слід час від часу (повторно) читати (найкращі книги, що стосуються) про добрі практики кодування:

  • Прагматичний програміст
  • Код заповнений
  • Чистий код

та інші, залежно від технології, яку ви використовуєте.


-2

Пам'ятайте лише ЯГНІ - вам це не потрібно .

програміст не повинен додавати функціональність, поки не вважатиме це необхідним ...

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

На думку тих, хто виступає за підхід YAGNI, спокуса написати код, який наразі не є необхідним, але може бути в майбутньому, має такі недоліки:

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

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