Имя: Пароль:
IT
1C 7.7
v7: Принципы «правильного» структурирования кода
0 Emery
 
13.04.16
13:28
При большом объеме программного кода возникает проблема эффективного управления им. Особенно это заметно, когда прошло достаточно много времени и прежде, чем что-либо изменить в собственном коде, не говоря уже о чужом, приходится тратить много времени на повторное освоение давно написанного и уже подзабытого. Также затруднительно вносить какие-либо существенные изменения. Часто проще, переписать весь проект заново, чем серьезно изменять существующий код. Не зря говорится в среде программистов: «Работает – не трожь!»

Конечно, в разных системах программирования есть разные возможности по структурированию кода. Самые важные из них это модульность и следование «правильным» принципам оформления исходного текста. Естественно, что процедурное программирование будет отличаться, от объектно-ориентированного или там клиент-серверного. Тем не менее, уверен, что вполне можно говорить об общих принципах.

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

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

В начальной процедуре пишем нечто вроде:

Процедура ПриОткрытии()
    Если ИницСправочников() = 0 Тогда
        Перейти ~Финиш;
    КонецЕсли;                          

    Если ИницПарамФормы() = 0 Тогда
        Перейти ~Финиш;
    КонецЕсли;

    // . . .

~Финиш:
    СтатусВозврата(0); // Данная команда не даст открыться форме обработки
    Возврат;  
КонецПроцедуры

Во второй функции пишем нечто вроде:

Функция ИницПарамФормы()
    Если ПроверкаИсходнДанных() = 0 Тогда
        Возврат 0;
    КонецЕсли;                          
    
    Если ПолучитьКонтВызывФормы() = 0 Тогда
        Возврат 0;
    КонецЕсли;                          
    
    Если ОбработатьИсточнДанных() = 0 Тогда
        Возврат 0;
    КонецЕсли;                          
    
    // . . .

    Возврат 1;
КонецФункции // ИницПарамФормы()

И т.д. и т.п. Только в конечных функциях код может быть нелинеен, но должен быть достаточно простым для восприятия и хорошо задокументирован.

Полагаю, идея линеаризация кода понятна. Правда она достигается ценой большого количества общих переменных модуля. А «семерка» это, «восьмерка» или «девятка», не суть важно. В С++ можно программировать аналогично, разве что модули там определяются программистом.

Вопрос, собственно говоря, в одном. Всё это хорошо, но одна неустранимая сложность все-таки возникает. Большое количество функций в модуле, даже если они обслуживают только одну задачу, вносит излишнюю путаницу. Как этого избежать?

Мое мнение, НУЖНО ПРОГРАММИРОВАТЬ КОД КАК ГИПЕРТЕКСТ. Одних сверток тел функций явно недостаточно. К сожалению, я не знаю систем программирования, предоставляющих подобный функционал. В принципе можно оформлять подобный гипертекст в MS Word либо аналогичных текстовых процессорах. Однако сказать, что это будет удобно, совершенно невозможно.

Какие ваши идеи?
1 Рэйв
 
13.04.16
13:30
Используй
#Область Какаято
#КонецОбласти

и будет тебе счастье
2 Тролль главный
 
13.04.16
13:30
за такое обилие goto надо бить ссаными тряпками
3 mingw
 
13.04.16
13:32
4 Маратыч
 
13.04.16
13:33
(2) Угу, ща Дейкстра восстанет и покарает ТС.

З.Ы. Кто-нибудь вообще в конфах безусловный переход юзает?
5 mingw
 
13.04.16
13:34
(4) >Кто-нибудь вообще в конфах безусловный переход юзает?
Только кто не умеет нормально программировать?
6 Nikoss
 
13.04.16
13:34
(4) Как прерывать выполнение нескольких вложенных циклов сразу, без нагромождения условий?
7 Маратыч
 
13.04.16
13:35
(5) Ну я хз, может, кто-нибудь наткнулся на безвыходную ситуацию, которая мне даже в воображении не является :)
8 Gary417
 
13.04.16
13:36
помоему я слышал лишь об одном вменяемой причине для чего надо goto использовать, выход из множественного вложенного цикла
9 asady
 
13.04.16
13:36
(0) а вместо гоуту возврат поюзать?
10 Encode
 
13.04.16
13:36
(0) Хочется взять и уе*** "Совершенным кодом" Макконела
11 Тролль главный
 
13.04.16
13:37
(6) забыл как-там в 7.7, но не помню когда в 8-ке приходилось писать циклы вложенности больше 2
12 Маратыч
 
13.04.16
13:38
(6) Нагромождением условий. С goto получаем бардак плохо читаемый. Если в одном из циклов окажется необходимость вкорячить кусок кода после завершения вложенного, получаем матюкающегося кодера, либо вставляющего условия с возвратом, либо, если дно уже пробито, добавляющего еще одну метку. Что, как правило, и происходит.

Да и большая вложенность циклов как бы намекает на рефакторинг.
13 Aceforg
 
13.04.16
13:38
Группировка циклов и условий поможет понять спагетти
http://screencast.com/t/8dfToccFKw4
14 orefkov
 
13.04.16
13:38
(6)
Вынести нагромождение циклов в отдельную функцию и использовать Возврат :)
15 mingw
 
13.04.16
13:38
(8) Прекрасно можно выйти из такого цикла установкой итераторов в нужное. И можно в циклы добавить условия для выхода заранее.

(7) Даже если вас съели у вас есть как минимум 2 выхода.
16 Маратыч
 
13.04.16
13:40
(15) То-то и оно, что ко второму выходу опускаться легче.
17 Emery
 
13.04.16
13:40
Здесь GoTo (Перейти) используется сознательно и только для упрощения кода. Иначе нужно много раз писать строки:

СтатусВозврата(0);
Возврат;  

Еще он нужен для быстрого входа из многоуровневых циклов. Больше особого применения я для него не вижу.
18 mehfk
 
13.04.16
13:41
(5) В Альфе 5-й есть. Альфа это вообще сборник канонических примеров как не надо делать.
19 zak555
 
13.04.16
13:42
что за извращение использовать перейти ?
20 orefkov
 
