Re[3]: Про бизнес-объекты: для сохранения, для API, для внутреннего
От: bnk Австрия http://unmanagedvisio.com/
Дата: 26.09.17 18:24
Оценка:
Здравствуйте, Shmj, Вы писали:

S>Здравствуйте, bnk, Вы писали:


bnk>>Нет тут никакой проблемы.

bnk>>Определяешь 5 разных классов, и все. Если попытаешься переиспользовать один — все закончится кашей (перемешиванием разных модулей и слоев)
bnk>>Копируешь автомаппером например (самая распространенная либа для этого на .net) — обеспечивает гибкое эффективное копирование "похожих" объектов.

S>Не ясно почему обязательно получится "каша".


Ясно почему — аттрибуты сериализации в базу полезут в Web API, и наоборот.
Данные, нужные только для UI, нужно будет маркировать "не сохранять", "не экспортировать", ну и т.д.
Типы данных будет покорежены — возьмем например enum. В базе нужет int, в UI — string. Что делаем?

S>А про копирование. Ведь есть такое понятие как конструктор и он вызвается при создании класса. Там указываются обязательные поля. А ваш automapper знает про конструкторы и обязательные поля?

S>Или вы предлагаете отказаться от концепции конструкторов, оставлять его всегда пустым и просто использовать метод VilidateInstance для проверки установлены ли обязательные поля?

Нафик конструкторы. Бесполезная вещь в данном случае. Данные проверяются строго на пользовательском вводе, и больше нигде. А там WebAPI и всякие [Required], заботиться не о чем.
Все равно в таких классах как правило дофигищи полей, не засовывать же их все в параметры конструктора?
Re[4]: Про бизнес-объекты: для сохранения, для API, для внут
От: Shmj Ниоткуда  
Дата: 26.09.17 20:27
Оценка:
Здравствуйте, bnk, Вы писали:

bnk>Ясно почему — аттрибуты сериализации в базу полезут в Web API, и наоборот.


А чем они мешают на практике?

bnk>Данные, нужные только для UI, нужно будет маркировать "не сохранять", "не экспортировать", ну и т.д.


Правильно, пометить что те или иные не нужно экспортировать. Это разве не логично и правильно? Пометил -- а система разберется.

bnk>Типы данных будет покорежены — возьмем например enum. В базе нужет int, в UI — string. Что делаем?


Так это по отдельности указывается с помощью атрибутов или Fluent

bnk>Нафик конструкторы. Бесполезная вещь в данном случае. Данные проверяются строго на пользовательском вводе, и больше нигде. А там WebAPI и всякие [Required], заботиться не о чем.


Данные поступают не только от пользователя. Идея такая -- нельзя создать объект класса без обязательных полей. Зачем тогда вообще конструкторы с параметрами нужны? Или вы их вообще не используете никогда, отказались от концепции конструктора как такового?

bnk>Все равно в таких классах как правило дофигищи полей, не засовывать же их все в параметры конструктора?


Но не все же из них обязательные?
Отредактировано 26.09.2017 20:47 Shmj . Предыдущая версия .
Re[5]: Про бизнес-объекты: для сохранения, для API, для внут
От: bnk Австрия http://unmanagedvisio.com/
Дата: 26.09.17 21:00
Оценка: 11 (3) +1
Здравствуйте, Shmj, Вы писали:

bnk>>Данные, нужные только для UI, нужно будет маркировать "не сохранять", "не экспортировать", ну и т.д.

S>Правильно, пометить что те или иные не нужно экспортировать. Это разве не логично и правильно? Пометил -- а система разберется.

Ну конечно :) А атрибуты где определены? В слое данных (EF?) Добавляем референс на него, ага.
Дальше, атрибуты для WCF? Конечно, добавляем референс на него тоже. Дальше, что там, WebAPI, JSON, XML? да, еще референсы.
Потом нужно передать пару дополнительных флажков для UI, и пару списков для комбобоксов? Конечно, добавляем поля и помечаем их всем чем нужно, для всех модулей не забыв.
Для JSON-сервиса понадобился штамп времени? Добавляем...

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

bnk>>Типы данных будет покорежены — возьмем например enum. В базе нужет int, в UI — string. Что делаем?


