Задать вопрос
  • С чего начать изучение написания TDD - тестов?

    @abcd0x00
    Сергей Протько:

    Опять же у вас есть пример?

    Вот функция из одной строки:
    func(a, b) { return a + b }
    Вот тесты:
    func(1, 2) == 3
    func([1], [2]) == [1, 2]
    func([], []) == []
    func([1], []) == [1]
    func([], [2]) == [2]

    Ещё можно напридумывать; главное, чтобы они покрывали случаи где это всё может выпасть.
    Итого, на одну строку приходится множество тестов.

    Мне уже немного надоело цитаты расставлять)

    Ну да, кривовато они ставятся, потому что кое-кто не знает про предпросмотр. ;)
  • С чего начать изучение написания TDD - тестов?

    @abcd0x00
    Сергей Протько:
    - чуть чуть поправили код
    - прогнали тесты и убедились что ничего не сломали
    - чуть чуть подправили тесты
    - прогнали тесты и убедились что вы не сломали ничего в тестах, в этом случае гарантом того что все работает выступает ваш код

    Так а где тут разработка через тестирование? Это просто покрытие кода тестами, тогда как при TDD код управляется тестами, а не просто ими покрывается и проверяется.

    Ух... как все запущено...

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

    У вас выборка не репрезентативна. Я понимаю еще в два раза, но в 10... Опять же TDD не регламентирует вам сколько у вас должно быть покрыто тестами кода, 10% или 100%.

    Покрытие - это вообще относится ко всему тестированию, там общие правила покрытия, чтобы было эффективно. TDD к этому вообще не относится и никаких правил не задаёт.

    Когда у вас тестов в 10 раз больше чем кода, это повод задуматься.

    Что задумываться, тестирование предполагает проверку множества вариантов, чтобы программа надёжнее была. И не повторяют они друг друга.

    Либо у нас мегакритичная часть приложения

    Программа должна быть надёжной сама по себе, а не по критерию "клиент принял - значит, всё правильно".

    которая должна учитывать все позитивные и негативные сценарии на всех пограничных случаях

    Да и без этого тестов навалом, потому нюансов бывает дофига и больше.

    Вообще доводы в духе "жалко удалять" это смешно.

    Ну, у тебя-то, походу, этим тестировщики занимаются, поэтому тебе это смешно, сам ничего не пишешь потому что. Но мы-то здесь не про то, как тестировщиками задания передавать, а как вести свою разработку.
  • С чего начать изучение написания TDD - тестов?

    @abcd0x00
    Сергей Протько:

    Вот я пытался бороться с говнокодом, вводили кодревью и прочее.... и в итоге я всеравно пришел к тому что в этом нет никакого value, пусть себе будет до рефакторинга. Работает и ладно.

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

    Повторюсь, у меня есть 3 слоя:

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

    Жалко только потраченного времени но это быстро проходит.

    При TDD тестового кода по количеству больше программного в десять раз. И жалко терять его, а ведь его никуда больше не пристроишь, ни в одну программу, тогда как из программного кода ещё можно взять что-то полезное.

    bagerman: Ну, надо же проявить минусы TDD, про них редко пишут, а они есть.
  • С чего начать изучение написания TDD - тестов?

    @abcd0x00
    Сергей Протько:

    Ну и зачем так делать? Можно например написать не 1 тест а 10, я так иногда делаю когда более-менее уверен в том что как должно быть. Но 100 тест кейсов... это явно перебор.

    Это делается затем, что если требования меняются к коду, чтобы переписать только тесты под новые требования, а код, выполняющий старые, не надо было выбрасывать. По тестам всегда видно, что "делает" этот несуществующий код, и так ты контролируешь его функции. То есть кода нет, но по тестам видно, что он делает и насколько он готов. Почему не 10, потому что 10 - мало. Ты, может быть, имеешь в виду большие десять тестов, но тесты нельзя делать большими, потому что это такой же код - просто получится каша-малаша.
    10 тестов в моём понимании - это тестовый класс, в котором десять методов.

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

    От прототипа (скоростная версия без тестов) я сразу получаю реальные данные. А чем они отличаются, а тем, что берутся из реального мира. В тестах-то они выдумываются.

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

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

    У Дяди Боба скажем довольно жесткие правила:

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

    И ни слова о интерфейсах и прочего.

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

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

    Значит, там ошибки. Ты просто так не перекинешь эту инфраструктуру в другие программы, потому что тестов нет. А где гарантия, что они правильно работают? Правильная работа в каком-то контексте не гарантирует правильной работы во всех контекстах.

    Так программа или UI?

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

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

    Да, главное, что-нибудь посложнее написать, чтобы потом никто в этом не разобрался. :)
  • С чего начать изучение написания TDD - тестов?

    @abcd0x00
    Сергей Протько:

    Как это понимать? Вы месяц тупо писали тесты? Это как бы идет в разрез с TDD если что.

    Не идёт оно вразрез. Просто вместо одного теста ты пишешь сто.

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

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

    Используя TDD вы все это видите еще на этапе написания тестов

    Речь идёт про реальные данные, которые нужны, а не про составленные. Про мотивацию идёт речь. Программа пишется, чтобы получить определённые данные.

    проблемы открываются раньше

    Проблемы могут появляться из пустоты. Собираешься, например, добавить новую фичу (необходимую), а она не подходит к тем фичам, которые уже есть. Значит, тебе надо их перестроить, чтобы её включить. А они обложены тестами, которых по количеству кода больше, чем этих фич, раз в десять.

    Скажем покрывать тестами код, который должен только заменить данные (по сути сеттеры, хотя я сеттеры аля setSomething не пишу).

    Да никто не пишет покрытие для элементарных методов.

    Я это к чему, можете сформулировать эти самые правила TDD?

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

    Этого не может быть, если вы практикуете TDD.

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

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

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

    @abcd0x00
    Даниил:

    Вообще-то, он лезет проверять в __lt__ при > :
    >>> class Test:
    ...   def __init__(self,value):
    ...     self._value = value
    ...   
    ...   def __lt__(self,other):
    ...     print('lt')
    ...     if type(other) != Test:
    ...       raise ValueError('comparing object must be of type Test')
    ...     return self._value < other._value
    ... 
    >>> a = Test(10)
    >>> b = Test(20)
    >>> a < b
    lt
    True
    >>> a > b
    lt
    False
    >>>
  • Как не прописывать действие для каждой операции сравнения?

    @abcd0x00
    Даниил:

    __gt__ не изменился:
    >>> class Test:
    ...   def __init__(self,value):
    ...     self._value = value
    ...   
    ...   def __lt__(self,other):
    ...     if type(other) != Test:
    ...       raise ValueError('comparing object must be of type Test')
    ...     return self._value < other._value
    ... 
    >>> a = Test(10)
    >>> b = Test(20)
    >>> a < b
    True
    >>> a > b
    False
    >>> a < 3
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 7, in __lt__
    ValueError: comparing object must be of type Test
    >>> a > 3
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: unorderable types: Test() > int()
    >>>
  • Как не прописывать действие для каждой операции сравнения?

    @abcd0x00
    Даниил:

    Если вы определяете __lt__ (<), то неявно автоопределится __gt__ (>), но не __ge__ (>=) и __le__ (<=).


    С чего вдруг там __gt__ определится? Если что-то не меньше, то это недостаточно для того, чтобы оно было больше.

    Благо питон даёт удобный интерпретатор, в котором легко всё проверяется:
    >>> class A:
    ...     def __lt__(self, v):
    ...         return hasattr(v, 'x')
    ... 
    >>> class B:
    ...     x = 1
    ... 
    >>> class C:
    ...     y = 1
    ... 
    >>> a, b, c = A(), B(), C()
    >>> 
    >>> a < b
    True
    >>> a > b
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: unorderable types: A() > B()
    >>> a == b
    False
    >>> a != b
    True
    >>> a <= b
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: unorderable types: A() <= B()
    >>> a >= b
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: unorderable types: A() >= B()
    >>> 
    >>> a < c
    False
    >>> a > c
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: unorderable types: A() > C()
    >>> a == c
    False
    >>> a != c
    True
    >>> a <= c
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: unorderable types: A() <= C()
    >>> a >= c
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: unorderable types: A() >= C()
    >>>
  • Какая разница между C, C#, C++?

    @abcd0x00
    "Ну почему же неправильно. Все круто было, особенно для своего времени и в сравнении с главной альтернативой - ассембером."

    Не, я имел в виду auto_ptr, который сначала встроили в язык, а потом зачеркнули.
    https://en.wikipedia.org/wiki/Auto_ptr
    The current C++ standard, C++11, made auto_ptr deprecated, replacing it with the unique_ptr class template.
  • Вы тоже постоянно всё забываете из программирования?

    @abcd0x00
    Иногда открываешь старый код, думая, что там что-то простое, а там какая-то сложная вещь реализована в лучшем виде. И не понимаешь, как ты это сделал тогда.
  • Какая разница между C, C#, C++?

    @abcd0x00
    coodan: "Те же умные указатели, хотя бы."
    Учил-учил, и тут оказалось, что теперь там кое-что устарело и стало заменено на новое, потому что было неправильно сделано изначально.
  • Что то с моей головой или с ssh?

    @abcd0x00
    Павел Падожников: ты увидишь там, почему он при наличии ключей переходит к запросу пароля (этот вариант запускается, когда ключ не найден).
  • Как лучше: разбивать рабочий день на две части или работать залпом, а потом отдыхать?

    @abcd0x00
    Радмир: вообще, получается что-то вроде природного: как устаёшь, отдыхаешь. Но сводить по максимуму получается к вузовскому варианту, чтобы больше делать и меньше "развлекаться".
  • Чем плохи комментарии на русском языке в коде?

    @abcd0x00
    Дѣаволъ: Да книги несущественны. Просто тут дело в коллективной разработке. Португалец и русский смогут вместе работать, если пишут на английском оба.
  • Используете ли вы витамины для "мозга"?

    @abcd0x00
    Evgeniy Burmakin:
    "Но ведь это миф."

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

    @abcd0x00
    Дѣаволъ:
    Вчера искал себе прокси, наткнулся на очередной пример
    code.google.com/p/python-proxy
    Докстринг, описывающий программу, даже не на испанском, а на португальском.

    "Лично мне проще читать чужой код"
    Когда его много, читать просто нет времени.
  • Чем плохи комментарии на русском языке в коде?

    @abcd0x00
    Не, просто больше людей смогут прочитать мою программу. В сотни раз больше.
  • Сначала учить язык программирования или сразу framework?

    @abcd0x00
    Хочу научиться читать, мне буквы учить или можно сразу слова заучивать?
  • Как выделить повторяющуюся строку из другой строки?

    @abcd0x00
    "Очевидно, что здесь повторяется слово PYTHON."

    PYTHONPYTHONPYTHON и YTHONPYTHONPYTHONP там тоже повторяются.