13.04.16
13:43
(0)
Что значит "код как гипертекст"?
Да и "большое количество функций в модуле" не приводит к путанице, а наоборот, делает код более выразительным семантически и легче тестируемым. Другое дело, что в 1С нет оптимизатора на этапе выполнения, который на "нижнем уровне" всё это заинлайнит, как "у больших".
21 Gary417
 
13.04.16
13:43
(15) писанины много плюс анализ нужных значений итераторов, а тут две строчки
22 Gary417
 
13.04.16
13:43
(21) +я никогда так не делал, но читал про goto и там это описывалось что это чутьли не единственный оправданный шаблон
23 Emery
 
13.04.16
13:44
Ключевые слова здесь: «НУЖНО ПРОГРАММИРОВАТЬ КОД КАК ГИПЕРТЕКСТ», издержки безусловных переходов мы все понимаем.
24 orefkov
 
13.04.16
13:45
(22)
В javascript просто сделали break и continue, в котором можно указать для какого оно цикла :)
25 mingw
 
13.04.16
13:47
(23) еще больше goto ? гиперссылка это же по сути переход
26 фобка
 
13.04.16
13:47
Не знаю ситуаций в которых нельзя обойтись без goto
27 Карупян
 
13.04.16
13:47
(24) там просто свместили брейк и гото
28 Gary417
 
13.04.16
13:49
(26) поэтому его никто и не использует уже...я вообще его со времён бейсика не видел...
29 Gary417
 
13.04.16
13:50
вру....в bat скриптах виндовых он используется
30 mingw
 
13.04.16
13:51
(29) Там с процедурами/функциями плохо.
31 Emery
 
13.04.16
13:52
(20) > Что значит "код как гипертекст"?

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

> Да и "большое количество функций в модуле" не приводит к путанице,
> а наоборот, делает код более выразительным семантически и легче тестируемым.

Не согласен, иначе не создавал бы тему. Просто обозначаю свою хотелку: ХОЧУ программировать код  как гипертекст. Как это проще всего сделать?
32 Турист
 
13.04.16
13:52
(29) и еще ассемблер ))
33 Dotoshin
 
13.04.16
13:53
34 Турист
 
13.04.16
13:54
(31) попробуй редакторы с плагинами типа атома
35 Emery
 
13.04.16
13:55
(25) > еще больше goto ? гиперссылка это же по сути переход

Но это не переход управления в коде! Это переход в тексте кода на место где этот код расположен. И совершенно не обязательно располагать логически связный код на одной странице.
36 mingw
 
13.04.16
13:56
(31) Почитать Кнута. Понять что уже все есть. Правой кнопкой по процедуре/функции и Перейти к определению
37 Карупян
 
13.04.16
13:58
(31) так вроде во всех IDE так и есть (кроме 1с 77, даже в 8 есть)
38 mingw
 
13.04.16
13:58
(35) А кому то хочется по прежнему г0вно-спагетти-кодить. И спрашивает про инструмент для облегчения такого кодинга.
Чтобы по goto-гиперссылкам переходить.
39 Карупян
 
13.04.16
13:59
те получается структурное программирование - это ОТСУТСТВИЕ goto
40 koreav
 
13.04.16
14:04
(39)
можно и без goto, с помощью "Вычислить" т.е.

Процедура ПриОткрытии()

    Вычислить(ПолучитьКодПриОткрытии());
41 Emery
 
13.04.16
14:04
(33) Это не совсем то. Там все правильно для кода одного цельного модуля размещенного на одной странице текста. Меня интересует гипертекстовое размещение одного цельного модуля на нескольких страницах текста. Можно, в принципе, самому создавать разные файлы и переходить вручную либо с помощью средств, вроде «перейти к определению функции». Но это не слишком удобно.
42 Emery
 
13.04.16
14:06
(34) > попробуй редакторы с плагинами типа атома

Имеется в виду Eclipse?
43 Локи-13
 
13.04.16
14:06
(41) так все конфы так построены, в бсп вообще чорт ногу сломит на скольких станицах раскиданы процедуры и функции
44 Drac0
 
13.04.16
14:09
(31) F12? 0_o
45 Лефмихалыч
 
13.04.16
14:10
(0) феерическая расстановка точек...

1. >Вот мне кажется, что все процедуры должны быть оформлены в виде функций
бред сивой кобылы

2. >Далее, код должен быть максимально линеаризованным
возможно, только без конкретики это не разговор.

3. >Перейти ~Финиш
Рисовать "готов" в ветке про правильный код - это тот еще финиш

4. общие переменные модуля - это такой же быдлокод, как и "готы". Так делают только мудаки.

5. >К сожалению, я не знаю систем программирования
судя по сабжу, ты вообще не в свою область в принципе влез
46 spock
 
13.04.16
14:11
(0)Программировать код, как гипертекст:

...какой-то код...
..
ВызватьГипертекст();
...
...какой-то код...


Функция ВызватьГипертекст()
   ...какой-то код...
   ...
   ...какой-то код...
КонецФункции // ВызватьГипертекст()

Таким образом, я просто и незамысловато перешел по гиперссылке.
47 Локи-13
 
13.04.16
14:11
и кстати "НУЖНО ПРОГРАММИРОВАТЬ КОД КАК ГИПЕРТЕКСТ."

не подойдет, разные задачи.

У гипертекста задача привезти тебя из пункта А в пункт Б.

А код должен восприниматься как нечто целое. Ты не должен начинать с яблока, а заканчивать помидором.
48 Живой Ископаемый
 
13.04.16
14:12
"правильно структурированный код". чуваки, вы ведь хотели асинхронного программирования в 1С? Уже начинает появляться. А асинхронные вызовы - это тот еще спагети-код, даже без гоуту.

Так что сабж (0) уже безнадежно устарел.
49 Emery
 
13.04.16
14:14
(31) > Почитать Кнута. Понять что уже все есть.