S>Так это по отдельности указывается с помощью атрибутов или Fluent


То есть сделать int/enum? а потом типа навешивать гроздьями атрибуты-конвертеры в строку для WCF или API? или сделать строкой?

bnk>>Нафик конструкторы. Бесполезная вещь в данном случае. Данные проверяются строго на пользовательском вводе, и больше нигде. А там WebAPI и всякие [Required], заботиться не о чем.


S>Идея такая -- нельзя создать объект класса, чтобы в нем не было обязательных полей. Зачем тогда вообще конструкторы с параметрами нужны? Или вы их вообще не используете никогда, отказались от концепции конструктора как такового?


Если больше одного-двух-трех — нет, в лес. Делаем проперти. Для DTO — да, никаких конструкторов.
Отредактировано 26.09.2017 21:14 bnk . Предыдущая версия . Еще …
Отредактировано 26.09.2017 21:05 bnk . Предыдущая версия .
Re[6]: Про бизнес-объекты: для сохранения, для API, для внут
От: Shmj Ниоткуда  
Дата: 26.09.17 21:59
Оценка:
Здравствуйте, bnk, Вы писали:

bnk>Ну конечно А атрибуты где определены? В слое данных (EF?) Добавляем референс на него, ага.

bnk>Дальше, атрибуты для WCF? Конечно, добавляем референс на него тоже. Дальше, что там, WebAPI, JSON, XML? да, еще референсы.

Доля истины в этом есть. Но многие атрибуты, к примеру Table, Key, Required, Display, NotMapped и пр. определены в системной сборке System.ComponentModel.DataAnnotations. Т.е. нет привязки к конкретной ORM, к примеру. Index, ForeignKey и пр. можно добавить с помощью Fluent API.

Если у вас во главе стоят бизнес-объекты, то ничего плохого в атрибутах нет.

Или же можно сделать их в виде интерфейсов. Но и там без атрибутов некоторых не обойтись...

bnk>Потом нужно передать пару дополнительных флажков для UI, и пару списков для комбобоксов? Конечно, добавляем поля и помечаем их всем чем нужно, для всех модулей не забыв.


А вы даже интерфейсы не определяете, просто делаете разные классы? Ни базового ни интерфейсов общих?

bnk>В общем я к чему — в результате получится класс данных, который "знает" все обо всех. Слишком много знает.


Оно и так и не так. В теории все атрибуты должны быть в System.ComponentModel.DataAnnotations. Но на практике не совсем так.

С другой стороны раз вы определили конкретные классы, а не контракты, то они и должны знать где их будут использовать. Или же тогда определять в виде контрактов-интерфейсов.

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

bnk>При модификации одной системы (базы например) придется держать в голове, как нужно пометить данную проперти, чтобы ничего не сломалось,
bnk>и чтобы она не прилетела, куда не нужно.

Да, соглашусь.

S>>Идея такая -- нельзя создать объект класса, чтобы в нем не было обязательных полей. Зачем тогда вообще конструкторы с параметрами нужны? Или вы их вообще не используете никогда, отказались от концепции конструктора как такового?


bnk>Если больше одного-двух-трех — нет, в лес. Делаем проперти. Для DTO — да, никаких конструкторов.


А зачем тогда вообще конструкторы с параметрами нужны? Может сразу запретить конструкторы с параметрами и всем станет проще жить?
Re[7]: Про бизнес-объекты: для сохранения, для API, для внут
От: bnk Австрия http://unmanagedvisio.com/
Дата: 26.09.17 22:14
Оценка:
Здравствуйте, Shmj, Вы писали:

S>А вы даже интерфейсы не определяете, просто делаете разные классы? Ни базового ни интерфейсов общих?


Ничего. Ни общего базового класса, ни интерфейсов. Просто разные классы с одинаково названными полями.

bnk>>Если больше одного-двух-трех — нет, в лес. Делаем проперти. Для DTO — да, никаких конструкторов.


S>А зачем тогда вообще конструкторы с параметрами нужны? Может сразу запретить конструкторы с параметрами и всем станет проще жить?


