All streams
Search
Write a publication
Pull to refresh
93
0
Юрий @m36

User

Send message
А вы не путаете код и тесты? Да, если будут умельцы русифицировать, то или должны войти в группу разработчиков и поправить тесты, либо это пираты, которые на свой риск меняют код, а тесты не прогоняют.

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

И на все контролы, где нужны названия, у вас будет что-то вроде Dictionary. Заполняется или со сборок, как обычно, или с БД, где есть таблица, описывающая наши докстатусы.

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

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

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

Почему не обязательно делать стопроцентное покрытие. Юнит-тесты прибавляют жесткости, они что-то закрепляют. Важно, чтобы они закрепляли что-то осмысленное, чтобы оставалась гибкость для рефакторинга. Где эта грань проходит — вопрос спорный и каждый чувствует сам. Может на счет покрытия тестов я ошибаюсь. Это мое интуитивное представление, выработанное на практике.
Тут с другого конца аналогия нарушена. Язык математики — это язык выражения мыслей ))))
У языков математики и естественных языков нет качественных различий. И настоящие математики это знают. А система образования этому не учит, она учит представлению, что языки математики — это аппарат вывода, который надо применять в определенной последовательности, чтобы что-то доказывать. И это да, но главное предназначение — это выражение мыслей. Более точных мыслей, которые естественным языком не выражаются.
Даже очень неглупые люди, изучавшие математику, но не понявшие эту мысль, математиками не становятся. Это не их язык. Они могут применять только время от времени ее. Но не мыслить ею.

Языки программирования более «гуманитарные». Тут мы придумываем много имен — классы, методы и т.д. Можем строить выражения на этих языках. Которые будут почти декларативно состоять из имен и порядка вызова. Что делает код читаемым почти также как и комментарии. Конечно, можно и сложно написать — но об этом и речь, что так не хорошо — мы ж не обфускаторы.

Ну и напомню про функциональные языки. Разные языки имеют разную возможность для выразительности. функциональные чаще имеют бОльшую выразительно. Что еще меньше позволяет думать о комментариях.

А про «дурной стиль»… Я бы дурным стилем комментарии назвал. Вы, вроде, на шарпе пишете? Довольно выразительный язык.
Да, у меня даже есть старая «олдскульная» привычка: когда есть костыль, я пишу такой комментарий:

// Fix Me!!!

Хотя студия позволяет более современными способами делать закладки. Но меня этот устраивает. Я легко потом текстовым поиском по всем файлам нахожу эти костыли.
Да, и комментарии — совсем не круто. Комментарии — признак говнокода.

Лучший способ писания программ — выражение мыслей на языке программирования. И если рука тянется написать комментарий — значит самим кодом объяснить его работу не получается.

Комментарии не компилируются их тяжело поддерживать. Комментарии — это другой язык, когда есть язык программирования. Если человек пишет комментарии, то это буквально говорит, что человек не профессионал в своей области. Все равно, что плотник имел бы записную книжку, а в ней писал: «Молоток, это такая штука с ручкой и железячкой, нужна для забивания гвоздей». Если у плотника такая записная книжка — знайте, это не плотник.

К сожалению, в программировании большинство людей бездарности и непрофессионалы. И даже методики придумывают для таких как они. Например, не пользоваться языком программирования, а рисовать диаграммы (аналогия с плотником). Зачем? Потому что в руководство лезут сантехники и они хотят видеть на понятном для них языке устройство программы — в виде труб. Код они читать не могут. И не хотят.

другие рекомендуют писать комментарии. К говнокоду главное, при этом, никаких вопросов у них нет. Им нужны комментарии, потому что читать код не умеют.

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

Комментарии можно делать, конечно. Бывают случаи, когда используются нетривиальные алгоритмы. И код действительно тяжело читать и это обоснованно. Или когда провели оптимизацию. Но писать их надо по остаточному принципу, когда другие средства не помогли.
ru.wikipedia.org/wiki/%D0%93%D1%80%D0%B0%D0%BC%D0%BE%D1%82%D0%BD%D0%BE%D0%B5_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5

в частности оттуда фраза Кнута:
«Давайте изменим традиционные приоритеты в создании программ: вместо представления о нашей задаче как о создании инструкций «Что делать?» для компьютера сконцентрируемся на объяснении другим людям описаний нашего видения того, что под управлением программы должен делать компьютер.»
Это не хардкод. Это процедура которая выполняет свое предназначение — называется «сформировать пакеты платежей», а DocState = '2' зафиксировать отказ тем платежам, у которых истек срок оплаты.