Читал, еще в детстве :) . Более того изобрел собственный метод сортировки, которого не было у Кнута ( http://emery-emerald.narod.ru/Cpp/2E1562.html ).

> Правой кнопкой по процедуре/функции и Перейти к определению

Это хорошо если все функции находятся в одном модуле. Но речь идет об одном логическом модуле, расположенном в нескольких физических модулях. В «восьмерке» это не упрощает ситуацию. Дробить искусственно модули не комильфо. Нужны встроенные средства на уровне системы.
50 Локи-13
 
13.04.16
14:15
(48) Уже начинает появляться? Да уже во всю используется!

Десятки мать их оповещений, с передающимися оповещенияами вызывающими оповещения.
51 Живой Ископаемый
 
13.04.16
14:17
2(50) Ну, я все-таки считаю что пока только начинают. Но да.
И представьте, автор столкнется с ними. Могу себе представить его батхерт
52 Михаил 1С
 
13.04.16
14:17
(33) Спасибо за ссылку.

ПС: почему-то никто ее не заметил, болтают о своем, будто бы ее и не было.
53 mingw
 
13.04.16
14:19
(49) >Более того изобрел собственный метод сортировки, которого не было у Кнута

У Кнута много чего не было. Но кто то явно не в курсе про индексы в БД и сами БД с их сортировками.
54 mingw
 
13.04.16
14:20
55 Локи-13
 
13.04.16
14:24
У 1С в целом все норм, бесит только то что у внешних обработок и отчетов нет модуля менеджера
56 mingw
 
13.04.16
14:28
(55) Я однажды на этом лоханулся. Сделав обработку внешней и отправив заказчику.
57 Тролль главный
 
13.04.16
14:35
(55) у 1С нет типизации и ООП, у 1С далеко не всё норм
58 mingw
 
13.04.16
14:38
(57) Типизация зачем? ООП нет только наследования дальше 1 уровня. Т.е. нельзя от своих объектов другие свои отнаследовать.
59 Злопчинский
 
13.04.16
14:38
(4) ну я юзаю ИНОГДА очень редко и что? в сложных условиях. на мой взгляд проще написать

//какая-то хрень
Перейти ~ФинишНеуспешно;
//
~ФинишНеуспешно:
//всякая длинная хрень много кода
Возврат -1;
КонецФункции

чем  
//какая-то хрень
//собрать в параметры передаваемые данные
Возврат ФункциянеУспешногоВозврата(тутнахерачитьдофигапараметров);
//дальнейшая хрень
//тут опять насобирать кучу параметров для передчаи
Возврат ФункциянеУспешногоВозврата(тутнахерачитьдофигапараметров);;
КонецФункции

Вопрос использования готу - имхо почти всегда проблема архитектуры решения/кода. всем при выставлении задач выделяется ДОСТАТОЧНО ВРЕМЕНИ для глубокой проработки архитектуры?
60 Тролль главный
 
13.04.16
14:39
+(57) у 1С есть пустые ссылки и Неопределено, это плохо

я не против Неопределено как аналог пустого указателя (nil в паскале, nullptr в с++, null в c#/java), чтобы отличать от null в субд. Но зачем оно хранится в БД?
61 Тролль главный
 
13.04.16
14:41
(58) >>Типизация зачем?
если такой вопрос задаешь, то тебе она не нужна
>>ООП нет только наследования дальше 1 уровня

а как следствие нет protected, нет interface, нет override (кроме "утиной")
62 Карупян
 
13.04.16
14:44
Отсутствие типизации это не плюс или минус - это просто другая идеология
63 Злопчинский
 
13.04.16
14:45
(61) да и фиг бы с ним что нет. извернулись бы. в клюшках же как-то изворачивались вполне.
главное - чтобы работало устойчиво.
64 Тролль главный
 
13.04.16
14:45
(62) согласен
вот я бы сделал свободную типизацию в отчетах
и строгую в логике проведения
65 mingw
 
13.04.16
14:46
(61) В JS есть типизация? В java есть. Ее наличие/отсутствие никоим образом не мешает нормально кодить.
Минус отсутствия типизации (динамическая типизация) что пока значение не присвоили не узнать его тип.
Но это не минус а плюс. Меньше г0внокода с лишней универсализацией.
66 Тролль главный
 
13.04.16
14:47
(65) зато ран-тайм ошибок больше, когда от данных требуют того, чем они не являются
67 mingw
 
13.04.16
14:48
(66) А нефиг трайкатчить. Пишите так чтобы не было рантайм ошибок.
68 Тролль главный
 
13.04.16
14:48
(67) ну извини, я не идеальный программист, делаю ошибки
69 myk0lka
 
13.04.16
14:51
Безусловные переходы - это ИМХО всё же зло.
Даже когда торопишься - лучше потратить немного дополнительного времени, но написать всё без этих костылей.
Потом сам себе за это скажешь спасибо, когда понадобиться что-то там дорабатывать.

А по поводу (57) - об этом, если я не ошибаюсь, тру-проги сокрушаются с самого появления клюшек, если не раньше.
Но тем не менее до сих пор язык позволяет решать все задачи.
В таком случае вопрос - а нужно ли оно в 1С?
70 Broadbread
 
13.04.16
14:53
(67) Исключения приходят извне. По крайней мере должны.
71 Живой Ископаемый
 
13.04.16
14:54
еще раз - "Безусловные переходы - это ИМХО всё же зло. " - асинхронные вызовы, и подписка-нотификация - это по сути те же самые безусловные переходы.


То есть ваша программа с точки зрения структурного программирования может быть идеальной, но код уже не линейный, и вы не сможете глядя на него что в какой момент исполняется.
72 mingw
 
13.04.16
14:54
(68) добавляйте тип переменной в ее название:
лчМоеЧисло=1;
лсМояСтрока = "1";
лдМояДата = ...
73 Карупян
 
13.04.16
14:55
(72) А смысл?
74 mingw
 
13.04.16
14:56
(73) визуальная типизация для тех кто путает переменные и их типы.
75 Злопчинский
 
13.04.16
14:57
осталось где-то внутри функции по полученному параметру определить имяэтогопараметра...
Функция(этоЧислоИлиСтрока)
76 Злопчинский
 
13.04.16
14:58
мну как-то совсем не мешал 1сный вариант типизации.
77 Локи-13
 
13.04.16
15:00
(57) назови хоть одну задачу для автоматизации, где прям требуется ООП или типизация
78 Тролль главный
 
13.04.16
15:00
(72) а если ДокументОбъект.РеализацияТоваровУслуг?
79 Карупян
 
13.04.16
15:02
(77) Это придумали не потому чтоэто прям требуется.
А для облегчения разработки
80 Локи-13
 
13.04.16
15:06
(79) и что ж там облегчается то?
81 mingw
 
13.04.16
15:06
(78) прикинь так и пишу обычно
РТиУВыборка = ...
РТиУСсылка = ...
РТиУОбъект = ...
82 Локи-13
 
13.04.16
15:06
все хотят ооп, но никто не занет зачем
83 Тролль главный
 
13.04.16
15:06
(77) любая ООП программа может быть написана без ООП
84 mingw
 
13.04.16
15:08
(82) считают что если выучат кунфу то смогут побить кого угодно?
85 quest
 
13.04.16
15:08
все эти беды - не от ума, а от его отсутствия. Изучите пару языков отличных от 1С (а еще лучше - вообще с другой парадигмой) и вы поймете что эти проблемы не от оформления кода, а от кодера который сделал тяп/ляп и забыл воткнуть комментарий к функции. Нормальный код читается как хороший рассказ, при использовании нормального редактора (емакс, например) - так и вообще как поэма.
86 4St
 
13.04.16
15:08
GOTO бывает незаменим внутри "Выполнить", поскольку там нельзя вызывать "Возврат". В остальных случаях - на усмотрение разработчика.

Вложенность циклов или условий более 2-3 - плохой признак. Значит, скоро там кто-то запутается.

Глобальные переменные - зло, особенно для УФ. Во многих случаях они легко заменяются на одноименные функции, которые уже можно кэшировать в каком-нибудь Соответствии. Потерь скорости практически нет.

Свертка кода - приятная фича, но можно спокойно жить и без нее. Точка входа, F12, F12, ....
87 Broadbread
 
13.04.16
15:08
(77) Нет ни одной задачи автоматизации, которую нельзя решить при помощи асма.
88 Карупян
 
13.04.16
15:09
(81) А посложнее
СхемаКомпоновкиДанныхДляВыводаВТабличныйДокументИмениБорисаНуралиева (с)
89 quest
 
13.04.16
15:10
(85)+ и второе - код не надо писать. Его надо генерировать. Но данная нам объективной реальности 1С - не умеет этого делать. Ибо те кто планируют разработку платформы и введение новых возможностей - *удаки.
90 Локи-13
 
13.04.16
15:10
(87) есть:
создай каталог телефонных номеров за 10 минут, с поиском и сортировкой по имени, фамилии, отчеству и городу
91 quest
 
13.04.16
15:11
(87) используя bones можно решать легко на scheme
92 mingw
 
13.04.16
15:11
(88) скдЖе

(86) Вот про Выполнить() не подумал. Наверно потому что не пользуюсь. Проще так не издеваться и свой "выполнитель скриптов" наваять спец. Даже несколько разных с нужным функционалом.
93 Broadbread
 
13.04.16
15:11
(90) Где там код?
94 Тролль главный
 
13.04.16
15:12
вот это по сути про ООП  http://v8.1c.ru/o7/201603module/index.htm
единственное сделано через ж...
95 quest
 
13.04.16
15:12
(86) а еще в eval()  можно обратно в цикл зайти, и много прикольных плюшек поиметь. Ну нахер такой изврат.
96 mingw
 
13.04.16
15:14
(94) Уже сейчас в типовых никакой поллитры не хватит чтобы разобраться. После использования этого в типовых они станут черными ящиками.
И будет проще свои ящики объекты (справочники и документы) ваять чем править существующие.
97 orefkov
 
13.04.16
15:14
(31)
А, понял. То есть вы просто не знаете хоткей "F12" и "Ctrl + Shift + -" в Конфигураторе? Бывает.
98 mingw
 
13.04.16
15:15
(97) а еще там отладчик есть и СП "от Дениса"
99 Timon1405
 
13.04.16
15:16
(97) Обратный переход вроде просто ctrl+"-"
100 Локи-13
 
13.04.16
15:16
(93) вот и я том же
(94) не надо свои педали прикручивать к нашей лодке
это не для ооп, это для других задач
101 orefkov
 
13.04.16
15:17
(99)
Возможно. Навскидку не помню, я его всегда на Alt-Left переназначаю, привычка.
102 Локи-13
 
13.04.16
15:18
(97) (99) не то и не другое, забыл не могу вспомнить (
вы оба написали сворачивание группировки
103 Карупян
 
13.04.16
15:18
(94) Это скорее не ООП, АОП (аспектно-ориентированное)
104 Timon1405
 
13.04.16
15:20
(102) Нет, мы все правильно пишем. Сворачивание - это контрол-шифт-NUM-, а тут ctrl+"ОбычныйМинусНеНумпадовский"
105 Локи-13
 
13.04.16
15:20
(104) блин, точно, есть же другой минус
106 Локи-13
 
13.04.16
15:21
контрол-шифт-NUM- это свернуть все
контрол-NUM- свернуть текущую группировку
107 Broadbread
 
13.04.16
15:28
(100) >вот и я том же
Одинэса там тоже нет.
108 Локи-13
 
13.04.16
15:32
(107) на 1С это делается за 10 минут без сточки кода

Все разжевывать нужно чтоли? Нет задач в 1С где нужен ООП.
Для любых возникающих задач хватает того что есть, но даже для самых извращенных можно подключить внешнюю компоненту.
109 Broadbread
 
13.04.16
15:32
(91) Используя питон можно легко и непринуждённо генерить код фокспро.
110 Broadbread
 
13.04.16
15:33
(108) На экселе создаётся новый документ.
111 Broadbread
 
13.04.16
15:34
(108) В опу 1С - речь шла о задачах автоматизации вообще.
112 Локи-13
 
13.04.16
15:37
(110) на экселе тоже можно решать задачи. но только небольшого определенного круга.
(111) с фига ли? читай (57)
113 Broadbread
 
13.04.16
15:38
(112) Читай своё же (77)
114 quest
 
13.04.16
15:39
(109) но фокпрос не умеет копилироватся на асм. а схема через кости - может
115 Локи-13
 
13.04.16
15:42
(113) Не тупи, вопрос был про задачу автоматизации на 1С, т.к. (77) ответ на (57) который об 1С

и с такой логикой тебе давать ООП? нет уж, извольте.
116 Broadbread
 
13.04.16
15:43
(115) Не выкручивайся.
117 Broadbread
 
13.04.16
15:45
(114) И это хорошо.
118 Лефмихалыч
 
13.04.16
15:45
(59) ты ИНОГДА плохой и негодный программист, но очень редко
119 Broadbread
 
13.04.16
16:34
В одной C#-кальке с 1С было приятно кодить. Прямо крылья расправлялись.
120 mingw
 
13.04.16
17:13
(119) и где эти решения то? речь про NG Framework?
121 Emery
 
13.04.16
18:22
(97)  > А, понял. То есть вы просто не знаете хоткей "F12" и "Ctrl + Shift + -" в Конфигураторе? Бывает.

Переход на определения функций и сворачивание / их тел это не полноценный гипертекст. Смотрите, лучше всего дела обстоят в VC++. Допустим там мы определили два класса в файлах SomeClass.h и SomeClass.cpp. Пусть в классе под сотню функций, не считая определений констант и переменных. Естественно, ничто нам не мешает нам на имени некоторой функции нажать F12 или Ctrl+F12 (перейти к определению или к объявлению) либо просто показать определения, никуда не переходя (Alt+F12). Можно даже там найти все ссылки (Shift+F12), показать иерархию вызовов (Crrl+KT) и много чего еще. Все это просто великолепно. Но хочется большего. Например, я хочу каждую функцию видеть на отдельной странице / закладке нашей IDE. Не суть важно, чтобы это было сто файлов для одного класса, которые еще замучаешься компоновать всякими #include и т.п. Но, отображения разных функций я хочу в видеть в разных окнах, чтобы не отвлекаться на «лишний» код. Вот, что я имею в виду под гипертекстом – отображение / визуализацию кода на разных страницах IDE, но не обязательно в разных файлах. С файлами я и так могу делать, что хочу.
122 Gary417
 
13.04.16
18:31
гипертекст... "..Конгресс, немцы какие-то... голова пухнет! ..." (c)


оч сомневаюсь что у вас получится какуюто новую концепцию придумать. Все эти хотелки с функциями в новых окнах реализуются силами IDE, такое и в эклипсе и в нетбинсе, и прочих вижуалстудиях при желании можно сделать. Но вот разрекламить чтобы этим стали пользоватся? Вопрос... я вот сколько раз не перечитал тему...ну никак не могу въехать в чём удобность такого подхода... по отдельности всё понимаю, а в целом нет.
123 mingw
 
13.04.16
18:38
(122) в спагетти-коде с кучей goto проблема понять в многоэкранных портянках это все еще та же функция или уже другая

вот ТС и хочет чтобы каждая функция на отдельной закладке, и случайно спагетину с другой функции не засосать
124 Fragster
 
гуру
13.04.16
18:40
125 Broadbread
 
13.04.16
19:08
(120) Ага. Вроде оно.
126 Emery
 
13.04.16
19:24
(122) До сих пор программный код ЯВУ представлен в виде обычного текста. Я хочу, чтобы это был гипертекст. И так, наверное, будет, рано или поздно. А навигацию по коду удобно делать мышкой, как, например, в справочной системе Qt. А на верхней панели чтобы были стрелочки вперед / назад по дереву навигации. Нужно еще, чтобы любая страница кода сразу же могла редактироваться в стиле MS Word. Идеологически это похоже на высокоразвитые средства разработки сайтов. Пока  наиболее близкий по реализации продукт – последняя версия MS VS C++. Думаю, мелкософт здесь движется в правильном направлении.
127 Gary417
 
13.04.16
19:32
<Идеологически это похоже на высокоразвитые средства разработки сайтов>

Это какие например?
128 Gary417
 
13.04.16
19:33
(126) <последняя версия MS VS C++>

Это называется MS Visual Studio
129 mingw
 
13.04.16
19:38
(126) Понятно. Можно сделать через IDE. Это просто интерфейс.
Использование функции в коде помечается гиперссылкой. При нажатии нее автоматом переход в  код этой функции.

Но не сможете пользоваться таким. Неудобно будет. Например переименование функции как?
130 Emery
 
13.04.16
19:49
(129) > Использование функции в коде помечается гиперссылкой. При нажатии нее автоматом переход в  код этой функции.

А на странице будет отображаться только одна эта функция или все имеющиеся функции? Понятно, что речь идет о примочках IDE, там уже много чего есть, но есть и куда еще совершенствоваться.

> Но не сможете пользоваться таким. Неудобно будет. Например переименование функции как?

Рефакторинг отлично реализован в IntelliJ IDEA последних версий, пусть MS возьмет оттуда лучшее.
131 Zhuravlik
 
13.04.16
20:40
(124) +1
(0) Зачем внешние обработки? Для 77 есть замечательная ВК TurboMD. А все остальное - просто структурируйте код (по ссылке в (124) рассказано как). Пишите понятно, и никаких проблем.
132 Emery
 
13.04.16
21:12
(131) > Зачем внешние обработки? Для 77 есть замечательная ВК TurboMD.

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

> А все остальное - просто структурируйте код (по ссылке в (124) рассказано как).

К сожалению, там требуется регистрация, поэтому содержимое посмотреть не могу. Теоретически, наша фирма имеет право на подобный сервис, мы покупали годовую подписку ИТС, но из-за войны в ЛНР, поставщик из Луганска кинул нас и сам пропал. В итоге у нас не было ни дисков, ни прав на регистрацию в подобном сервисе.

> Пишите понятно, и никаких проблем.

Я уже писал, что главное это максимальная линеаризация кода, комментирование и логическая модульность. Другие возможности связаны с интерфейсом используемой IDE и внешними компонентами. Возможности гипертекстового кода оставим на будущее.
133 mingw
 
13.04.16
21:20
(132) >максимальная линеаризация кода, комментирование и логическая модульность

Какая еще линеаризация? Отвыкаем от квикбейсика. Переходите на прогрессивный визуал бейсик и турбо паскаль.
134 Злопчинский
 
13.04.16
21:25
(132) "...логическая модульность"
- я здесь понимаю это словосочетание как "смысловая модульноть". потому как по логике все может быть правильно но настолько "запутано" по смыслу шо каец...
- я прав?
135 orefkov
 
13.04.16
21:28
(121)
Вам бы вместо маниловщины и невнятных мечтаний матчасть как следует освоить. Поизучать состав меню Окна в конфигураторе. Он между прочим позволяет разделять/слеплять/дублировать окна в любых мыслимых и немыслимых сочетаниях, не говоря уж о пристыковывании их к любой стороне экрана. Чтобы писать код, надо просто писать код. Через неделю привыкаешь, и всякие невнятные хотелки отпадают, так как всё нормально получается и без них.
136 Emery
 
13.04.16
21:31
(133) > Какая еще линеаризация?

Имеется в виду последовательный вызов функций возвращающих успех выполнения либо неудачу. И так по рекурсии. Конечные функции могут содержать нелинейный код, но желательно максимально простой, который легко понять и сопровождать. Наверное, я когда-нибудь выложу подробную статью на эту тему в Интернете.
137 Emery
 
13.04.16
21:46
(135) Т.е., если я Вас правильно понял, Вы утверждаете, что программный код ЯВУ всегда был, есть и будет текстовым и никогда гипертекстовым? А в конфигураторе «восьмерки» есть все что нужно?

Я только что поэкспериментировал с окнами, о которых Вы пишите, в общем-то, неплохо, но не совсем то, о чем я говорю. Однако мы уже решили оставить проблему гипертекстового кода на будущее. Будем пользоваться тем, что есть.
138 Broadbread
 
13.04.16
21:48
(137) В нормальной IDE он и так гипертекстовый.
139 Злопчинский
 
13.04.16
21:52
(136) кстати, я так последнее время и стараюсь писать...
140 ildary
 
13.04.16
21:52
(137) за всех не скажу, скажу за себя - в 7.7 есть прекрасная вещь на основе OpenConf - называется SiColorer, и в ней сделана возможность гипертекстовости процедур и функций, то есть Ctrl + LMB делают переход на нее. Вот только этой фичей я не пользуюсь - потому что быстрее нажать Ctrl+Enter (точно такой же результат), чем снимать правую руку с клавы на мышь, кликать, а потом назад.
141 Злопчинский
 
13.04.16
21:52
(134)
- Доктор, почему меня все игнорируют?
- Следующий!
142 Emery
 
13.04.16
21:52
(138) > В нормальной IDE он и так гипертекстовый.

Можете привести образец такого гипертекстового кода, для конкретной IDE? Типа html-верстки.
143 mingw
 
13.04.16
21:53
(136) Нет смысла в линейном коде.
Для простоты чтения. Достаточно выносить в функции/процедуры. Весь код внутри циклов. По максимуму. И внутри прочих сложных конструкций тоже.
144 Broadbread
 
13.04.16
22:09
145 Emery
 
13.04.16
22:10
(134) > - я здесь понимаю это словосочетание как "смысловая модульноть". потому как по логике все может быть правильно но настолько "запутано" по смыслу шо каец...
- я прав?

Русский язык, от такой :) . В С++ под логическим модулем естественно понимать один класс и то в двух файлах *.h и *.cpp. В 1С это понятие более размыто. Я воспринимаю его как набор функций для решения определенной задачи, например для создания полууниверсальной обработки (в «семерке», в «восьмерке» целесообразней использовать другие возможности) для создания определенной группы отчетов и загрузок промежуточных данных для последующих специальных отчетов. Или это могут общие функции для первичных и вторичных журналов расчетов (реализованных на справочниках) и т.д. и т.п.

А так, Ваше замечание правильно. Но простое нередко является гениальным :) .
146 Emery
 
13.04.16
22:12
(139) кстати, я так последнее время и стараюсь писать...

Ну вот, уже появились единомышленники, что на форумах редко бывает :) .
147 Злопчинский
 