Ну речь же про DTO. Вот для DTO — не нужны. А вообще — бывает удобно. using сделать, эксепшен бросить, зависимости проинициализировать.. Для DI например.
Последнее кстати исключение — может быть больше аргументов. Но тут уже чисто технические ограничения используемого фреймворка.

Речь не только про конструктор. Вообще, зачем в фунцию передавать много аргументов? Если надо — обернул в объект, передал.
А то сделают конструктор типа
new UserInfo(string domain, string username, string gender, string title, string password)
— поди не перепутай аргументы при вызове
Отредактировано 26.09.2017 22:15 bnk . Предыдущая версия .
Re[3]: Про бизнес-объекты: для сохранения, для API, для внут
От: Kolesiki  
Дата: 27.09.17 16:15
Оценка:
Здравствуйте, Shmj, Вы писали:

S> Но как быть с другими свойствами? Если один объект для всего, то вообще нельзя создавать только get-свойства. Получается если передали объект в метод -- нет гарантий что он там не подвергнется изменениям.


По какой причине нельзя создавать get-only??
Re[3]: Про бизнес-объекты: для сохранения, для API, для внутреннего
От: Kolesiki  
Дата: 27.09.17 16:21
Оценка:
Здравствуйте, Shmj, Вы писали:

S>1. Если используете тот же EF CodeFirst, то нужно помечать атрибутами поля.


А если не используете, то не надо. Сугубо фишка EF.

S> А это значит что библиотека ваших контрактов будет иметь зависимость на конкретную ORM.


Ну и что? Вы много меняли ОРМов в одном и том же проекте? ОРМ — это не то, чтобы фундаментальная вещь, но всё же пишется не на один год (в отличии от JS библиотек). Да, у классов некоторые поля будут со специфичными атрибутами. Вам они жмут?


S>2. Все поля должны быть get и set


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

S>Фактически любой ваш объект может быть изменен в любом слое, вы не можете этого запретить.


А зачем мне что-то "запрещать" в собственном коде?? Ради чьей-то парадигмы? Это ты пишешь код — ты и решаешь, что изменять.
Re[4]: Про бизнес-объекты: для сохранения, для API, для внут
От: Shmj Ниоткуда  
Дата: 27.09.17 16:55
Оценка:
Здравствуйте, Kolesiki, Вы писали:

S>> Но как быть с другими свойствами? Если один объект для всего, то вообще нельзя создавать только get-свойства. Получается если передали объект в метод -- нет гарантий что он там не подвергнется изменениям.


K>По какой причине нельзя создавать get-only??


Если у вас один объект для всего, то в одном слое может требоваться set, а в другом только get. И дабы была универсальность вам везде нужно будет проставить и get и set.
Re[4]: Про бизнес-объекты: для сохранения, для API, для внутреннего
От: Shmj Ниоткуда  
Дата: 27.09.17 17:43
Оценка:
Здравствуйте, Kolesiki, Вы писали:

K>А если не используете, то не надо. Сугубо фишка EF.


То есть ваше решение не совместимо с EF?

S>> А это значит что библиотека ваших контрактов будет иметь зависимость на конкретную ORM.


K>Ну и что? Вы много меняли ОРМов в одном и том же проекте? ОРМ — это не то, чтобы фундаментальная вещь, но всё же пишется не на один год (в отличии от JS библиотек). Да, у классов некоторые поля будут со специфичными атрибутами. Вам они жмут?


Как уже сказали выше, ваш слой контрактов будет знать обо всем. Кроме того, атрибуты могут и конфликтовать -- для одного слоя нужна сериализация а для другого нет.

S>>2. Все поля должны быть get и set


K>Ваще не так. С чего это? Хочешь — заводи поля, хочешь — проперти (любого вида доступа). Главное — чтобы объект умел отдавать поля, нужные для базы и записывать те, которые берутся из базы (а это могут быть разные наборы).


А если в одном из слоев вы не хотите разрешать запись в свойство, в которое база должна уметь писать?

S>>Фактически любой ваш объект может быть изменен в любом слое, вы не можете этого запретить.

K>А зачем мне что-то "запрещать" в собственном коде?? Ради чьей-то парадигмы? Это ты пишешь код — ты и решаешь, что изменять.

