Pull to refresh
93
Юрий@m36

User

21
Subscribers
Send message
Императивное и декларативное программирование — термины. Не я придумал. И легко погуглить и убедиться, что это такое. Шарп является императивным языком. Условно. Его можно использовать и декларативно. Но он предрасполагает к императивному программированию, потому что сколько не инкапсулируй код в классы — основная работа проходит в методах, где последовательности, циклы и ветвления.

SQL — декларативный язык. На нем вы пишете «что» вы хотите, а не «как». В этом и мощь SQL. Задачи с помощью него решаются в десятки раз быстрее, ошибок при умении в десятки раз меньше, кода в десятки раз меньше, чем если бы вы писали в шарпе циклами и ветвлениями.

Я нигде фигню не написал. Аналогии привожу для того, чтобы вы поняли мысль. Не надо аналогии дословно воспринимать и искать в них частные несоответствия. Натуральный язык и язык программирования имеют количественные различия, но не качественные. Так что аналогии уместны. Мне, конечно, тяжело только с помощью натуральных языков объяснить, насколько они разные. Грамматики, логика, похожи. Но они не обязаны быть такими.

«Что» хочу и «Как» хочу — по смыслу разные вещи. Да, я встречал заказчиков, которые говорили: «хочу, чтобы в таблице была такая колонка, это мое требование». В результате были посланы. Я с такими людьми работать не хочу.

Также и «Проблема в том, что в моем примере код содержит информацию о том, _как_ решать задачу, и это и есть то, чего я хочу» — если это так, то это действительно проблема.

«Элементарные понятия не описываются, если что. Они элементарные, они просто закрепляются в понятийном аппарате. „

Корабли не плавают, они ходют (аналогия). Закрепление на понятийном уровне не происходит телепатически и невербально. Вот это закрепление и есть описанием.
Если код содержит алгоритм и решает задачу — то он императивный. Если код решает задачу, но в нем не сказано как решать задачу, а только что хотите — он декларативный.
Прямое или непрямое отражение — это субъективные вещи, связанные с культурой. Англичане могут удивляться, что вы прямое слово dog говорите непрямым словом «собака». А когда вы увидете свои требования на китайском, вообще удивитесь.

SQL — это отражение, что хочет пишущий от сервера. Но конечно, используя грамматику не русского языка, а грамматику SQL. Источники данных, связи и преобразованя — это декларативный способ описания «чего» вы хотите.

Естественный язык в этом плане далеко не лучше SQL. Если бы у вас осталась только грамматика языка, но язык не имел бы предопределенных понятий, то вам любое ваше требование пришлось бы долго «кодить». Сначала описать элементарные понятия.
«Описание задачи не может быть ее решением, вот в чем проблема.»

Один из примеров декларативных языков SQL. Вы в коде запроса описываете, что вы хотите. Вы не пишете последовательность шагов и не уговариваете сервер выполнять какие-то последовательности или условия. Поэтому запрос на SQL является описанием задачи и также и ее решением.
«Я еще раз спрашиваю — зачем нам знать, какие методы оно использует? Нам надо знать, _что_ оно такое. Оно — рента. Рента — это частный случай платежа.»

Ну да. Нам надо знать _что_оно_такое. Я ж о чем.
var renta = GetRent(...);
никак не говорит _что_оно_такое. Оно говорит: получаем методом ВзятьРенту нечто, чему дадим название «рента». В данном случае — рента — это не понятие пока, это слово. И мало ли, может программист был пьян, когда употребил это слово. Кодом ну никак не определяется. Имя переменной rent как и сама переменная, только здесь впервые появляется. Еще не было «пусть рентой будет Оплата, которая...». Еще этого не было. Все совпадения в фильме с реальными фактами — считать случайными.

«Весь ваш пример построен на том предположении, что вы знаете, что такое Payment»
Payment уже описывалось. Здесь Payment не впервые встречается. Здесь оно уже имеет суть. Я говорю о линейном восприятии. Если оно уже встречалось, значит скорее всего я уже знаю, что это такое. Если не знаю, то перейду на описание этого класса. И это сделать проще. И потом, если снова перейду назад, я не забуду, что рента, это какая-то оплата. Payment в данном случае — это гиперссылка. Понятие уже введено, но если кто не знает, перейти может.