13.04.16
22:18
(146) а с +рекурсией это у меня получается при последовательном чтении иксемелек...
148 Emery
 
13.04.16
22:19
(140) > за всех не скажу, скажу за себя - в 7.7 есть прекрасная вещь на основе OpenConf

Согласен, недавно вот поставил себе, понравилось. Спасибо Александру Орефкову! Уже даже пришлось редактировать скрипты, которые вызвали ошибки в работе. Благо, это нетрудно сделать. Со временем, надеюсь освоить глубже.
149 Злопчинский
 
13.04.16
22:19
(145) " Но простое нередко является гениальным :) ." - прям как
Флажок = 1-Флажок;
150 mingw
 
13.04.16
22:22
(149)

Функция НЕ(ЧислоБулево01)
  Возврат 1-ЧислоБулево01;
КонецФункции

И тогда Флажок = НЕ(Флажок);
151 Emery
 
13.04.16
22:25
(143) > Для простоты чтения. Достаточно выносить в функции/процедуры

Добавлю еще, что эти функции вызываются последовательно и всегда возвращают только успех / неудачу, что должно проверяться. Я называю это рекурсивной линеаризацией (за исключением конечных функций, которые могут быть нелинейными, но не очень сложными). Вообще все проблемы идут от неопределенности в терминологии.
152 Broadbread
 