А что другие ваш код не используют? Ну если чисто для себя -- согласен.
Re[3]: Про бизнес-объекты: для сохранения, для API, для внут
От: Vladek Россия Github
Дата: 27.09.17 22:45
Оценка: -2
Здравствуйте, Shmj, Вы писали:

S>Здравствуйте, Kolesiki, Вы писали:


K>>Вот с этого и надо начинать. Если некая свежепровозглашённая шиза не вписывается в практичную логику, это не "парадигма", а сферический конь в вакууме.


S>Ну почему шиза? Вы читали Guidelines https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/guidelines-for-collections ?

S>Те же коллекции не должны иметь set-еров по этим рекомендациям. А для XML-сериализации/десериализации, к примеру, они обязательны.


S>С коллекциями ошибся, оказывается и без сетеров сериализация работает. Но как быть с другими свойствами? Если один объект для всего, то вообще нельзя создавать только get-свойства. Получается если передали объект в метод -- нет гарантий что он там не подвергнется изменениям.


Просто потому что описанное — не ООП. Это не объекты и методы, а структуры данных и процедуры, существующие порознь.

Объекты инкапсулируют данные и процедуры, сгруппированные вместе, отражая сущность объекта.



Тебе не хватает выделенного.
http://files.rsdn.org/43395/hr-kyle-theisen-04.png
Re: Про бизнес-объекты: для сохранения, для API, для внутреннего
От: Doc Россия http://andrey.moveax.ru
Дата: 28.09.17 05:21
Оценка:
Здравствуйте, Shmj, Вы писали:

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


Если одинаковый на вид код имеет разное назначение, это разный код. )
В данной ситуации IMHO предпочтительнее собственные классы внутри слоев, решающие конкретные задачи, а не один класс, собирающий все что можно в кашу.
Re[5]: Про бизнес-объекты: для сохранения, для API, для внутреннего
От: Kolesiki  
Дата: 29.09.17 10:44
Оценка:
Здравствуйте, Shmj, Вы писали:

S>Здравствуйте, Kolesiki, Вы писали:


K>>А если не используете, то не надо. Сугубо фишка EF.


S>То есть ваше решение не совместимо с EF?


Т.е. моему решению пофиг, что за ОРМ используется — вешай атрибуты от любого!


S>Как уже сказали выше, ваш слой контрактов будет знать обо всем.


И что в этом плохого? Напомню, мы говорим про ОДИН объект на всё. Для каждого слоя объект имеет нужные атрибуты и проперти. А слоёв у нас — три.

S> Кроме того, атрибуты могут и конфликтовать -- для одного слоя нужна сериализация а для другого нет.


Глупости, это не "конфликт", а небольшой оверхэд. Какому слою надо, тот и сериализует (находя нужные именно ему атрибуты).


S>А если в одном из слоев вы не хотите разрешать запись в свойство, в которое база должна уметь писать?


Ну так а кто в этом слое полезет в проперть?? Нельзя писать — пометь комментом и не пиши!

S>А что другие ваш код не используют? Ну если чисто для себя -- согласен.


Вы так муторно заворачиваете всю эту проблему, будто у программиста только и головной боли, что "а кто в том слое хочет изменить мою бесценную проперть?!". Возможно, в каше слишком много разных круп — пересмотрите котелок.

Бизнес объект — это не какая-то недотрога, которую надо охранять — это данные, ваш бизнес-код должен ими оперировать и только. Где там взяться "чужому коду"?? А если и появляются "чужаки", так для этого (специфичного случая) специально надо архитектуру затачивать! Но уверяю, это не общий случай.
Пару раз у меня были моменты, когда некие данные не должны были быть видимы. Сделал элементарнейший метод клонирования, который в копию передавал только видимые данные и отправлял объект другому модулю — всего делов-то!
Был ещё момент, когда некие данные категорически нельзя перезаписывать (в базе). Моё решение: из базы считываю ОРМ-объект, перезаписываю свежие данные тлько нужных пропертей, сохраняю обратно. Таким образом ты можешь коверкать проперти, но они никогда не испортят систему.

