И так, раз пошла такая пьянка сразу введем некоторые правила и ограничения. Данная тема посвящена им. Просьба не засирать ее не относящимся к делу. Один вопрос — одно подсообщение.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>И так, раз пошла такая пьянка сразу введем некоторые правила и ограничения. Данная тема посвящена им. Просьба не засирать ее не относящимся к делу. Один вопрос — одно подсообщение.
Работа с VCS. Предлагаю сделать так:
Любая фича делается в клоне или в локальном репо и пушится в центральный только на стадии какой-то готовности. Если разработчик не уверен в готовности фичи, он пушит ее в клон и задает вопрос на форуме. После одобрения пушит в центральный. Та же начальная структура папок вполне могла бы быть уже в клоне.
Совет начинающим по использованию tortoisehg — лучше сразу заменить в настройках его стандартный diff/merge tool на tortoisesvn.
Boot — это каталог содержащий набор файлов необходимый для начальной сборки проекта.
Когда компилятор сможет скомпилировать сам себя, в Boot будет хранится бинарники компилятора которыми можно собрать текущие исходники.
Так как какое-то (и довольно долгое) время компилятор не сможет собирать себя (да и вообще что-то) проект будет собираться наиболее свежей, доступной на сайте в виде инсталлятора версией Nemerle 1.0. Посему каталог Boot должен содержать файл Readme.txt в котором должен быть указан путь к инсталлятору и краткая инструкция по сборке проекта (если надо).
По поводу Boot-2.0, Boot-4.0 и т.п. Новый компилятор будет способен собирать сборки для любой версии дотнета (что будет определяться опциями компиляции). Посему нам не нужны Boot-ы подо всем поддерживаемые платформы.
Платформой на которой будет работать компилятор будет являться Microsoft Framework 4.0 и последняя версия Momo. При появлении более свежих рантаймов будем думать о миграции под них.
Пока что, в следствии того, что Nemerle 1.0 порождает сборки для Microsoft Framework 2+ платформой будет Microsoft Framework 3.5.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Ziaw, Вы писали:
Z>Любая фича делается в клоне или в локальном репо и пушится в центральный только на стадии какой-то готовности. Если разработчик не уверен в готовности фичи, он пушит ее в клон и задает вопрос на форуме. После одобрения пушит в центральный. Та же начальная структура папок вполне могла бы быть уже в клоне.
Лично я никогда не работал с подобными системами, так если можно опиши процесс по подробнее.
Z>Совет начинающим по использованию tortoisehg — лучше сразу заменить в настройках его стандартный diff/merge tool на tortoisesvn.
Опять же по шагам, что как и зачем делать?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, Ziaw, Вы писали:
Z>>Любая фича делается в клоне или в локальном репо и пушится в центральный только на стадии какой-то готовности. Если разработчик не уверен в готовности фичи, он пушит ее в клон и задает вопрос на форуме. После одобрения пушит в центральный. Та же начальная структура папок вполне могла бы быть уже в клоне.
VD>Лично я никогда не работал с подобными системами, так если можно опиши процесс по подробнее.
Попробую.
У нас есть центральный репозитарий, назовем его M.
Для разработки необходимо сделать его локальный клон — L. В этом клоне мы можем делать сколько угодно комитов не трогая M. В это время кто-то делает изменения в M. По достижении готовности фичи, мы вытягиваем (pull) все изменения из M к себе и склеиваем две ветки разработки, свою и чужую локально (merge). После этого мы можем отправить все изменения (push) в M. Теперь M и L снова идентичны.
Еще есть возможность создать удаленный клон репозитария прямо на гуглкоде, назовем его C. Все то же самое, только его никто не трогает и мы можем пушить туда свои изменения хоть после каждого комита. По завершении фичи делаются все те же действия, только пуш делатся как в C так и в M. После такого пуша L, C, M — снова идентичны.
Вместо merge можно делать rebase, т.е. встроить свои изменения так, как будто все делалось в одной ветке, тогда не будет лишнего комита и граф ревизий будет выглядеть прямо. Но это опционально.
Z>>Совет начинающим по использованию tortoisehg — лучше сразу заменить в настройках его стандартный diff/merge tool на tortoisesvn.
VD>Опять же по шагам, что как и зачем делать?
Это просто задается в настройках tortoisehg, там комбобокс даст выбрать tortoisemerge если она установлена.
Самый удобный способ работы с tortoisehg — запустить hgtk log внутри репозитария. Оттуда можно сделать посмотреть историю, сделать комит, пуш, пул, мердж. Я просто в студии вывел на тулбар запуск hgtk log и hgtk commit в папке солюшена как внешние инструменты (external tools). Если интересно — опишу подробнее, когда буду под виндой. Теперь комичусь перед каждым рефакторингом в 5 сек, потом удобно посмотреть все что он затронул.
Еще одна типичная ошибка переходящих из свн. Не делайте hg pull (svn up) не закомитив локально свои правки. В принципе они смерджатся, но при кривом мердже вы можете что-то потерять. Смерджить эти изменения лучше имея две закомиченые ветки.
Здравствуйте, Ziaw, Вы писали:
Z>У нас есть центральный репозитарий, назовем его M. Z>Для разработки необходимо сделать его локальный клон — L. В этом клоне мы можем делать сколько угодно комитов не трогая M. В это время кто-то делает изменения в M. По достижении готовности фичи, мы вытягиваем (pull) все изменения из M к себе и склеиваем две ветки разработки, свою и чужую локально (merge). После этого мы можем отправить все изменения (push) в M. Теперь M и L снова идентичны.
Возможно все станет более понятно глядя на репо nrails
Я и Валера начали добавлять фичи основываясь на ревизии da7. Поскольку мои изменения были сделаны раньше и не перескались с чужими в M — я просто выложил их в M, hg push (svn commit). Валера уже не смог бы сделать push, т.к. в репозитарии появились бы две ветки растущие из da7 (это тоже реализуемо, но сейчас не об этом). Поэтому он сделал pull моей ветки и свел их, получив ревизию 2bb. Теперь у него в репозитарии осталась одна ветка и он смог сделать push всех своих изменений в M.
Предисловие. Стиль кодирования является весьма флэймовой темой. Прошу всех кто не согласен с изложенным ниже стилем быть конструктивными и понимать, что в этом вопросе не возможно достичь полного согласия и каждый должен пожертвовать своими привычками. Мы конечно будем рассматривать вопросы изменения стиля кодирования, если на то будут ощутимые (большинством) причины. Но до принятия общего решения по изменению стиля нужно строго придерживаться описанного ниже стиля.
Так же заранее прошу прощения за узурпацию права по выработке стиля.
2. Правила описанные ниже переопределяют правила описанные в приведенном в пункте 1.
3. Длинна строк должна быть <= (меньшей или равной) 120 символам. Допускаются строки длинyее 120 символов если они не несут смысловой нагрузки. Например, если имеется длинная строк с текстовым сообщением, то ее нет смысла переносить на новую строку, так как для понимания кода она не особо нужна, а увеличение количества строк ухудшает понимание остального кода. Если выражение получается слишком длинным и требует переноса, то стоит подумать над тем, чтобы разбить его на ряд промежуточных выражений путем введения дополнительных локальных переменных или локальных функций. Имена локальных переменных и локальных функций являются дополнительной документацией к коду, так что не пренебрегайте ими на том основании, что можно обойтись без них или что код станет чуточку длиннее. Помните, что важна не длинна кода, а его понятность окружающим.
4. Старайтесь оставлять строковые литералы целыми. Разбивайте их только если они превышают в длинну более 150 символов.
5. Если литералы содержат несколько строк, предпочитайте DSL-строки (<#...#>) или манки-строки (@"..."). Тоже самое касается строк содержащих символы '\\' и '"'. Старайтесь по возможности избегать эскеп-последовательностей. Например, для путей к файлам лучше использовать манки-строки, а для текста содержащего кавычки и концы строк — DSL-строки.
6. Оформление локальных переменных.
6.1. Если локальная переменная может быть не изменяемой, то ее нужно стараться сделать таковой (т.е. определять с помощью ключевого слова def, а не mutable).
6.2. Если вы инициализируете mutable начальное значение которой совпадает со значением для ее типа принятым по умолчанию, не указывайте начальное значение.
6.3. Инициализацию переменной размещайте или на той же строке что ее объявление
def obj = if (meth.IsAbstract) <[ null : this ]> else <[ base ]>;
или оформляйте ее следующим образом:
Обратите внимание на то, что инициализирующее выражение ОТБИТО на один отступ внутрь, и на то, что оно ОБЯЗАТЕЛЬНО заканчивается точкой а запятой (хотя Nemerle позволяет этого не делать).
6.4. По возможности используйте табличное форматирование при объявлении группы переменных (как локальных, так и полей). Например:
7. Формление оператора match.
7.1. Скобки тела оператора match всегда ставятся с новой строки.
7.2. Содержимое тела оператора match отбивается на один отступ внутрь.
7.3. Если содержимое обработчика "=> ..." умещается на одной строке, то оно должно находиться на той же стоке где и оператор "=>", а содержимым не должно идти пустых строк.
7.4. Если содержимое обработчика не вмещается в одну строку, оно сносится со строки обработчика и оформляется в несколько строк отбитых на один отступ относительно отступа образца. В конце такого обработчика обязательно должна идти пустая строк (чтобы визуально отделить такой обработчик от следующего. Исключением является тело последнего обработчика. В этом случае пустая строка не ставится.
// Правильно:match (_ast)
{
| PT.TopDeclaration.VariantOption(members) =>
unless (Util.is_capitalized(name))
Message.Error(NameLocation, "variant options' names must start with capital letter");
foreach (mem in members)
unless (mem.Attributes %&& NemerleAttributes.AccessModifiers)
mem.Attributes |= NemerleAttributes.Public; // пустая строка нужна!
| PT.TopDeclaration.Variant => attributes |= NemerleAttributes.Abstract // пустая строка не нужна
| PT.TopDeclaration.Enum when !this.typarms.IsEmpty =>
Message.Error("enums cannot have generic type parameters"); // пустая строка не нужна!
}
// Не правильно!match (_ast)
{
| PT.TopDeclaration.VariantOption (members) =>
unless (Util.is_capitalized (name))
Message.Error(NameLocation, "variant options' names must start with capital letter");
foreach (mem in members)
unless (mem.Attributes %&& NemerleAttributes.AccessModifiers)
mem.Attributes |= NemerleAttributes.Public; // нет пустой строки!
| PT.TopDeclaration.Variant => attributes |= NemerleAttributes.Abstract // лишняя пустая строка!
| PT.TopDeclaration.Enum when !this.typarms.IsEmpty =>
Message.Error ("enums cannot have generic type parameters"); // нет пустой строки!
| _ => () // лишняя пустая строка!
}
7.5. В случае если это возможно применяйте табличное форматирование в операторе match:
match (part)
{
| PT.TopDeclaration.Class (typarms = t) => t
| PT.TopDeclaration.Variant (typarms = t) => t
| PT.TopDeclaration.Interface(typarms = t) => t
| _ => Util.ice("non class / variant")
}
...
match (topDecl)
{
| PT.TopDeclaration.Class => TypeDeclaration.Class()
| PT.TopDeclaration.Alias(t) =>
match (this.tydecl)
{
| TypeDeclaration.Alias(null) =>
def ttype = this.tenv.BindFixedType(this.GlobalEnv, this, t, check_parms = false);
TypeDeclaration.Alias(ttype)
| _ => Util.ice("The 'tydecl' field of alias must have TypeDeclaration.Alias(null) type.")
}
| PT.TopDeclaration.Interface => TypeDeclaration.Interface()
| PT.TopDeclaration.Enum => TypeDeclaration.Enum()
| PT.TopDeclaration.Variant =>
TypeDeclaration.Variant(variant_options.Map(fun (x : TypeBuilder) : TypeInfo { x }))
| PT.TopDeclaration.VariantOption => TypeDeclaration.VariantOption()
| PT.TopDeclaration.Delegate
| PT.TopDeclaration.Macro => Util.ice("this top declaration shouldn't survive to typing")
}
7.6. Если match применяется к значению вариантного типа или к перечислению, старайтесь не использовать символ заместитель "_" для обработки неиспользуемых значений. Лучше перечислить эти значения явно. Это заставит компилятор отслеживать недостающие значения и сообщать вам об этом.
7.7. Если оператор match имеет большие размеры в следствии того, что большие размеры у некоторых обработчиков, следует вынести обработчики в локальные функции или методы. Помните, что работать с большими операторами match крайне неудобно!
8. Локальные функции.
8.1. Старайтесь указывать типы параметров и возвращаемых значений у локальных функций. Это полезно сразу по двум причинам. Во-первых, тем самым вы упрощаете чтение кода (код не всегда читается в IDE), так как типы — это дополнительная документация. Во-вторых, тем самым вы облегчаете жизнь IDE и компилятору. При этом они будут работать быстрее и выдавать более точные сообщения об ошибках.
Не следует доводить выполнение этого пункта до маразма. Так что в каждом случае стоит подумать нужно ли указывать типы параметров и возвращаемого значения. Бывают простые случаи когда в этом нет смысла. Так же бывают случае кода информация о типах ухудшает читаемость кода, например, когда размеры типов очень большие. В таком случае возможно не задавать типы, задавать их частично, или объявить псевдонимы (алиасы) типов с помощью конструкции type или usung.
Так же можно задавать только часть структуры типов указывая вместо некоторых параметров типов постановочный символ "_". Например, вместо Hastable(SomeLongTypeName[OtherLongTypeName], string) указать Hastable(_, string). Помните, что даже частично заданные типы могут сделать код понятнее.
В общем, если вы видите, что тип может улучшить понятность кода, то не поленитесь и добавьте аннотацию типов.
Помните так же, что аннотации типов можно задавать и вне параметров (прямо в выражениях).
9. Точка с запятой.
Точку с запятой следует ставить там где требует компилятор, в конце инициализации переменных или за выражениями тип которых void.
Причем при инициализации переменных точка с запятой должна ставиться даже если компилятор этого не требует (когда выражение кончается на фигурную скобку), а в остальных случаях только если выражения не оканчиваются на закрывающую фигурную скобку.
Не ставьте точку с запятой в конце выражений которые являются листовыми (содержат возвращаемые из функции значения), если его тип не void.
Обратите внимание на то, что объявление локальных функций так же имеет тип мoid, так что не ставьте точку с запятой за ними.
10. Пробелы. Для отбивки кода используется 2 пробела. Табуляции или отличное от двух пробелов недопустимо.
11. Указание типов. Ставьте по одному пробелу до и после двоеточия (если не применяется табличное форматирование). Если это возможно применяйте табличное форматирование.
// Неправильно:def loop(i:int, k: int, z :string)
{
def a:int=i;
def bbbb:int = i;
...
}
// Правильно:def loop(i : int, k : int, z : string)
{
def a : int = i;
def bbbb : int = i;
...
}
12. Оформление функций и свойств в одну строку.
Если тело функции или свойства (или его эксосора) настолько маленькое, что легко влезает в одну строку, то можно оставить выражение и все фигурные скобки на одной строке с определением функции/свойства/событий.
При этом обязательно от отбивайте тело функции/свойства/событий одним пробелом от фигурных скобок. Так же по одному проблему должно быть перед и после ключевых слов get/set/add/remove.
// Неправильно:public SomeProperty : int { get{_someField+1}}
public SomeProperty : int { get{ _someField + 1 } }
public SomeProperty : int { get { _someField + 1 }}
public SomeProperty : int {get{ _someField + 1 } }
public SomeProperty : int {get{_someField + 1}}
// Правильно:public SomeProperty : int { get { _someField + 1 } }
PS
Если в этом списке и в Соглашениях по оформлению кода команды RSDN отсутствуют правила для того или иного фрагмента кода, спрашивайте о том как его форматировать здесь (в ответ на это сообщение).
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Сделал клон в котором закомитил свой обычный .hgignore (исключает из комита ненужные в репозитарии файлы) и файл со структурой каталогов.
Посмотри, если все нормально — залью в центральный.
Здравствуйте, Ziaw, Вы писали:
Z>Сделал клон в котором закомитил свой обычный .hgignore (исключает из комита ненужные в репозитарии файлы) и файл со структурой каталогов. Z>Посмотри, если все нормально — залью в центральный.
Вроде все ОК. А что нужно сделать мне, чтобы слить эту версию с основной?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, WolfHound, Вы писали:
WH>Отступы чем отбиваем? Таб или 2 пробела?
Вот хрен его знает. Раньше я бы категорически за табы, но как-то привык к двум проблемам. Так что теперь мне в общем-то все равно. Даже проблемы удобнее, так как таб можно использовать для отбивки в стиле табличного форматирования.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, WolfHound, Вы писали:
WH>>Отступы чем отбиваем? Таб или 2 пробела?
VD>Вот хрен его знает. Раньше я бы категорически за табы, но как-то привык к двум проблемам. Так что теперь мне в общем-то все равно. Даже проблемы удобнее, так как таб можно использовать для отбивки в стиле табличного форматирования.
А как же Золотая Середина Синклера, что табы набиваем в соответствии с логическими отступами, а пробелы — чтобы красиво было?
Здравствуйте, VladD2, Вы писали:
Z>>Сделал клон в котором закомитил свой обычный .hgignore (исключает из комита ненужные в репозитарии файлы) и файл со структурой каталогов. Z>>Посмотри, если все нормально — залью в центральный.
VD>Вроде все ОК. А что нужно сделать мне, чтобы слить эту версию с основной?
Да ничего, я сам залью. Но в принципе можешь и ты, требуются примерно такие действия:
ziaw@ziaw-desktop:~/dev$ hg clone https://ziminav-main.googlecode.com/hg/ ziminav // берешь себе мой клон
requesting all changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 2 changes to 2 files
updating to branch default
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
ziaw@ziaw-desktop:~/dev$ cd ziminav // заходишь в папку
ziaw@ziaw-desktop:~/dev/ziminav$ hg push https://nemerle-2.googlecode.com/hg/ // делаешь пуш в центральный
pushing to https://nemerle-2.googlecode.com/hg/
searching for changes
http authorization required
realm: Google Code Mercurial Repository
user: ziminav@gmail.com // тут нужен пользователь с правом комита в nemerle-2
password:
remote: Success.
Второй вариант, у тебя есть локальный репозитарий nemerle-2, в нем делаешь:
Тут предполагается, что в моем клоне уже все сведено к последней версии в репозитарии, иначе надо перед пушем сделать merge (hgtk log, выделить топ одной ветки потом в контекстном меню топа другой нажать merge).
Здравствуйте, VladD2, Вы писали:
VD>Вот хрен его знает. Раньше я бы категорически за табы, но как-то привык к двум проблемам. Так что теперь мне в общем-то все равно. Даже проблемы удобнее, так как таб можно использовать для отбивки в стиле табличного форматирования.
+1
Но нужно сделать выбор.
Предлагаю два пробела.
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, VladD2, Вы писали:
VD>Предисловие. Стиль кодирования является весьма флэймовой темой. Прошу всех кто не согласен с изложенным ниже стилем быть конструктивными и понимать, что в этом вопросе не возможно достичь полного согласия и каждый должен пожертвовать своими привычками. Мы конечно будем рассматривать вопросы изменения стиля кодирования, если на то будут ощутимые (большинством) причины. Но до принятия общего решения по изменению стиля нужно строго придерживаться описанного ниже стиля.
VD>Так же заранее прошу прощения за узурпацию права по выработке стиля.
VD>Стиль кодирования проекта Nemerle 2
Вообще в опенсорс проектах обычно выделяются несколько самых простых правил для стиля и описываются в небольшом документе для всех (это выравнивание, именование, основные правила обрамляющих {}), это можно положить в Docs. Этого обычно достаточно, чтобы пофиксить баг и не превратить код в кашу.
Все остальное для внутреннего пользования командой разработки и достаточно ветки на этом форуме.