13.04.16
22:26
Всё придумано до нас.
153 mingw
 
13.04.16
22:29
(151) Функции вызываются не последовательно. А согласно структурам программы. Могут и не вызываться. Так как пропустили. Или вызываться много раз. Могут заново начать вызываться с начала (рекурсия основной программы на себя).
154 Злопчинский
 
13.04.16
22:33
(151) ".. и всегда возвращают только успех / неудачу,"
я обычно еще возвращаю некое "расширенное содержимое неудачи" дабы можно было куда-нить логгировать/выводить.. и вообще чтоб понятнее было что за неудача и для каждого расследования не лезть внутрь
155 Злопчинский
 
13.04.16
22:34
(153) "Могут и не вызываться.".. фигня.. это тот же самый выхов, но 0 раз... ;-)
156 Broadbread
 
13.04.16
22:35
А ещё, могут вызываться строго по порядку, а могут произвольно...
157 франц
 
13.04.16
22:41
"процедуры должны быть оформлены в виде функций" - по мне, всегда пытаюсь следовать данному принципу.
"логический успех или неуспех" - с передачей параметра самое лучшее.
"через общие переменные модуля" - ну, я бы за это как минимум четверовал бы через повешение с сиквестированием мозга и прочих ненужных такому программисту органов и возможностей..
158 orefkov
 