Короче, специфичные бизнес-случаи, которые вовсе не обязательно тащить на уровень архитектуры. Бонусом послужил простой, поддерживаемый код — первоочередное свойство у интыпрайзных решений. А если у меня на каждый слой/модуль/свистелку будет свой набор классов... ё-моё... я повешусь поддерживая это в консистентном состоянии! Таблицы — они не то, чтоб часто менялись, но их изменения не должны превращаться в недельный аудит кода "где я тут проперть делал ридонли??". Нафик, чем проще — тем понятнее.
Re: Вижу: DRY, копипаста
От: igor-booch Россия  
Дата: 08.10.17 14:00
Оценка:
По сути несколько классов с похожей структурой это копипаста со всеми вытекающими последствиям.
Добавление поля требует изменений не в одном классе, а в нескольких. И попробуй ошибись. А если изменения более сложные чем добавление поля (изменились связи между классами)?
Между тем в старпапе изменения структуры данных вполне нормальная вещь. Да, клиенты не знают чего хотят или знают но не могут объяснить, с этим нужно смириться. И при этом готовый к продакшену продукт нужно получить в кратчайшие сроки. Поэтому по возможности я делаю универсальные классы.
Отвечайте на это сообщение, только если у Вас хорошее настроение и в Вашем ответе планируются только конструктивные вопросы и замечания
http://rsdn.ru/Info/rules.xml
Re: Про бизнес-объекты: для сохранения, для API, для внутреннего
От: rm822 Россия  
Дата: 08.10.17 14:25
Оценка:
S>Видите ли вы проблему в том что по сути одни и те же данные по многу раз приходится копировать из одной структуры в другую лишь по той причине, что они применяются в разных слоях (но по стуи одинаковые сущности)?
Да, это проблема, когда объектов становится >1млн. И в чем вопрос?
Re[2]: Вижу: DRY, копипаста
От: Shmj Ниоткуда  
Дата: 09.10.17 01:09
Оценка:
Здравствуйте, igor-booch, Вы писали:

IB>По сути несколько классов с похожей структурой это копипаста со всеми вытекающими последствиям.

IB>Добавление поля требует изменений не в одном классе, а в нескольких. И попробуй ошибись. А если изменения более сложные чем добавление поля (изменились связи между классами)?

А как вы смотрите на использование интерфейсов в качестве основы/скелета бизнес-объектов для всех слоев?
Re[2]: Про бизнес-объекты: для сохранения, для API, для внутреннего
От: Shmj Ниоткуда  
Дата: 09.10.17 02:16
Оценка:
Здравствуйте, rm822, Вы писали:

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

R>Да, это проблема, когда объектов становится >1млн. И в чем вопрос?

А если 10 тыс. -- то не проблема?
Re[3]: Про бизнес-объекты: для сохранения, для API, для внутреннего
От: rm822 Россия  
Дата: 09.10.17 06:16
Оценка:
S>А если 10 тыс. -- то не проблема?
как правило — нет, мало...
Re[3]: Вижу: DRY, копипаста
От: igor-booch Россия  
Дата: 09.10.17 10:21
Оценка:
S>А как вы смотрите на использование интерфейсов в качестве основы/скелета бизнес-объектов для всех слоев?

Я не уверен, что правильно понимаю Вашу технологию интерфейсов. Допустим есть слой доступа к данным. Есть web приложение и десктоп приложение. Web приложение и десктоп приложение умеют сохранять заказ, используя при этом слой доступа к данным. Какие где будут классы и интерфейсы?
Отвечайте на это сообщение, только если у Вас хорошее настроение и в Вашем ответе планируются только конструктивные вопросы и замечания
http://rsdn.ru/Info/rules.xml
Re[4]: Вижу: DRY, копипаста
От: Shmj Ниоткуда  
Дата: 10.10.17 03:00
Оценка:
Здравствуйте, igor-booch, Вы писали:

IB>Я не уверен, что правильно понимаю Вашу технологию интерфейсов. Допустим есть слой доступа к данным. Есть web приложение и десктоп приложение. Web приложение и десктоп приложение умеют сохранять заказ, используя при этом слой доступа к данным. Какие где будут классы и интерфейсы?


1. Выделяете слой сервисов, реализация которых не зависит от GUI. Создаете контракты для каждого сервиса. К примеру, будет интерфейс IOrderService. А в нем метод CreateOrder(IOrder order). Так вот IOrder -- тоже интерфейс, но уже для бизнес-объекта.