«Если коротко, то потому, что код — это выражение решения задачи, а не терминов, в которых задача выражена.»

Это плохо. Восприятие кода как решения задачи — (имхо) влияет плохо и на процесс кодирования и на архитектуру и всё остальное. Если воспринимать код, как описание задачи — то код будет приближаться к описанию и будет более декларативным. Что и значит — он будет более прямо выражать суть задачи, будет более коротким, более надежным и т.д. и т.п.

«Потому что код не способен выразить «аренда — это процесс использования чужого имущества» и «ИНН — это уникальный номер, присваиваемый налогоплательщику таким-то органом».»

Почему это не способен? Если он не способен выразить мысль, то он не способен и предоставить решение. Разве если есть такие утверждения, то вы вообще не способны закодить такие требования? Очевидно, что способны.
Код условно можно разбивать на две части — декларативную и императивную. Декларативная часть описывает «что», императивная «как». Есть языки, которые только «Что» описывают и это прекрасно.
На вскидку решение задачи двух ваших утверждений. В реляционной БД можно задать таблицы и связи — декларативный способ. Что такое эти связи — это по сути ограничения. Можно взять и создать сто таблиц со ста колонками каждая, тип которых любой (varbinary) и просто пронумеровать, не ставить связи. Очень гибкий вариант, очень большое N-мерное пространство и все точки в нем возможно выразить такими таблицами. Наша задача, удовлетворять требования, т.е. ограничить точки и придумать способ их интерпретации. Способ интерпретации — даем таблицам осмысленные имена, ограничиваем типы колонок нужными типами атрибутов, даем имена. Простраство вариантов сократилось и уже более лучше отвечает задачи. Добавляем связи между сущностями — и еще сократилось. Вот уже довольно неплохо у нас описана предметная область. Имущество, процесс и т.д. (я бд для примера привел, можно и в шарпе такое же сделать). Далее приступаем к недекларативной части и кодируем возможные переходы между состояниями (точками). И если не удалось ограничить типами, проверяем местами на неверные точки и выбрасываем эксепшины.

И вот у нас код выражает требования «аренда — это процесс использования чужого имущества». И т.д. Императивная часть кодирования — похожа на доработку напильником. Иногда из паровоза получаем вертолет.

Такое представление о кодировании, кстати, показывает, что лучше не кодом, а структурами данных выражать предметную область. Т.е. подбирать подходящие типы, которые не позволяют программе быть в запрещенных точках. А также каждая переменная по возможности должна быть независимой от других (ортогональность осей).

Язык программирования — это прежде всего язык. Также, как например, неверно воспринимать математику, как набор формул для решения задач — это в первую очередь язык описания более сложных и точных мыслей. Шарп — это язык более точного описания мыслей, чем естественный язык. И многие говорят, что программы пишут в первую очередь для того, чтобы их читали.

Языки стремятся сделать декларативными. Нас силой заставляют, потому как не захотели мы с рождения на лиспах писать. Декларативные языки не описывают алгоритмы, а описывают задачу «Что делать», а не «как делать». Конечно, это пока красиво в теории, но на практике даже функциональные языки далеки от естественных в простоте описаний.

Но ничего, наработки накапливаются. Всё таки надеюсь, что мы еще застанем такие языки программирования. А сейчас, пока их нет, у нас большой диапазон способов, как использовать шарп, например. Его можно хоть циклами весь залепить, хоть лямбдами, хоть классами. Я предлагаю (и не только я), рассматривать его как язык и отталкиваться в написании кода от критерия ясности кода. как если бы мы просто были переводчиками и напрямую переводили требования.

Пока вы правы — просто и прямо использовать классы как словарь терминов и язык описания требований — не всегда легко. Но стоит только подумать в эту сторону, наверное, сразу придумаете много способов это сделать.

Извините за многословность. Но тема такая. Религиозная. Чтобы объяснить идеи, приходится использовать очень далекие аналогии.
Не согласен по всем пунктам.

Чем отличается 1) собака от 2) собака. Первая состоит из 6 букв, вторая из четырех лап, хвоста и рычалки. Слово и объект, с которым оно связано — разные по сути вещи. И линейное восприятие информации — это последовательное присвоение имен (терминов) объектам или уже созданным терминам.