14.04.16
07:20
(137)
Упс. Только сейчас понял, что про семёрку речь идет. В ней да, чуть похуже. Но там надо ставить openconf+telepat+scicolorer - немного исправляет ситуацию.
159 Kyon8
 
14.04.16
09:01
(10) +1000
160 Emery
 
14.04.16
09:29
(158) > Да, исправляет, никто не спорит. Плюс использование внешних обработок (или внутренних, при желании) как общих модулей, без отображения их формы, для логически связанного кода, куда можно передавать контекст любой вызывающей формы и получать обратно любой контекст.
161 Zhuravlik
 
14.04.16
09:41
(132) Самый популярный отмаз для отказа чтения ИТС. Там тест-драйв есть :)
162 Emery
 
14.04.16
10:21
(161) > Там тест-драйв есть :)

На него я не обратил внимание. Получил временную регистрацию, посмотрел указанные примеры. В принципе, как я и предполагал там речь идет о правильном стиле программирования в 1С, как таковом. При этом ничего не говорится о выносе кода конфигурации во внешние модули (обработки). Почему стоит вопрос об этом? Просто текущие конфигурации вроде 1С:ЕРП УП слишком уж монстрообразные. Поэтому хотелось разделить их код на внешние модули, загружаемые по мере необходимости. Речь не идет конкретно о данной ЕРП, а вообще, хочется иметь дело не с монолитным блоком 1С, а с чем-то более структурированным. Это и отладку облегчает и исправление отдельных модулей, и понимание структуры и т.д.

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