2. В реализации сервиса IOrderService делаете класс OrderService, который реализует метод CreateOrder. А так же в реализации сервисов делаете класс бизнес-объекта Order, который реализует IOrder (делается одной кнопкой). И у этого класса уже проставляете нужные вам поля.

3. Web-приложение и десктоп-приложение работают не с сервисом OrderService, а с контрактами IOrderService. Конкретную реализацию подключаете с помощью IoC (есть готовые либы типа Unity и пр.).

4. Web-приложение делает свой класс-реализацию IOrder. Причем может добавлять доп. поля и доп. атрибуты, которые нужны ему. Соответственно десктоп-приложение делает то же самое -- свои доп. поля и атрибуты.

5. Если вы измените какое-либо поле в контракте или добавите новое -- компилятор сразу же сообщит об этом, т.е. не забудете исправить во всех слоях.
Отредактировано 10.10.2017 3:51 Shmj . Предыдущая версия .
Re[5]: Вижу: DRY, копипаста
От: igor-booch Россия  
Дата: 10.10.17 08:34
Оценка:
S>5. Если вы измените какое-либо поле в контракте или добавите новое -- компилятор сразу же сообщит об этом, т.е. не забудете исправить во всех слоях.

Это весомое преимущество. Конечно я за интерфейсы. Какие еще Вы видите профиты от интерфейсов в рассматриваемом сценарии? Я вижу следующее преимущество: можно навесить логику на интерфейс IOrder (например, в виде экстеншен методов), поместить её в сборку вместе интерфейсом IOrder и использовать эту логику в десктопе и веб приложении (десктоп и веб приложение ссылаются на сборку с интерфейсом).

В случае если с десктопа и с веб приложения был бы допустим прямой доступ к БД, я бы сделал проще.
Слой доступа к данным (имеющий прямой доступ к БД) реализуем в сборке. Десктоп и веб приложение просто ссылаются на эту сборку.
Если веб приложению понадобятся доп. свойства у Order,
в сборке веб приложения создаем наследника WebOrder : Order. Аналогично для десктопа.
В этом случае интерфейс IOrder не нужен. Вернее он может понадобиться, но только как часть бизнес модели, но не как технический интерфейс для обеспечения инфраструктуры слоёв (скелета бизнес объектов, как Вы сказали).
Если кому-то понадобился непрямой доступ к БД (через сервис), оборачиваем ту же сборку доступа к данным в сервис, и тогда технический интерфейсы для обеспечения инфраструктуры слоёв становятся нужны. Но в этом случае логику на инфраструктурный интерфейс IOrder уже не навесишь (как я выше написал), так как она уже в классе Order присутствует.
Но я сторонник прямого доступа к БД с десктопа (с веб приложения тем более). Да, надо поработать над безопасностью, правами доступа пользователей на уровне БД, SSL соединением клиента С БД, но дело того стоит. Не надо создавать сервис доступа к БД, только для того чтобы не возиться с её настройками безопасности.

S>3. Web-приложение и десктоп-приложение работают не с сервисом OrderService, а с контрактами IOrderService. Конкретную реализацию подключаете с помощью IoC (есть готовые либы типа Unity и пр.).

Несколько различных реализаций IOrderService кроме тестирования может ещё для чего-то понадобиться?
Отвечайте на это сообщение, только если у Вас хорошее настроение и в Вашем ответе планируются только конструктивные вопросы и замечания
http://rsdn.ru/Info/rules.xml
Отредактировано 10.10.2017 15:17 igor-booch . Предыдущая версия . Еще …
Отредактировано 10.10.2017 10:12 igor-booch . Предыдущая версия .
Отредактировано 10.10.2017 10:10 igor-booch . Предыдущая версия .
Отредактировано 10.10.2017 9:34 igor-booch . Предыдущая версия .
Отредактировано 10.10.2017 9:00 igor-booch . Предыдущая версия .
Отредактировано 10.10.2017 8:59 igor-booch . Предыдущая версия .
Отредактировано 10.10.2017 8:36 igor-booch . Предыдущая версия .
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.