Вот! Вы уже говорите более человеческим языком. Не совсем понятно задание, но уже теплее.

Переводим на наши языки программирования:
Процедура называется:
FormPaymentPackages
Ну, тело мы видели. А тест, вполне без комплексов и стеснений так и написан:

declare @DocStateId char
select @DocStateId = Id from DocStates
where Description like N'зафиксировать отказ тем платежам, у которых истек срок оплаты'


Счастье есть. Тут ровно перевод того, что вы сказали, без никаких художественных отклонений. Кроме разве что: нужно обращать внимание на то, что видит пользователь. Поэтому там может быть не длинный дескрипшин, а короткий кепшин, который отображается в гуи. И всё отлично, код связан. Кепшин связан насквозь через всё приложение. Тесты тестят его, а не какие-то числа. Профит: можно как-то гарантировать, что приложение делает то, что хотелось заказчику.

Не ужели Вы реально полагаете, что я буду писать болгарским или арабской вязью, чтобы связать GUI с однозначным значением '2'? И по вашему в этом заключается предметная область?


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

вот и весь сыр-бор. Нужна другая таблица, которая расшифровывает числа. Нужны тесты, которые «свяжут» требования и шифрования прямо по с текстом требований. Иначе число так и останется числом. И непонятно, программа для юристов создана или считает частицы андронного колайдера. Причем для обоих случаев не подходит…
точно! :) Go — это не стоять. Я всё пытаюсь донести, что программирование делается не ради программирования. Также как искусство ради искусства — это полный отстой.

И самая дурная и полная чепуха, это когда пользователь ожидает одно (поехали), а программа делает другое (стоп). Вы за кого, за брата или за медведя? Что для вас критерий правильности работы программы? Неужели внутренние инты или энамы…
Нет, ну об этом мы не спорим ))
Конечно, если работодателя устраивает и вы делаете свою работу, то профит. В конечном счете работает экономика, а работодателя не интересует идеализм и красота.

Так что если получается и получается без «много багов», то все мы красавчики ))
никто не спорит. Особенно играет роль время. Может кто-то будет идеальную систему год разрабатывать, а второй напишет кривую внутри, но работающую и за два месяца. Точно — второй сделал лучше. Тут вообще без вопросов.

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

Я тоже сторонник не архитектуры, а разработки. Просто не согласен на счет ненужности юнит-тестов. И тут во всех каментах спор о том, писать так — костыли, а не так (продумывать архитектуру) классно. Или наоборот.

У меня есть свой взгляд. Что так и надо наобум писать и упрощать всё что можно. Но только — тесты не лишние. Ну и это не только мое мнение. Но например и VolCh. Только разошлись в мнениях — как именно писать. А это более тонкая черта.

Как бы то ни было, наобум писать код и не испоганить его — нужен хороший опыт. И у того человека, который описан в статье, видимо он есть.

У меня свой опыт. Я тоже его слегка изложил. Много тонкостей в оценке кода. Начиная от требований. И мой метод тоже прекрасно работает. Хотя он и не мой, не я его придумал. Но не могу сказать, что я его изучал специально.

Где-то так. Главный критерий — пишете код, получаете удовлетворение, получает удовлетворение заказчик — это пять.
Ну так всё верно: предусловие, запуск, постусловие.

Только предусловие и постусловие — ни в коем случае не снепшот. Оно должны писаться осознанно, отражая какое-то требование. Пусть даже маленькое требование программиста, пишущего код и делающего утверждение.

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

Один раз я занимался такими снепшотами всего приложения и базы. Но там был особый случай. В наследство остался код, очень нереально плохой. При этом никто не знал бизнес-требований. Но его работа по смыслу удовлетворяло. Только было много глюков и тормозов. (Там был пожественный класс, который всё делал статическими методами без эксепшинов. Свернутые только сигнатуры занимали десять страниц).
Вот тогда я сделал мок-объекты при доступе к базе, а также анализатор ввода в гуи, и эта штука собирала в XML тест-кейсы. Нужно было только правильно нажимать разные штуки и оно фиксировало, какой запрос пошел в базу.
И цель рефакторинга была в том, чтобы потом эти же тест-кейсы проходили.

Т.е. это был единственный случай, когда по умолчанию считалось, что код делает приблизительно то, что надо, но что надо, никто не знал.

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

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

Можете из апликейшина кидать запросы и там же тестировать. не имеет значения. Но просто идти до конца надо в любом начинании. Если уже связи там, то там все нужные связи. Иначе это криво, не поддается тестированию и т.д.
Учу. Полей вида DocStates на самом деле есть три вида: системные состояния, которые вообще не видны пользователю, состояния, наименования которых он задает сам (как правило админ этим занимается), состояния, наименование которых жестко задает разработчик.