var rent = GetRent(...);
Говорит: нечто мы возьмем с помощью метода GetRent и назовем рентой. Здесь rent — это слово (привет кэпу). И здесь тоже:

Payment rent = GetRent(...);
Но Payment — уже не просто слово. Словом оно было здесь:
class Payment
{
}
Что читается, как «пусть Оплатой мы будем считать...». Мы в этом месте определили суть слова Payment. Присвоили имени суть.

В этом же месте впервые появляется новое слово:
Payment rent = GetRent(...);
И читается так:
мы получили оплату методом ВзятьРенту, которую назовем рентой в данном скоупе.

Этот код говорит:
var rent = GetRent(...);
Мы получили нечто методом ВзятьРенту и пока пусть будет нечто, позже станет понятно, какие методы оно пользует. Если непонятно, то посмотри в словарь. Если непонятно дальше, посмотри на интелисенс и перейди, посмотри класс.

Самым главным документом является код. Почему словарь (обязательный реквизит для чтения кода) написан в ворде? Что такое ворд? Оно компилится? нет. Оно отражает то, что делает приложение? нет. Чем вообще люди занимались, когда его писали???

Я утрирую. Но в общем, язык программирования — это язык описаний. Он иногда неуклюж, но языки движутся в эту сторону. Код — единственный наш друг, который не соврет. Любая документация (ЮМЛ, требования) — являются вторичными и необязательными. Они могут быть и могут дополнять. Но только код является первичным и обязательным. Требования можно писать тестами. Тесты — это утверждения. Чем не язык?

В общем в будущем думаю так и будет. Описали задачу, и она уже работает. Два раза не описывают. А пока, думаю, к этому надо стремиться. Хотя бы с помощью шарпа.
«Если вы не знаете, что такое рента, то вы не знаете business domain.»

Так вот код и есть та книжка, которую можно читать при некотором подходе к программированию. Языки стремятся в декларативную сторону, отвязаться от реализации. Поэтому код и есть документом, а не реализацией. (то, что вы защищаете). Поэтому я его хочу читать как книгу и даже если у меня есть пробелы в предметной области, хочу по максимуму понимать написанное в коде, а не в дополнительных документациях к коду. Требования к задаче и сама решение по возможности должны быть равны — и то и другое описание.

«А зачем вам это знание в дальнейшем коде?»

Для понимания. Я никак не могу вам объяснить, что типы — не только бывают с реализацией связаны, но и с описаниями. Мой мозг например, плохо работает, когда я читаю книгу, допустим по математике или физике, а там пишут формулой или термин, еще не встречавшийся и говорят: «а что это, мы узнаем в следующей главе». И оперируют на всю формулой или термином. Мозг отключается и абсолютно отказывается читать дальше.

Также и здесь. Я последовательно воспринимаю информацию. Очень плохо воспринимаю просто слово, а потом через куски кода можно понять, что это такое. Описание типа перед именем осознается, как привязка слова к некоторому объекту. Слово не висит в воздухе, ожидая, что я потом его свяжу с объектом.
«SomeInterface obj =

Это совсем другое. Это ничем не отличается от указания типа (собственно, интерфейс и есть тип).
»

Тут и я поспорю. Информационной ценности что там что там. Кстати, с выводами статьи Липпера вполне согласен. Я же сразу писал, что иногда использую var, когда действительно тип не имеет значения. Когда в запросе линькю меня никак не волнует, какой там список — кверибил или просто IEnumerator, потому что дальше я просто перебираю элементы или делаю поиск элемента. Кишки действительно не интересны и не нужны.
Но возвращаемое значение метода для меня не очень понятно по типу. Вот здесь тип уместен. Если это кастомный тип и отражает важную часть предметной области. Интелисенс — не выход. Я хочу читать код, а не клацать мышкой, чтобы найти что-то скрытое. Не считаю, что эта инфа лишняя, она элемент семантики. Иногда типы — это части реализации. Особенно, где нет кастомных. В С, например. int, float, double — какое мне дело, сколько он байт выделяет? Тут не надо. Но когда я должен знать, платеж это, или должник, или клиентБанка, то имен экземпляров не достаточно лично для меня.

Я интуитивно всегда за то, чтобы язык использовали, как лингвистическую вещь, которая описывает задачу, а не решение задачи. И вот, что получится, например:

var yesterdayRent = GetRent(DateTime.Now.AddDays(-1));

Рента — это тип Paymant. Откуда я из кода выше это знаю? Если делать перевод на наш язык, звучит примерно так:

Некая/нечто рента, взятая за вчера.

А так:

Payment yesterdayRent = GetRent(DateTime.Now.AddDays(-1));

Вчерашняя рента, которая является платежом. (тут меня осеняет, что это платеж, а значит даже не зная этого класса, я догадываюсь, что в нем есть атрибуты — кто платил, когда платил и т.д.).

В первом случае, да, допустим, я тоже понял слово рента. Но я не знаю, что это точно. Может быть это класс, содержащий распределение цен на жилье/офисы географически. А может быть и по времени средние цены. Я знаю только слово, которое меня приблизило к смыслу, но не дало мне понимания, что за тип и что с ним можно делать.
Честно говоря, я впервые по другую сторону баррикады. Обычно я доказываю всем, как важна семантика и смысл, и как не играют роль реализации.

Но в данном вопросе мы разошлись во мнениях, что является семантикой.
«Значит вы плохо себе представляете, что у вас происходит в этом куске кода.»

Конечно. У меня цель — прочитать чужой код. Я его плохо понимаю изначально и хочу понять, что он делает и зачем. О том и речь. Мы спорим о вкусах. По вашему получается, что заменив тип на слово var, код становится читабельнее. Вы думаете, что уменьшив информацию, вы убрали ненужную информацию — шум, которая отвлекает от сути.
А я считаю, что это в большинстве случаев не шум. Опыт у меня такой. Мне тяжелее читать чужой код, где кругом пользуются var. У нас есть любители. И даже мой код правят, меняя типы на var.

Цель написания кода — чтобы его читали. Вот, я один из народа, у которого есть личный негатив и трудности со чтением реального кода. Можно, конечно, поспорить, что имена плохие давали, что причина не в var, а в названиях экземпляров. Может быть. Но глаза мои не сломались бы, если бы перед хорошими именами экземляров были прописаны хорошие имена классов.
«И что, если вы напишете var вместо Платеж, то сможете сделать операцию, не принадлежащую платежу?»

Не смогу. Я и не спорю — статическая типизация не нарушается. Если я напишу var то я буду плохо понимать, что это. И мне придется больше времени въезжать, какую операцию я могу с именем сделать, а какую нет.

Хорошо, я почитаю статью, а то нехорошо как-то спорить без этого
«И пользователи тоже функции передают? И вы мне хотите сказать, что 6 и 7 — это не данные?»

Нет )) Не данные. Пользователи передают функции-константы 6 и 7. Это формальность, правда? Функциональные языки обобщают понятие функции, в результате чего можно данные рассматривать как функции. В результате обобщения появляются замечательные возможности.

«Передача делегатов в методы — это всего лишь передача делегатов в методы, тот или иной сценарий, тот или иной паттерн, если угодно»

Смотря что вы называете языком. Создавая делегаты, которые берут на вход делегаты, вы создаете возможность потом создавать код, но отвечающий спецификациям делегатов, что вам позволит ограничить действия тех, кто будет использовать ваш код — т.е. создать язык, которым можно будет что-то выражать в какой-то предметной области. Яркий пример — методы для коллекций, берущие на вход лямбды. Вы коллекциями вращать можете как хотите и у вас почти SQL. Это уже язык, в каком-то смысле. Добавив еще парсер и абстрактное дерево — получили и новый синтаксис — linq
Если тип int (т.е. тип, относящийся к реализации, а не предметной области), то не нужен. Всегда достаточно знать _роль_ объекта. Вопрос только в том, откуда вы это знаете. Кастомный тип — это и есть его роль (т.е. возможная работа над ним).

Я совершенно согласен, что нужно обращать внимание на семантику, а не реализацию. Но типы могут быть элементами семантики. Если я пишу программу для банка, то Платеж — это элемент предметной области. И тип, следовательно, тоже. И я согласен, что сам тип имеет меньшее значение, чем его конкретный экземпляр (которому дают имя). Поэтому я и против венгерской нотации. Но все же даже если у меня есть конкретный экземпляр Платежа, мне не достаточно знать, что это какая-то var рента. Это уточняет — рента — это конкретный Платеж. Но я не уверен, что это вообще он. А именно тип определяет, что я с этим объектом могу делать.