Кстати, похожая проблема есть и опенсорсных С++ проектах. Так, я решил чуток переделать под себя код Audacity, использующий wxWidgets,. Все, в общем-то, прекрасно получается, однако процесс перекомпиляции проекта при изменениях занимает слишком большое время. Понятно, что без предварительной компиляции отдельных модулей никуда не деться. Как раз с этим сейчас и разбираюсь, в свободное время.
163 VladZ
 
14.04.16
10:31
(0)  Из всего текста важное: "При программировании код нужно структурировать".  Все остальное можно не читать.
164 Злопчинский
 
14.04.16
14:18
посмотри СКАТ-ПРОФЕССИОНАЛ.
они почти весь прикладной уровень решения вынесли за конфигуратор.
165 quest
 
14.04.16
18:06
(162) "рекурсивной линеаризации" - это что? На пальцах может рассказать?
166 Emery
 
14.04.16
20:16
(164) > посмотри СКАТ-ПРОФЕССИОНАЛ.
> они почти весь прикладной уровень решения вынесли за конфигуратор.

Посмотрел. И «семерку» и «восьмерку». Только не понял, что имеется в виду в последнем предложении? Как по мне, то все на месте. Часть кода защищена от просмотра и редактирования, только и всего. Все остальное как обычно. Хотя в «семерке» много всяких ВК используется, это можно поизучать.

А вот конфигурация "РБ-Софт:Рабочее место кассира" для «семерки» действительно почти не работает ни с собственной базой данных ни с собственными формами. Весьма экзотический вариант, хотя и глюковатый. Доступ к внешним dbf осуществляется через компоненту v7mysql.dll. А вместо формы списков используются обычные ТЗ. Кое-что здесь действительно интересно, но в целом выглядит странновато.
167 Злопчинский
 
14.04.16
20:45
(166)  8-ка у них весьма интересная
Я с их программером пообщался, он меня в экспресс-режиме протащил по решению, обновление у них делается просто - просто загрузкой нового дт, все остальное вынесено в метаконфигуратор, то есть можно под себя написать в прикладном режиме почти все и то большинство всякими собственными настройками, вплоть до произвольных правил видимости любых реквизитов на формах
Короче интересно
168 Emery
 
14.04.16
20:56
(165) "рекурсивной линеаризации" - это что? На пальцах может рассказать?

В теме приведен схематический пример кода для 1С77. В «главной» функции делаем «линейные» вызовы вида:

Функция ИницПарамВызывающФормы()
    Если ПроверкаИсходнДанных() = 0 Тогда
        Возврат 0;
    КонецЕсли;                          
    
    Если ПолучитьКонтВызывающФормы() = 0 Тогда
        Возврат 0;
    КонецЕсли;                          
    
    Если ОбработатьИсточнДанных() = 0 Тогда
        Возврат 0;
    КонецЕсли;                          
    
    // . . .

    Возврат 1;
КонецФункции // ИницПарамВызывающФормы ()

Каждая вызываемая функция имеет аналогичную «линейную» структуру, если она не последняя в «дереве» кода. Последняя функция может быть нелинейной, но желательно не слишком сложной, иначе логично разбить ее на последовательные субфункции. Это не жесткое правило, а просто общая тенденция. Например, первая используемая функция будет:

Функция ПроверкаИсходнДанных()
    Если ПроверкаЭлемСпрПараметры() = 0 Тогда
        Возврат 0;
    КонецЕсли;

    Если ПроверкаПриемнДанных() = 0 Тогда
        Возврат 0;
    КонецЕсли;
    
    Возврат 1;
КонецФункции  // ПроверкаИсходнДанных()

И так «рекурсивно» углубляемся до каждой «конечной» функции. «Последние» функции будут уже иметь более содержательный вид. Не исключен нелинейный код (переключатели, циклы, попытки – исключения, транзакции и т.п.) в «промежуточных» функциях. Но он должен быть максимально простой структуры, как правило, в виде вызовов функций следующего уровня. Где-то так.

Когда я сделаю рефакторинг своей конфигурации в этом стиле, я опубликую ее код для примера. Подобные идеи (с различными вариациями) можно применять в других ЯВУ. В том же С++ функции часто возвращают целочисленное значение, характеризующую меру своего успеха / неудачи выполнения (вроде типа HRESULT).
169 mingw
 