И не с одним из этих видов НЕЛЬЗЯ поступать так как вы предлагаете.


Жесть. А то реальный код был, который выслан? Бьюсь головой об стол ))

Вы там прописали номера (т.е. по моему разумению айдишки, пусть без таблицы). И с чего вдруг:

SET DocState = '2' 


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

Если же код зависит от чего-то другого, а не от названия, данного админом, а например, от типа статуса «системные», «пользовательские», «разработчика» — то вот и наш классификатор, который тоже ДОЛЖЕН отразиться в таблицах.

Сами ничего не ощущаете, что что-то не то в вашем описании? Интересно, как вы себе задачу представляете.
Две крайности — всё в базе и в тестах номера :) Связь ид-название/описание можно захардкодить в коде, чтобы можно было удобно и осмысленно писать тесты и сам код, и в то же время не допустить даже преднамеренной порчи связи администратором системы (не в смысле пользователем ОС с рутовскими правами, способного изменять бинарники, а в смысле роли в системе)


Нет никаких противоречий, даже если будут в тестах и в базе номера.

Почувствуйте разницу. Есть требование (а может нет, сами ставите, как для юнит-теста):
«У нас есть статус документа „отложен“ и если пришло событие (что там еще придумать… ) „сервер готов к обработке“, то документ переходит в статус „ожидает обработки“ ».

Пишем тест. Предусловие, запуск, постусловие.
Создаем документ со статусом «отложен». (Не со статусом 2!!!, даже если он в базе это значение имеет, а находим по названию).
Запускаем хранимку, даем статус сервера (находим по названию, это наш тип, наш артефакт)
Проверяем постусловие. Ищем статус по названию «ожидает обработки». Сравниваем. Нет — тест не прошел.

Второй случай:
Есть требование — документ в статусе «отложен». Приходит HTTP статус «использовать прокси» (совершенно надуманный пример, я не веб-программист), переходим в статус «ожидает обработки».

Статус документа до сих пор наш артефакт. Айдишки — только созданы только в нашей системе и могут быть любыми. По ним логика точно такая же. Но с HTTP-статусом история другая. Он не наш. Его номера — стандарт. Их не надо прописывать в базе. И мы в тесте без зазрений совести используем цифры. Возможно с комментариями со ссылками на стандарт. Всё.
Так тоже можно развязаться от логики теста. не писать селект по множеству, а выбрать точечные переходы.

Ни разу не слышал, что это обязательно.

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

Он не ошибается. Джойны делает как надо. Толку от тестирования такого. Разве что жизнь себе усложнить. В том плане, когда логика поменяется, джойн другой напишут, тест упадет. И тест еще придется менять. Это хорошо было бы в случае если тест логику бы тестировал. Т.е. в тесте закрепили логику работы чего-то. Но логики без смысла не бывает. Фиксировать поведение без цели — это не юнит-тест. Юнит тест — это утверждение.
Так должен быть смысл у дескрипшина.

ну ладно. Я тут возможно не очень удачное название для колонки выбрал. Эта колонка должна нести смысл для пользователя. Может не дескрипшин, а Caption. Name резервируем для имени перечисления в коде апп.

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

Есть даже методики и языки (правда не работал так), где бизнес-требования механически переводятся в теоремы и программа строится на их доказательстве.

Вот здесь приблизительно то же самое. Если вы не связали эти названия не с ГУИ, ни с документацией, а держите связь в уме, то вы ошиблись во второй раз. И когда эта колонка никак не связана ни с чем, то стопроцентов так и будет — тест не будет ничего толком тестировать.

А вы рассматривайте всё в совокупности: есть бизнес-требования, написанные на человеческом языке. Код — это перевод этих требований. И чем лучше он связан, тем большие гарантии, что он делает именно то.

Если вы делаете абстрактные никак не связанные с требованиями переменные, а потом какие-то прилепливаете названия в ГУИ, то для вас требования не первичны, и программа — не перевод, что не гуд. А если сумели связать и исходите из требований — то гуд.

Давайте представим идеальный язык. В требованиях сказано: бывают статусы у документа «в обработке», «отослан» и т.д. И вы создаете множество из элементов, которые ровно так и звучат. С пробелами. Без никаких дополнительных айдишек. Вот оно — вы точно тогда передаете смысл своей программой. Если еще были бы у этого языка конструкции, близкие к выражению смысла на человеческом языке — мы бы ВООБЩЕ не кодили, а просто описывали задачу, перечисляя требования.