Тип — это тоже объект, грубо говоря — экземпляр метакласса. И если это не int или decimal, которые никак не относятся к предметной области, то эта информация является семантической. Это не «реализации». К семантике, как я понимаю, может относиться также и сам код, если его писать правильно (как переводчики, а не реализаторы бизнес-логики. Она не реализуется, а описывается в идеале).

Как и в естественных языках, для передачи семантики важны не только слова, которым вы дали свои имена, а также и местоимения, запятые и структура предложения.
«Вы что-то путаете. Как это нет данных? А операции над чем производятся?»

Над функциями. Ну, вот аналог на шарпе:

delegate int IntConst();
delegate IntConst IntOp(IntConst a, IntConst b);

IntOp plus = (a, b) => () => a() + b();
IntConst const6 = () => 6;
IntConst const7 = () => 7;

int r = plus(const6, const7)();

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

«Там есть и скрытое поведение, и безумные затраты на изменение поведения программы»

Это смотря кто как пишет. Обычно шарп программисты очень плохо к SQL относятся, потому что слабые в нем специалисты. А если еще плохо транзакт использовать и тригеры, то можно вообще написать что-то жуткое и страшное. То же и к шарпу относится. Если человек плохо на шарпе пишет, может написать очень плохой код. В реляционных БД есть свои и немалые плюсы, вот я описал, на что обращать внимание. Та же логика относится, например, к linq. Передача делегатов в методы позволяет создавать свои языки.
«Скажите честно, вы статью Липперта, на которую я дал ссылку, прочитали? Мы говорим о том, что там уже разжевано.»

Честно, пока нет. На работе развлекаюсь :)
Спасибо за статью, обязательно почитаю.
«А главное — в вашем примере отчетливо понятно, что Вася — это Человек»

Для меня не отчетливо. Я же написал ниже: имена дают и свиньям. И собакам. А может быть кот Вася. И это разные типы объектов, не обязательно имеющие общего предка. Конечно, если Вася — тип человек, а человек имеет метод «Платить», то любой его потомок — Мужчина, Женщина, ПлатящийЧеловек — имеют метод «платить».

А если нет общего предка, то ничего сказать нельзя. Выражать семантику именами — хорошо и правильно. Я только о том, что не только именами нужно выражать семантику.

«var Вася = новый Человек();
Человек Вася = новый Человек();»

Я изначально говорил, что в таком примере я не имею ничего против var. Тут явно вызов конструктора. А если ссылку на Васю получают вызовом метода, то в этом случае остается только надеяться, что Вася — правильное и понятное имя, выражающее тип (я уже говорил, могут быть и свиньи), а также имя метода — правильное и понятное имя, подразумевающее точно, что у нас возвращается ровно тот тип, который, как мы подозреваем из имени, есть у Васи.
Две вещи подряд, которые не проверяются компилятором и условны. Произведение вероятностей — вероятность правильного ответа падает. Вероятность бага — растет.
Сомневаюсь, что это беда. Важность оптимизации очень сильно переоценена.

Еще не разу не сталкивался с критическими тормозами, потому что Dictionary использовал. Оптимизация — это процесс, который проводится после написания кода, который проходит в определенном порядке. Вначале замеры производительности, выбор узких мест, поиск оптимальных решений для узких мест.

Узких мест почти всегда два-три. Где-то цикл, в нем цикл, а в нем самый внутренний цикл, где в сумме программа проводит почти всё время. Вот там и оптимизируют. И если код уже написан, а там замеры показали — тормозит Dictionarу, то нет проблем из него сделать switch.

А так, просто, на вскидку, ни разу не помню, чтобы Dictionary был в чем-то виноват.
«Константа — это функция, которая не всегда возвращает одно и то же»!!!

Ошибся. Править нельзя. Конечно, константа — функция, которая ВСЕГДА возвращает одно и то же
«у вот у меня под рукой МакКоннел, в котором явно написано, что привлекательность табличных методов (а это, как мы уже выяснили, частный случай) зависит от сложности кода.»
Читал я МакКонела. Согласен с ним в данном случае. От языка это зависит. И от сложности кода и задачи. Так не будем и спорить, представляя себе крайние противоположные случаи.