14.04.16
21:01
(167) А мануал по этому метаконфигуратору есть у них?
170 Emery
 
14.04.16
21:06
(167) > Короче интересно

А свои модули в «восьмерке» «УправлениеПроведением», «УправлениеРегистрацией» и «БюджетныйУчет» они защитили с помощью WiseAdvise?
171 Emery
 
14.04.16
21:27
(169) А мануал по этому метаконфигуратору есть у них?

У них на сайте есть файл scat_help8.zip (запакованный chm-файл в виде CKAT8.exe ). Там есть раздел Метаконфигуратор. Также этот раздел есть в кратком варианте документации СКАТ-Профессионал.pdf.
172 quest
 
14.04.16
22:27
(168) :pre и :post из кложуры - ты об этом хотел сказать?

Вообще, идея местами - то ли на контрактное программирование похожа, то ли на функциональное, то ли на автоматы писаные руками, то ли еще на какую эзотерику. Минусов реализации такого на 1С - чуть больше чем дофига.

Уже говорил, но повторюсь - нельзя писать код. Его надо генерить.

Но если генерить не получается - то простой DSL для твоего случая -

Функция ИницПарамВызывающФормы()
@Когда (ПроверкаИсходнДанных() = 1
            ПолучитьКонтВызывающФормы() = 1
            ОбработатьИсточнДанных() = 1 )
    
    // . . .

    Возврат 1;
КонецФункции // ИницПарамВызывающФормы ()
ну а @Когда раскрываешь уже сам в меру сил и потребностей отдельным компилятором, который берет все твои макросы и раскрывает их на 1С.
173 Emery
 
15.04.16
07:42
(172) Нам трудно понять друг друга по обрывкам информации. Любой используемый принцип не абсолют,  применяется постольку, поскольку в нем имеется смысл. Излагаемые здесь идеи подсмотрены  в открытом С++ коде. Но там легко применялись исключения из правил, когда это является целесообразным. Возможно в будущем, когда код будет представлен в двух видах (внутреннем, как html / xml и т.п. и внешнем как гипертекст) то средства структурирования программ станут на порядок лучше.
174 quest
 
15.04.16
09:03
(173) Все равно не понял. Зачем тебе гипертекст??? что он даст? Вот тебе функция -
Функция ф(х,у)
если х = 0 тогда
   вызватьисключение "Делимое 0 - так нельзя";
конецесли
если у = 0 тогда
   вызватьисключение "Делитель 0 - так нельзя";
конецесли
если у = 1 тогда
   вызватьисключение "Делитель 1 - так  тоже нельзя";
конецесли

если у = 2 тогда
   вызватьисключение "Делитель 2 - и так  тоже нельзя";
конецесли
возврат х / у;
конецфункции

Перепиши в своей нотации с гипертекстом. Как это будет выглядеть?
175 Emery
 
15.04.16
10:48
(174) > Все равно не понял. Зачем тебе гипертекст??? что он даст?

Для удобства навигации по коду (как, скажем, в справочной системе Qt). При этом желательно, чтобы на одной странице отображалась только одна функция (или несколько, по выбору, т.е., чтобы «лишний» код не загромождал обзор), причем во внутреннем представлении это должен быть один модуль (в соответствии с нашим проектом). Также должно быть доступно редактирование гипертекста в своем внешнем представлении (а не только через html-коды, их, вообще, должна делать система автоматически). Теоретически из такого кода можно будет сделать целый сайт со всякими прибамбасами, но внутренняя его структура должна определяться выбранной структурой проекта. Возможно, это покажется чересчур избыточным, но, почему-то уверен, что так будет. M$ уже не знает, что придумать в программировании, поэтому ему можно продать эту идею :) .

> Вот тебе функция

Переходы можно делать по именам (переменных, констант, структур, классов, функций и т.п.), примерно то, что сейчас достигается в Visual Studio C++ через клавиши (Ctrl+F12; Shift+F12; Alt+F12; Ctrl+KT и т.п. Только там нет отображения одного объекта на одну страницу / вкладку / закладку / экран / окно и т.д.). В твоей функции представлены только параметры, ключевые слова и текст. Есть смысл, здесь демонстрировать только каким либо образом (на уровне системы), что x и y являются параметрами данной функции.
176 quest
 
15.04.16
10:53
может на doxygen посмотришь? я так понимаю это то что тебе надо, только без редактирования текста.
177 Emery
 
15.04.16
10:56
(176) > это то что тебе надо, только без редактирования текста

Вот! В принципе, близко. Только обязательно должно быть редактирование и просмотр выбранного объекта в отдельном окне, без нарушения структуры проекта.
178 Карупян
 
15.04.16
10:58
(177) пиши на яве. Там каждый объект в отдельном окне (файле)
179 Emery
 
15.04.16
11:06
(178) Под объектом я понимаю не только класс, но и любую структурную единицу, например, функцию, обычную структуру, перечисление и т.п.

А Ява предлагает только размешать один класс в одном файле, да еще и структуру каталогов поддерживать самому. Лучше уж писать на С++ с фрейморками в Visual Studio или в Qt Creator. Это, на мой взгляд, более удобные системы программирования.
180 quest
 
15.04.16
11:17
(177) Ну напиши. Ничего сложного нет - парсинг текста + анализ + хранение информации + отображение.
181 Emery
 
15.04.16
11:31
(180) > Ну напиши. Ничего сложного нет - парсинг текста + анализ + хранение информации + отображение.

Смеешься? Хотя, если оформить как плагин для Qt Creator, то можно подумать.
182 Mikeware
 
15.04.16
11:34
"НУЖНО ПРОГРАММИРОВАТЬ КОД КАК ГИПЕРТЕКСТ"
чот напомнило: "современные ракетные двигатели - они скорее как цилиндр"©
183 quest
 
15.04.16
11:35
(181) да не привязывайся ты к инструменту. Делай методологию. Тогда и инструмент станет  понятен
184 Emery
 
15.04.16
11:50
(183) Согласен, что теория нужна, но примеры реализации не повредят. Будем стремиться.
185 Тролль главный
 
15.04.16
14:52
Программист всегда исправляет последнюю ошибку.