Но всё не так плохо. На наших языках можно также передавать смысл. Можно очень плохо, а можно лучше. И вот, большинство программистов исходят из интов, какой-то х… и другой, считая, что они делают что-то. А потом, привязывают типа названия и смысл в конце. Т.е. код не ориентированный на требования изначально.

Я бы разложил конкретную задачу для примера, чтобы было понятнее, как это возможно. А то вы смотрите на приоритет каких-то чисел и непонятно чего, а потом сами же говорите, что дескрипшин в вашем представлении с логикой не связан и поэтому нет смысла на него смотреть. Да просто вы сами себе так представили.

млин )))

DocState — это HTTP-статусы? Нет. Это артефакт нашего приложения? Да. Они могут поменяться в рамках нашего приложения? Да.

HTTP-статусы — это артефакт нашего приложения? Нет. Мы за эти кода ответственны? Если номер статуса — стандарт и не наш причем, то ради бога, не храните их в базе, а смело в тестах пользуйтесь номерами.

Попытаюсь еще раз сформулировать мысль. Программа должна выражать смысл. Это не конструктор. За это надо еще было в ВУЗах наказывать, но некому. Программисты наши учатся не выражать мысли, а «писать программы».

То, что я предлагаю, исходит из смысла. Если вы в коде где-то на апликейшине даже взяли и ввели перечисление статусов и работаете на уровне кода с ними, то это далеко не круто. Смысл исходит начиная с требований и ГУИ, что пользователь видит. Он и его мысли по поводу работы ПО первичны. Поэтому дескрипшин, который он будет видеть (если будет) в комбобоксах или в даже описаны словами в документации — первичны. Поэтому и тест правильно на это завязывать. Хотя юнит-тест не обязательно. Но всё же если есть возможность исходить из смысла — это первично.

Если вы добавили перечисление в коде — это просто ни к чему не обязывающая фигня. Даже если умно назвали, это ничего не значит для пользователя. Вам в любом случае придется эти перечисления связать с названиями. И (о да!) они изменчивы, чтобы на них завязывался код. Но они — отличная штука, чтобы на них завязывались тесты. Возможно придется написать перечисление, чтобы сделать нормально наследование и разное поведение в разных статусах. Но так или иначе оно должно как стержень, прошить всё приложение и на ГУИ или в документациях описанный словами смысл. Поэтому не лишнее (даже обязательное) хранить предметную область в базе. Сделаете перечисление, будете откуда-то вытягивать названия на русском языке (или для кого там пишете). И вот, они будут в базе. Плюс написать еще один простой тест, чтобы перечисление мапилось на табличку один к одному. Чтобы айди записей и количество — совпадали. И колонка имени (== элементу перечисления).

С т.з. производительности вообще нет никаких проблем. Код апдейта, как видим, не джойнится к ней. Зато наличие этой таблички гарантирует, что не апдейтните какое-то бессмысленное число. А табличка статусов говорит о смысле.

Вы в апликейшине можете использовать перечисления. Тогда будет дублирование. Перечисление будет отражением таблицы. приведение к инту элемента перечисления будет айдишкой. Тоже нормальная практика. В чем проблема, не знаю. Если вы разрываете модель, то вы не можете внутри базы писать осмысленные тесты, опирающиеся на требования. Тестировать просто буквы или просто код, который бессмысленнен, не имеет смысла. Тогда тесты, возможно, надо будет писать на уровень выше, а не в базе на каждый апдейт или хранимку. Там, где код уже имеет смысл с т.з. задачи.
конечно. Не только целостность. Сам смысл. Если человек рассматривает таблицы, как абы-что контейнеры, то… Что тут говорить.

Таблицы в первую очередь при хорошем моделировании или сущности или связи между сущностями. Выразить с помощью таблиц предметную область — это ли оверинжиниринг???

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

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

Говорить, что здесь оверинжиниринг… Ну слов нету )))) Т.е. убрать с одного места код, перенести в другое место, а далее говорить, что локально в первом куске кода меньше ))))

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

Ну так не надо разрывать модель данных
???

Где оверинжиниринг?
первое и более главное требование к коду: отражение смысла. Языки программирования — это не конструкторы, где как хочешь, так и строишь домики. Код должен быть читаем и отражать то, что от него хотели.

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

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

На селект тоже можно писать тесты, в случае «закрепления» логики, если она еще и подкреплена хардкодными идентификаторами.
:)

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

Information

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