«Если честно, я перестал понимать, что вы считаете данными, а что — кодом.»
Могу только интуитивные аналогии приводить. Разница между кодом и данными условна.
Вспоминаем паскаль. Там есть отличие между процедурами и функциями. Процедуры что-то делают, но значение не возвращают, функции что-то делают и возвращают. С, С++, шарп — проводят обобщение, добавляя тип void. Функциональный подход проводит еще большее обобщение — всё функции, данных нет. Т.е. функция — это значение, которое зависит от входных параметров. Константа — это функция, которая не всегда возвращает одно и то же. Любая программа — это функция — преобразование входных параметров в выходные. Поэтому нет данных. Или можно сказать, что функции — это данные. Список интов — это список из функций, например. Такой подход мощнее.

Шарп не такой. Но в нем можно использовать многие наработки из функционального подхода. При этом решения иногда получаются даже лучше, чем обычное ООП или структуры кода. Вот о чем эта статья.

И шарп весело шагает в сторону функционального подхода. С каждой версией в нем появляются всё более лаконичные средства.

На счет аналогии, выше, попытаюсь еще раз на пример. Вы знаете C# и думаю, знаете SQL и реляционные СУБД. Можно сказать, что SQL — это хоть и не обычный, но функциональный язык. Когда вы моделируете предметную область на шарпе, вы вынуждены строить кирпичик за кирпичиком, дописывая код и скрывая еще в классах, вовне только видимые интерфейсы. Каждую программу можно представить, как структуру в N-мерном пространстве. Где N — это количество переменных. Каждая ось — это переменная. В шарпе программист пытается кодом ограничить точки в пространстве, в которых может находиться программа. Он пытается снизить нагрузку на свое внимание и допустить меньше багов с помощью инкапсуляции. И в каждом методе и классе он оперирует небольшим набором объектов и прописывает пути в н-мерном пространстве. Далее на каждом новом уровне он скрывает код, который пишется на более низком уровне. В результате он получает код вверху, который оперирует небольшим количеством объектов и может делать небольшое ограниченное число действий. Надежда, что этого достаточно для покрытия требований.

Что происходит в БД. Моделируются связи между данными и структуры данных декларативно. Уже после создания структуры БД смоделированы большинство зависимостей, которые не позволяют программе находиться в запрещенных точках в N-мерном пространстве. И есть мощный язык SQL, который позволяет почти без усилий делать любые преобразования, а структура БД следит за целостностью. Таким образом у нас с одной стороны нет скрытого поведения, с другой стороны затраты на изменения поведения программы минимальны.

Т.е. проблемы решаются не скрыванием кода, а наличием ограничений и выразительного языка.
Где-то так и в функциональном подходе. Вы создаете язык и ограничения, а потом пользуетесь сколько угодно гибко.
На семантика и правила именования идентификаторов компилятор не обращает внимания. Язык программирования можно разбить на две части — то, что имеет значение для компиляции и не имеет.
Задача программистов, как переводчиков — переводить требования в наиболее подходящий текст на языке программирования. И хорошо и правильно уделять внимание семантике, ставить ее на первое место. Но удерживать смысл только в недоступных компилятору местах — нехорошо. Семантика не только в именах, но и в конструкциях. Паттернах, коде. Старый пример. Хотите сделать обход коллекции, используете foreach, а не for. Это говорит читающему ваш код, что вам не важен порядок элементов в коллекции. Семантика также и в типах. Кстати, когда создаете тип, тоже даете имя — и это семантика. Тип — человек, экземпляр Вася.

var Вася
Человек Вася

Второй пример понятнее и более строгий. И тип здесь — элемент семантики. Ведь могло быть и:
Поросенок Вася.

Конечно, можно использовать правила именование:
var ВасяЧеловек;
Но такой подход дает меньше уверенности. И смысла всю семантику переносить в имена тоже нет.
Когда скрол прокрутится, да, видно не будет, что за тип. Точно также как и с var. Но с var его не видно при любом положении скрола.
Конечно. Я в курсе. Писал только о сути. А делегаты или указатели на функцию — это уже детали реализации.
Делегаты — аналоги указателей на функции в большинстве случаев.

Information

Rating
Does not participate
Location
Киев, Киевская обл., Украина
Date of birth
Registered
Activity