MetaProg

Описание: Разработка и отладка приложений. Упор на 3D-графику.

dyvniy M
Автор темы, Администратор
Администратор
Аватара
dyvniy M
Автор темы, Администратор
Администратор
Возраст: 41
Репутация: 1
Лояльность: 1
Сообщения: 3579
Зарегистрирован: Ср, 10 октября 2012
С нами: 11 лет 5 месяцев
Профессия: Программист
Откуда: Россия, Москва
ICQ Сайт Skype ВКонтакте

#43 dyvniy » Вт, 30 августа 2016, 17:53:41

О большое
https://habrahabr.ru/post/308818/
Спойлер
Когда «О» большое подводит перевод

Программирование*,
Математика*,
Компиляторы*,
Алгоритмы*




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

Память, медленная-медленная память


В начале 1980-х время, необходимое для получения данных из ОЗУ и время, необходимое для произведения вычислений с этими данными, были примерно одинаковым. Можно было использовать алгоритм, который случайно двигался по динамической памяти, собирая и обрабатывая данные. С тех пор процессоры стали производить вычисления в разы быстрее, от 100 до 1000 раз, чем получать данные из ОЗУ. Это значит, что пока процессор ждет данных из памяти, он простаивает сотни циклов, ничего не делая. Конечно, это было бы совсем глупо, поэтому современные процессоры содержат несколько уровней встроенного кэша. Каждый раз когда вы запрашиваете один фрагмент данных из памяти, дополнительные прилегающие фрагменты памяти будут записаны в кэш процессора. В итоге, при последовательном проходе по памяти можно получать к ней доступ почти настолько же быстро, насколько процессор может обрабатывать информацию, потому что куски памяти будут постоянно записываться в кэш L1. Если же двигаться по случайным адресам памяти, то зачастую кэш использовать не получится, и производительность может сильно пострадать. Если хотите узнать больше, то доклад Майка Актона на CppCon — это отличная отправная точка (и отлично проведенное время).


В результате этого массивы стали лучшей структурой данных, когда важна производительность, даже если согласно анализу "О" большого массив должен работать медленнее. Там, где вы хотели использовать дерево, отсортированный массив с двоичным поиском может подойти лучше. Там, где вы хотели использовать очередь, растущий массив может подойти лучше, и так далее.

Связный список и динамический массив


Когда вы поняли важность доступа к последовательной памяти, для вас не будет сюрпризом тот факт, что если нужно быстро пройти по коллекции, то массив будет быстрее связного списка. Окружения с умным управлением памятью и сборщиками мусора, возможно, будут хранить узлы связного списка более последовательно, но они не могут гарантировать это. Использование сырого массива обычно требует более сложного кода, особенно когда нужно вставлять или добавлять новые элементы, так как придется обрабатывать рост массива, перемещение элементов, и так далее. В большинстве языков есть родные библиотеки, содержащие ту или иную реализацию динамических массивов. В C++ естьvector, в C# есть List (в F# используется под именем ResizeArray), а в Java есть ArrayList. Обычно эти структуры предоставляют такой же или похожий интерфейс, как и связный список. В этой статье я буду называть такие структуры динамическими массивами (Array List), но имейте ввиду, что в примерах на C# используется класс List, а не более старый ArrayList.


Что, если нужна структура данных, в которую можно быстро вставлять элементы и быстро проходить по ним? Давайте представим, для этого примера, что у нас такой случай: мы будем вставлять в начало коллекции примерно в 5 раз чаще, чем проходить по ней. Давайте также представим, что и у связного списка, и у динамического массива в нашей среде есть одинаково приятные для работы интерфейсы. Остается только решить, что будет более эффективным решением. Мы можем обратиться к анализу "О" большго для оптимизации нашего ценного времени. Обратимся к полезной подсказке про "О" большое, соответствующие сложности для этих структур данных это:
Проход Вставка
Динамический массив O(n) O(n)
Связный список O(n) O(1)



Проблема динамических массивов заключается в ставке, как минимум нужно будет копировать и двигать каждый элемент на единицу после точки вставки чтобы освободить место для нового элемента. Отсюда O(n). Иногда нужно создать новый массив, больший по размеру чтобы появилось место для вставки. В нашем случае вставка происходит в 5 раз чаще, чем проход, так что, кажется, вывод очевиден. Пока n достаточно большой, связный список должен в целом быть эффективнее.

Эксперимент


Но чтобы удостовериться, лучше посчитать. Давайте проведем эксперимент с C#, используя BenchMarkDotNet. В C# есть коллекция LinkedList, которая является классическим связным списком, и List, который является динамическим массивом. Интерфейсы у обоих похожи, и оба можно с легкостью применить в нашем случае. Рассмотрим худший случай для динамического массива — вставка всегда происходит в начало, так что приходится копировать весь массив при каждой вставке. Конфигурация окружения тестирования такая:

Host Process Environment Information:
BenchmarkDotNet.Core=v0.9.9.0
OS=Microsoft Windows NT 6.2.9200.0
Processor=Intel(R) Core(TM) i7-4712HQ CPU 2.30GHz, ProcessorCount=8
Frequency=2240910 ticks, Resolution=446.2473 ns, Timer=TSC
CLR=MS.NET 4.0.30319.42000, Arch=64-bit RELEASE [RyuJIT]
GC=Concurrent Workstation
JitModules=clrjit-v4.6.1590.0

Type=Bench Mode=Throughput

Тест-кейсы:

[Benchmark(Baseline=true)]
public int ArrayTest()
{
//In C#, List<T> is an array backed list.
List<int> local = arrayList;
int localInserts = inserts;
int sum = 0;
for (int i = 0; i < localInserts; i++)
{
local.Insert(0, 1); //Insert the number 1 at the front
}

// For loops iterate over List<T> much faster than foreach
for (int i = 0; i < local.Count; i++)
{
sum += local[i]; //do some work here so the JIT doesn't elide the loop entirely
}
return sum;
}

[Benchmark]
public int ListTest()
{
LinkedList<int> local = linkedList;
int localInserts = inserts;
int sum = 0;
for (int i = 0; i < localInserts; i++)
{
local.AddFirst(1); //Insert the number 1 at the front
}

// Again, iterating the fastest possible way over this collection
var node = local.First;
for (int i = 0; i < local.Count; i++)
{
sum += node.Value;
node = node.Next;
}

return sum;
}

Результаты:
Метод Размер Вставки Медиана
ArrayTest 100 5 38.9983 us
ListTest 100 5 51.7538 us



Динамический массив выигрывает с неплохим отрывом. Но это маленький список, "О" большое описывает производительность только растущего до больших размеров n, так что результаты теста должны в итоге перевернуться наоборот при увеличении n. Давайте попробуем:
Метод Размер Вставки Медиана
ArrayTest 100 5 38.9983 us
ListTest 100 5 51.7538 us
ArrayTest 1000 5 42.1585 us
ListTest 1000 5 49.5561 us
ArrayTest 100000 5 208.9662 us
ListTest 100000 5 312.2153 us
ArrayTest 1000000 5 2,179.2469 us
ListTest 1000000 5 4,913.3430 us
ArrayTest 10000000 5 36,103.8456 us
ListTest 10000000 5 49,395.0839 us






Неожиданные для многих результаты. Каким бы большим ни был n, динамический массив все равно оказывается лучше. Чтобы производительность стала хуже, отношение вставок к проходам должно измениться, а не только размер коллекции. Заметьте, что это не ошибка анализа "О" большого, это просто человеческая ошибка — мы неправильно применяем метод. Если углубиться в математику, то "О" большое покажет, что обе структуры данных будут расти с одной скоростью пока отношение вставок к проходам не меняется.


Где находится переломный момент, зависит от множества факторов, но хорошее приближенное правило предложено Чандлером Каррутом из Google: динамический массив будет эффективнее связного списка пока вставок на порядок больше, чем проходов. В нашем случае правило работает хорошо, потому что при отношении 10:1 можно увидеть сдвиг в сторону связного списка:
Метод Размер Вставки Медиана
ArrayTest 100000 10 328,147.7954 ns
ListTest 100000 10 324,349.0560 ns


Дьявол в деталях


Динамический массив побеждает потому, что числа, по которым происходит проход, находятся в памяти последовательно. Каждый раз, когда происходит запрос числа из памяти, целый набор чисел добавляется в кэш L1, так что следующие 64 байта данных уже готовы к обработке. При работе со связным списком каждый вызов node.Next перенаправляет указатель на следующий узел, и нет гарантий, что этот узел будет находится в памяти сразу за предыдущим. Поэтому иногда мы будем попадать мимо кэша. Но нам не всегда приходится работать с типами, хранящими непосредственно значения, особенно в объектно-ориентированных языках, где проход зачастую происходит по ссылочным типам. В таком случае, не смотря на то, что в динамическом массиве сами указатели находятся в памяти последовательно, объекты, на которые они указывают — нет. Ситуация все еще лучше, чем со связным списком, где вам придется дважды разыменовывать указатели для каждого элемента, но как это влияет на общую производительность?


Производительность значительно ухудшается, в зависимости от размера объектов и особенностей железа и софта. Если заменить в примере выше числа на маленькие объекты (12 байт), то точка "перелома" опускается до 4 вставок к одному проходу:
Метод Размер Вставки Медиана
ArrayTestObject 100000 0 674.1864 us
ListTestObject 100000 0 1,140.9044 us
ArrayTestObject 100000 2 959.0482 us
ListTestObject 100000 2 1,121.5423 us
ArrayTestObject 100000 4 1,230.6550 us
ListTestObject 100000 4 1,142.6658 us



Управляемый код на C# сильно страдает в этом случае, потому что проход по динамическому массиву создает излишние проверки границ массива. Вектор в С++, скорее всего, будет работать эффективнее. Если быть совсем агрессивным в решении этой задачи, то можно написать более быстрый класс для динамического массива с использованием небезопасного кода C# чтобы избежать проверки границ массива. Относительная разница также будет сильно зависеть от того, как распределитель памяти и сборщик мусора управляют динамической памятью, насколько большие объекты и от других факторов. Более крупные объекты обычно улучшают производительность динамических массивов в моей среде. Когда речь идет о целых приложениях, относительная производительность динамических массивов может также улучшаться с увеличением фрагментации динамической памяти, но чтобы удостовериться, нужно проводить тестирование.


Еще один момент. Если объекты достаточно маленькие (от 16 до 32 байтов или меньше в разных ситуациях), то стоит рассмотреть вариант хранения их по значению (struct в .NET), а не в объекте. Это не только сильно улучшит производительность благодаря последовательному распределению в памяти, но также теоретически уменьшит дополнительную нагрузку из-за сборки мусора, в зависимости от сценария использования этих данных:
Метод Размер Вставки Медиана
ArrayTestObject 100000 10 2,094.8273 us
ListTestObject 100000 10 1,154.3014 us
ArrayTestStruct 100000 10 792.0004 us
ListTestStruct 100000 10 1,206.0713 us



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

Убедитесь, что абстракция себя оправдывает


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


Информация для размышления: вот семь разных способов найти сумму списка чисел в C#, со временем исполнения и использованием памяти. Везде используется арифметика с проверкой переполнения, чтобы сравнение с Linq, где метод Sum использует именно такую арифметику, было корректным. Заметьте, насколько лучший метод быстрее остальных. Заметьте, насколько затратный самый популярный способ. Заметьте, что абстракция foreach хорошо работает с массивами, но не с динамическими массивами или связными списками. Каким бы ни был ваш язык и окружение, важно понимать эти детали чтобы принимать правильные решения по умолчанию.
Method Length Median Bytes Allocated/Op
LinkedListLinq 100000 990.7718 us 23,192.49
RawArrayLinq 100000 643.8204 us 11,856.39
LinkedListForEach 100000 489.7294 us 11,909.99
LinkedListFor 100000 299.9746 us 6,033.70
ArrayListForEach 100000 270.3873 us 6,035.88
ArrayListFor 100000 97.0850 us 1,574.32
RawArrayForEach 100000 53.0535 us 1,574.84
RawArrayFor 100000 53.1745 us 1,577.77


[Benchmark(Baseline = true)]
public int LinkedListLinq()
{
var local = linkedList;
return local.Sum();
}

[Benchmark]
public int LinkedListForEach()
{
var local = linkedList;
int sum = 0;
checked
{
foreach (var node in local)
{
sum += node;
}
}
return sum;
}

[Benchmark]
public int LinkedListFor()
{
var local = linkedList;
int sum = 0;
var node = local.First;
for (int i = 0; i < local.Count; i++)
{
checked
{
sum += node.Value;
node = node.Next;
}
}

return sum;
}

[Benchmark]
public int ArrayListFor()
{
//In C#, List<T> is an array backed list
List<int> local = arrayList;
int sum = 0;

for (int i = 0; i < local.Count; i++)
{
checked
{
sum += local[i];
}
}

return sum;
}

[Benchmark]
public int ArrayListForEach()
{
//In C#, List<T> is an array backed list
List<int> local = arrayList;
int sum = 0;
checked
{
foreach (var x in local)
{
sum += x;
}
}
return sum;
}

[Benchmark]
public int RawArrayLinq()
{
int[] local = rawArray;
return local.Sum();
}

[Benchmark]
public int RawArrayForEach()
{
int[] local = rawArray;
int sum = 0;
checked
{
foreach (var x in local)
{
sum += x;
}
}
return sum;
}

[Benchmark]
public int RawArrayFor()
{
int[] local = rawArray;
int sum = 0;

for (int i = 0; i < local.Length; i++)
{
checked
{
sum += local[i];
}
}

return sum;
}
 алгоритмы, структуры данных, программирование, оптимизация, математика, о большое
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама
Хабы
Программирование
JAVA
Отладка
Разработка мобильных приложений
Perl
Разработка под Android
JavaScript
Node.JS
GitHub
Разработка веб-сайтов
Все хабы
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама
Похожие публикации
Автоматическая генерация типизированных структур данных для Си 35
Алгоритмы и структуры данных — шпаргалка 43
Алгоритм подготовки данных для сжатия 62
Школа Microsoft по структурам данных и алгоритмам 39
Структуры данных: бинарные деревья. Часть 2: обзор сбалансированных деревьев 28



6,9k

48




Перевод:
Jack Mott
Рахим Давлеткалиев
@freetonik
карма
508,5
рейтинг
209,1
со-основатель Hexlet.io
Сайт
Facebook
Twitter
Github
Instagram
Реклама помогает поддерживать и развивать наши сервисы

Подробнее

Реклама
Самое читаемое
Разработка
Сейчас
Сутки
Неделя
Месяц
+11
Гейзенбаг, или как Луна портит код
5,5k
11
1
+10
Удостоверяющий центр из Китая по ошибке выдал пользователю SSL-сертификат для домена GitHub
4,7k
8
3
+15
PHP: неправильный путь
3k
24
10
+16
Let the Holy War begin: Java vs С++
2,6k
10
4
+34
Что нового в IntellIJ IDEA 2016.3 EAP
5,8k
10
2
Комментарии (16)
Monnoroch
30 августа 2016 в 14:08

–2


Вставка в динамический массив O(1). Потому у вас графики и параллельные вышли.
lair
30 августа 2016 в 14:09



+1



… в начало-то?
Monnoroch
30 августа 2016 в 14:27



0


Да, с началом вы правы, мой bias против вставки в начало меня подвел, я даже не рассматривал подсознательно этот вариант :)
LifeKILLED
30 августа 2016 в 17:46 (комментарий был изменён)



0


А зачем вообще вставлять в начало последовательного массива? Кто вообще будет так поступать? Обычно последовательность элементов вообще не имеет значения, перебирать ведь так или иначе придётся сразу все. Насчёт удаления из списка — тут тоже честное удаление не требуется, достаточно прописать в элементе «флаг» deleted=true, и просто пропускать его при переборе, а после N-ного числа удалений, так уж и быть, подчищать их. Ясное дело, что это заковыкистые хитрости, которые усложняют читабельность кода, но уж извините, оптимизации — они такие и есть. Их применяют с умом. И если тестировать самый неудачный вариант применения динамического массива, то какой прок от такого тестирования, если это по сути тест на криворукость?

Labunsky
30 августа 2016 в 15:53



0


Стоит учесть, что для вставки в произвольное место используется смещение с помощью memcpy и подобных, а не простой пробег for'ом. Не знаю, как именно оно работает в .Net, но даже при равной асимптотике, скорость может быть выше на порядок, отсюда и почти параллельные графики.
Viacheslav01
30 августа 2016 в 16:31



+1


А чем memcpy отличается от пробега фором, каким он по сути и является.
freetonik
30 августа 2016 в 14:19



0


В лучшем случае. В худшем — O(n).

quantum
30 августа 2016 в 14:20



–1


Почему О(1)? Вставка не в конец, а в произвольную позицию со сдвигом

nightwolf_du
30 августа 2016 в 14:36

0


@freetonik где-нибудь можно найти собранные библиотеки «быстрых» вариантов алгоритмов для c#?
Точнее, дополнения методами расширения на IEnumerable/другие интерфейсы для LINQ методов, по скорости сравнимых с RawArrayFor, дерева на динамическом массиве, и т. д.?

zartdinov
30 августа 2016 в 15:05

–2


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

Bombus
30 августа 2016 в 15:28

0


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

ToSHiC
30 августа 2016 в 16:09



+2


What every programmer should know about memory, http://lwn.net/Articles/250967/
Есть переводы на русский разной степень хорошести.
BloodUnit
30 августа 2016 в 16:30 (комментарий был изменён)

+1


Если объекты достаточно маленькие (от 16 до 32 байтов или меньше в разных ситуациях), то стоит рассмотреть вариант хранения их по значению (struct в .NET), а не в объекте.

Откуда взяты эти цифры, чем плоха структура меньше 16 байт?
Sing
30 августа 2016 в 16:30

+7


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

Судя по всему, автор не понимает Big-O. Вне зависимости от того, на какое константное число раз вставок будет больше, чем проходов, O(F(x)) не изменится.

т.е. мы имеем для массива вставку и проход = O(n) + 5O(n) = O(n)
для связного списка O(n) + 5O(1) = O(n)

Делаем графики, они действительно растут примерно одинаково, но это почему-то:

> Неожиданные для многих результаты.

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

Если делать ТОЛЬКО вставки, то связный список будет СУЩЕСТВЕННО лучше, только об этом говорит Big-O. Он не говорит ни о конкретной реализации, ни о том, кто из двух O(n) быстрее. Ему, если хотите, всё равно. Для Big-O разница в 2 раза — это не «неплохой отрыв», это пшик.

Для реальных применений, конечно, разница даже в миллисекунду может иметь значение. Но тут единственное правило — измеряйте. Big-O даёт отличный старт для поиска оптимального решения и оно не «подводит», как написано в заголовке (или, как у оригинала, «обманывает»).
LifeKILLED
30 августа 2016 в 17:34 (комментарий был изменён)

0


Реакция после прочтения: «Какого *#$?!». Последняя табличка выморозила даже не тем, что перебор последовательного массива гораздо быстрее перебора связного списка. Как бы так и должно быть, свои плюсы и минусы, свои цели. Вымораживает то, что встроенная в язык команда foreach оказалась в 2 два раза медленнее конструкции for! Как так вообще произошло?! В какой день рухнул мир?! (а уж про Sum() и говорить страшно, только покрутить пальцем у виска)
Viacheslav01
30 августа 2016 в 17:36



+1


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

dyvniy M
Автор темы, Администратор
Администратор
Аватара
dyvniy M
Автор темы, Администратор
Администратор
Возраст: 41
Репутация: 1
Лояльность: 1
Сообщения: 3579
Зарегистрирован: Ср, 10 октября 2012
С нами: 11 лет 5 месяцев
Профессия: Программист
Откуда: Россия, Москва
ICQ Сайт Skype ВКонтакте

#44 dyvniy » Ср, 31 августа 2016, 16:51:19

Абстракции
http://russian.joelonsoftware.com/Articles/LeakyAbstractions.html
Спойлер
Закон Дырявых Абстракций


Автор: Джоэл Сполски
Переводчик: Семён Хавкин
Редактор: Маргарита Исаева
23 марта 2000


Есть в Интернете инженерное волшебство, на работу которого мы с вами полагаемся каждый день. Оно заключено в сетевом протоколе TCP, одном из основных кирпичей, из которых выстроен Интернет.

TCP — способ пересылки данных, который считается надёжным. Это значит: если вы с его помощью отсылаете сообшение по сети, оно обязательно прибудет на место в неискажённом виде.

Мы все пользуемся TCP для повседневных нужд: загрузить страничку с веба, послать электронную почту. Надёжность TCP позволяет всякому Остапу Бендеру из Восточной Африки рассылать по миру спам наивысшего качества. О счастье, о радость!

Посмотрим теперь на другой, ненадёжный, метод пересылки данных под названием IP. Тут уже никто не обещает, что посылка доедет до места назначения, и что по дороге с ней ничего не случится. Отправляя через IP кучу сообщений, не удивляйтесь, если половина из них потеряется, а из остальных часть окажется совсем не тем, что посылалось: может, они будут содержать фотографии прелестных котят, но скорее всего — просто нечитаемый мусор, вроде столь любимого нами всеми тайваньского спама.

Волшебство же состоит в том, что TCP основан на IP. Иными словами, TCP обязуется работать надёжно, используя лишь ненадёжные детали.

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

Предположим, некая дама отправляла подводами из Петербурга в Москву диван, чемодан, саквояж и т.д. Часть подвод сломалась и до Москвы не доехала. Часть подвод опрокинулась по пути, разбив картину, картонку и зеркала. Подводы добирались до Москвы не в том порядке, в каком выезжали из Петербурга, поскольку некоторых задержали страшные лесные разбойники, и вообще возницы выбирали разные маршруты. А теперь представим, что даме предлагается новая услуга: Красная Стрела, которая гарантирует, что багаж (а) прибудет на место (б) в целости и сохранности (в) и в нужном порядке. Но волшебным образом Красная Стрела не использует, как вы подумали, железной дороги, а нанимает тех самых возниц с подводами. Красная Стрела организует работу возниц следующим образом. Состояние багажа каждой подводы тщательно проверяется. В случае повреждения диван, чемодан и проч. заменяются со склада точно такими же. Подводы выстраиваются в правильном порядке. Если страшные лесные разбойники сумели захватить Бологое и перерезать дорогу, то Красная Стрела перенаправляет подводы другим путём, и дама ничего не подозревает. Ей просто кажется, что багаж прибывает немного медленнее, чем обычно; а об ужасных событиях в Бологом даме знать необязательно.

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

Вернёмся к TCP. Я тут для простоты слегка загнул, и у кого-то, может быть, от этого уже пар из ушей пошёл. Короче, я сказал, будто TCP гарантирует, что сообщение прибудет на место. На самом деле, это не так. Если ваш любимый хомячок перегрызёт сетевой кабель, так что никакие пакеты IP не дойдут до компьютера, то TCP ничего не сможет поделать, и сообщение не придёт. Если же вы поругались с сетевым администратором, который в отместку включил ваш компьютер в перегруженный хаб, то много пакетов IP потеряется, и хотя TCP будет работать, но так медленно, что за время пути собачка, сами понимаете, того.

Вот это я и называю дырявой абстракцией. TCP пытается абстрагироваться от ненадёжной сети полностью, но иногда эта сеть все-таки просвечивает сквозь дыры в абстракции, так что абстракция не всегда защищает от необходимости иметь дело с глубокими подробностями. Это всего лишь один пример того, что я назвал Законом Дырявых Абстракций:Все нетривиальные абстракции дырявы.


В абстракциях обнаруживаются дыры. В одних немного, в других целая куча. Эти дыры постоянно просвечивают, протекают, абстракции не срабатывают. Вот ещё примеры.
Простой пример: итерация по большому двумерному массиву может идти с совершенно разной скоростью, смотря как он обходится: горизонтально или вертикально. Как и в случае с поленом, которое легче раскалывать вдоль волокна, а не поперёк, одно направление может вызывать значительно больше отказов памяти, чем другое, а отказы обслуживаются долго. Даже программистам на ассемблере приходится делать вид, что у компьютера большая плоская память, но в системе виртуальной памяти это всего лишь абстракция, в которой при отказе памяти образуется дырка, так что отдельные обращения к памяти могут занимать значительно больше наносекунд, чем обычно.
Язык SQL был создан, чтобы абстрагироваться от процедурных шагов, нужных для запросов к базе данных. Вместо этого он позволяет описать, что именно запрашивается, и пусть база данных сама догадается, какие процедурные шаги для этого нужны. Но в иных случаях некоторые запросы SQL в тысячи раз медленнее, чем другие, логически им эквивалентные. Известный пример: некоторые сервера SQL значительно быстрее отрабатывают запрос where a=b and b=c and a=c , чем where a=b and b=c , хотя результат, конечно, тот же самый. Программисту на SQL вроде бы и не следует заботиться о процедуре, только о спецификациях. Но иногда абстракция протекает, что приводит к страшным потерям в производительности, так что приходится лезть во внутренности планировщика запросов и смотреть, что там не так, и как заставить его работать эффективнее.
Хотя сетевые библиотеки, вроде NFS и SMB, позволяют работать с файлами на других машинах как на своей, иногда связь становится очень медленной или просто падает, и дальний файл перестаёт прикидываться местным; а ведь программисту надо писать код так, чтобы и в этой ситуации всё работало. Значит, в абстракции "всё равно, где лежит этот файл" есть дырки.

Вот пример для системных администраторов Юникса. Если домашние директории лежат на дисках, подмонтированных по NFS (одна абстракция), а пользователи создают файлы .forward для автоматической пересылки почты в другое место (вторая абстракция), и сервер NFS падает, а почта всё прибывает, то никуда она не перешлётся, поскольку файл .forward будет недоступен. Так сквозь дырку в абстракции письма могут просыпаться на пол.
Строковые классы должны представлять строчки в виде граждан первого класса. Они абстрагируются от того, что строки — штуки сложные, и дают возможность работать с ними легко, ну прям как с числами. Почти все строковые классы C++ перегружают оператор +, и для конкатенации строчек можно писать s+"bar". Но как ни старайся, никакой на свете строковый класс C++ не даст вам написать "foo"+"bar", поскольку строковые литералы в C++ всегда имеют тип char*, а не string. Абстракция прохудилась так, что языком C++ её не заткнёшь. (Интересно, что историю развития C++ можно описать как историю затыкания дырок в абстракции строк. Уж не знаю, отчего бы не добавить к языку элементарный класс строчек.)
И ещё: несмотря на дворники, мощные фары, крышу и обогреватель, которые защищают (абстрагируют) от непогоды, под дождём быстро ехать нельзя; приходится иметь дело с водяной подушкой, а иногда ливень такой, что на дороге ничего не видно, и надо остановиться; так что и погоду, из-за закона дырявых абстракций, полностью не абстрагируешь.

Закон дырявых абстракций означает, к сожалению, что абстракции не так сильно упрощают нашу жизнь, как хотелось бы. Если я обучаю программистов C++, было бы здорово, если бы мне не нужно было рассказывать им про char* и арифметику указателей, а можно было сразу перейти к строкам из стандартной библиотеки темплейтов. Но в один прекрасный день они напишут "foo"+"bar", и возникнут странные проблемы, а мне придётся всё равно объяснить им, что такое char*. Или они попытаются вызвать функцию Windows с параметром типа LPTSTR и не смогут, пока не выучат char* и указатели и Юникод и wchar_t и хедерные файлы TCHAR — все то, что просвечивает через дырки в абстракциях.

Когда я обучаю кого-то программированию COM, было бы здорово ограничиться визардом Студии и автоматической генерацией кода, но если что-то выйдет не так, у них не будет ни малейшего понятия, что случилось и как это исправить. Значит, надо рассказывать им про IUknown и CLSID и ProgIDS и... о боги!

При обучении программистов ASP.NET было бы здорово сказать: мол, дважды кликните мышом на штучку, а затем пишите код, который должен отрабатываться на сервере, когда пользователь кликнет на эту штучку. И правда, ASP.NET абстрагирует разницу между написанием кода HTML для отработки нажатия на гиперссылку (<a>) и кода для отработки нажатия на рисованную клавишу. Проблема: разработчикам ASP.NET пришлось скрыть тот факт, что в HTML нету способа отсылать форму из гиперлинка. Они обходят это, генерируя несколько строчек на JavaScript и добавляя к гиперлинку функцию onclick. Но эта абстракция дырява. Если пользователь отключит JavaScript, то приложение на ASP.NET не будет правильно работать; и если программист не знает, что именно абстрагировалось ASP.NET'ом, он не поймёт, в чём там дело. Из-за закона дырявых абстракций вот что получается: придумает кто-нибудь чудесный новый генератор кода, с которым у программиста работа наконец-то станет эффективной, а ему и говорят: "Сперва научись делать это руками, а потом уж пользуйся генератором, чтобы сэкономить время". Генераторы кода, абстрагирующие разработку кусков кода, так же дырявы, как и все прочие абстракции. А единственный компетентный способ залатать эти дыры - выучить, как работают абстракции, и какие подробности они скрывают. Итак, абстракции экономят наше рабочее время, но не экономят учебное время.

Отсюда парадоксальное следствие: в то время как инструментарий программиста забирается на всё более высокие уровни сложности со всё более развитыми абстракциями, подготовить высококвалифицированного программиста становится всё труднее.

Во время мой первой стажировки в Microsoft я писал строковые библиотеки для Макинтоша. Типичное задание: написать версию функции strcat, которая возвращает указатель на конец новой строки. Несколько строчек кода на C. Всё, что я делал, пришло прямо со страниц К&Р, одной тоненькой книжки про язык C.

Сегодня же для работы над CityDesk'ом мне нужно знать Вижуал Бэйсик, COM, ATL, C++, InnoSetup, внутренности Эксплорера, регулярные выражения (RegExp), DOM, HTML, CSS и XML. Всё это инструменты более высокого уровня по сравнению со старым K&Р, а всё ж таки мне и его надо знать, не то беда.

Десять лет назад можно было мечтать, что на сегодняшний день новые компьютерные концепции облегчат труд программиста. И правда: созданные за эти годы абстракции позволяют работать с проектами на порядки более сложными, чем десять или пятнадцать лет назад, типа программирования GUI и сетевого программирования. Но хотя замечательные инструменты, вроде современных объектных языков визуальных форм, позволяют сделать много и очень быстро, вдруг в один злосчастный день приходится искать течь в абстракции, и на это уходит пара недель. А когда вам нужно найти себе программиста в основном на Вижуал Бэйсике, совершенно недостаточно нанять программиста только на Вижуал Бэйсике, потому что каждый раз, когда абстракции Бэйсика потекут, он не сможет сделать ни шага.

Закон дырявых абстракций крепко держит нас за штаны.

Комментарии переводчика:

*) "Остапу Бендеру из Восточной Африки". Или из Западной; жулик - он везде жулик. Но ссылка на Африку неслучайна. Во-первых, подчёркивается проникновение высоких технологий в самые отдалённые и технически отсталые уголки населённого мира. А во-вторых, как раз в период написания статьи из этой самой Африки по всему миру прокатилась волна вопиющего спама.

*) Спам. Казалось бы, spam — простая тушёнка. Но благодаря одному из номеров популярного среди древних программистов сатирического коллектива «Монти Питон» (Monty Python), так стали называть всякое ненужное барахло, рассылаемое по электронной почте вовсе того не желающим абонентам.

*) Хаб — сетевой узел, в котором встречаются провода, по которым передаётся информация.

*) В случае с поленом речь идёт не о Буратино, а о волокне древесины; по-английски grain of the wood. Подобный термин (шуточный, но точный) в русском языке, насколько мне известно, не устоялся. Речь идёт о том, что перебор элементов массива в том порядке, в котором они физически лежат в памяти, бывает значительно эффективнее (т.е. быстрее). Похожим образом, колоть дрова проще, когда лезвие топора ложится вдоль волокон, а не поперёк.

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

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

*) К&Р — так программисты нежно называют классическую книжку Кернигана и Ричи, «Язык программирования C». Джоель использует этот термин и в более широком смысле - как стиль программирования.
Изображение

dyvniy M
Автор темы, Администратор
Администратор
Аватара
dyvniy M
Автор темы, Администратор
Администратор
Возраст: 41
Репутация: 1
Лояльность: 1
Сообщения: 3579
Зарегистрирован: Ср, 10 октября 2012
С нами: 11 лет 5 месяцев
Профессия: Программист
Откуда: Россия, Москва
ICQ Сайт Skype ВКонтакте

#45 dyvniy » Пт, 7 октября 2016, 08:16:34

Как развиться в выдающегося специалиста
https://tproger.ru/articles/google-guide-to-programming/
Спойлер
Как стать хорошим программистом: статья от Google

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

Если вы только собираетесь делать свои первые шаги в программирование и не знаете, с чего начать, то пройдите курс по направлению «Computer Science». Там вас научат азам программирования, так что после их прохождения вы будете относительно неплохо знать какой-либо язык программирования и писать качественный код. Такие курсы можно найти здесь и здесь. Также смотрите наш список из 10 лучших книг для начинающих разработчиков.
Объектно-ориентированное программирование сейчас является стандартом в промышленном программировании, поэтому выучите по крайней мере один объектно-ориентированный язык программирования, и хорошая зарплата вам гарантирована. Примерами таких языков являются C++, Java, Python. Курсы для новичков можно найти здесь, здесь и здесь, а для продолжающих обучение здесь и здесь. Несколько полезных сборников ссылок и книг для изучения Java, Python, С++.
Расширяйте свой программистский кругозор, не стоит ограничиваться одним ООП, осваивайте другие парадигмы, учите другие языки, пробуйте себя в разных сферах. Например, если вы хотите разрабатывать веб-приложения, то однозначно стоит обратить внимание на такие языки, как CSS + HTML, JavaScript, PHP, Ruby. Хотите экзотики? Посвятите немного времени Haskell, Clojure, Prolog. Курсы для закрепления своих знаний и получения новых можно найти здесь и здесь. Отдельно советуем обратить внимание на ресурс Codecademy. Обратите внимание на нашу подборку 10 бесплатных книг по JavaScript для начинающих.
Множество ошибок в коде не нравится никому: ни вашему тимлиду, ни тестировщикам, ни заказчику, ни конечным пользователям. Поэтому тестируйте свой код. Курсы по этой теме здесь и здесь. Смотрите также: зачем нужны юнит-тесты?
Разработайте в себе логическое мышление, выучите дискретную математику: если вы хотите делать в своей жизни что-то более интересное, чем до конца дней писать сайты, то без этого вам не обойтись. Курсы: от MIT, по логике, линейной и дискретной оптимизации, графических моделях, теории игр. Если вы все еще сомневаетесь, нужна ли программисту математика в работе, то прочитайте мнения экспертов по этому поводу.
Невозможно представить себе хорошего программиста без хорошего знания Computer Science, которая стоит за ними, поэтому учите алгоритмы и структуры данных, а также всю ту теорию, которая стоит за ними. Курсы: здесь, здесь и здесь. Также советуем почитать книгу по дизайну алгоритмов. Курс от tproger по базовым алгоритмам и структурам данных, а также подборка материалов для изучения сложных тем.
Любая программа взаимодействует с ОС, поэтому выработайте понимание того, как устроены операционные системы, хотя бы на базовом уровне. Отличный курс по теме на YouTube.
Выучите UX-дизайн, если хотите, чтобы вашим приложением было удобно пользоваться, а значит, чтобы его покупали. Курс от Udacity.
Человечество с давних пор мечтает об искусственном интеллекте, и сегодня эта мечта близка как никогда. Если вы хотите поучаствовать в ее осуществлении, то станьте специалистом в области машинного обучения — молодой, но активно развивающейся науке. Курсы по робототехнике, обработке естественных языков и машинному обучению. Также обратите внимание на топ-10 алгоритмов интеллектуального анализа данных.
Многие программисты пишут код и даже не задумываются, как он преобразуется в понятные компьютеру инструкции. Если вам это интересно, то изучите то, как работают компиляторы. Сделать это можно в этом курсе на Coursera.
В современном мире с многоядерными процессами никуда без параллельного программирования, поэтому обязательно научитесь работать с потоками в языках программирования. Курс по теме. Подборка книг о компиляторах.
Практика жизненно важна для всех, кто хочет быть программистом, поэтому в свободное время работайте над своим проектом: например, создайте или поддерживайте веб-сайт или соберите робота.
Участвуйте в open source-проектах, это поможет вам набить навыки работы с чужим кодом, да и в конце концов вы просто будете приносить пользу человечеству. Идеальным местом для open source-деятельности является GitHub.
Работайте над проектами вместе с другими программистами. Это поможет вам научиться работать в команде, что является неотъемлемым навыком в современном мире, а еще вы сможете научиться от них чему-то новому.
Участвуйте в соревнованиях по программированию и решайте алгоритмические задачи, ведь это помогает держать ваш мозг в форме, углубляет понимание алгоритмов и структур данных, да и вообще это неплохой способ провести время. Делать это можно на таких сайтах как Codeforces и TopCoder. Смотрите также нашу подборку сайтов с задачами и соревнованиями по программированию, а также 80 популярных задач с собеседований.
Найдите себе ученика в области, в которой вы неплохо разбираетесь. Как ни странно, но обучение кого-то какому-либо предмету помогает самому углубить знания в этом предмете, а еще неплохо развивает навыки коммуникации.
Вот и все. Если вы выполнили все эти указания, теперь вы желанный кадр для любой IT-компании в мире
Изображение

dyvniy M
Автор темы, Администратор
Администратор
Аватара
dyvniy M
Автор темы, Администратор
Администратор
Возраст: 41
Репутация: 1
Лояльность: 1
Сообщения: 3579
Зарегистрирован: Ср, 10 октября 2012
С нами: 11 лет 5 месяцев
Профессия: Программист
Откуда: Россия, Москва
ICQ Сайт Skype ВКонтакте

#46 dyvniy » Чт, 16 февраля 2017, 17:04:45

Говнокод или суперархитектура?
Эволюционный рефракторинг!
https://habrahabr.ru/post/172037/
Спойлер
8 марта 2013 в 20:42
Говнокод или суперархитектура? Сначала говнокод, а потом эволюционный рефакторинг!
Разработка веб-сайтов*, Программирование*
Ответ на статью.

Если вы не разрабатываете ПО для машин или систем автоматического поддержания жизни и тд — нижесказанное работает для вас при грамотном применении.

Сразу скажу — не моя идея, в статье «Проектирования больше нет?» сам Мартин Фаулер писал об эволюционном рефакторинге. А Боб Мартин даже целую книгу запилил с примером поэтапного развития приложения (и не одним), назвав «Быстрая разработка ПО» и продемонстрировав умение виртуозно материться на Java и C++.

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

Два — зарплата не берется из воздуха, и от идеи до хоть как-то взлетевшего стартапа лежит некий период поиска удачных вариантов функционала и монетизации. Прежде всего — функционала. И чем быстрее стартап может изменяться, тем с большей вероятностью он разовьется до стадии самодостаточности, обойдет конкурентов и пойдут деньги, из которых можно будет платить разработчикам премии. Как писал пророчески Билл Гейтс в 1997, 2000е будут десятилетием скорости. Кстати, на Хабре было исследование, согласно которому большая часть успешных стартапов так или иначе имели в своем развитии говнокод.

Несколько конкретных примеров.

Мы делаем трехуровневое меню хардкодом (версткой и массивами в годобжекте, magic numbers и другие антипаттерны), и у нас это копируют конкуренты, проектируя дерево в базе и делая кучу классов. Мы следим за кликами пользователей и видим, что люди теряются. Упрощаем меню, меняем код за один день (он простой, и выбросить не жалко хардкод, так как знали, что перепишем). У конкурентов начинается срач между ведущими, которым жалко менять спроектированное меню и две недели крутого правильного программирования, плюс у них замылен глаз. В итоге мы получили две недели времени.

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

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

Через два месяца конкуренты умерли, а мы переписали проект (часть я переделал на плюсах, когда трафик вырос), так как уже знали все сущности, бизнес-процессы и user stories, покрыли тестами, наладили CI. Еще заплатили премию нашим дорогим программистам из денег, которые мы заработали за счет прорыва на рынке, и отправили наших разработчиков бесплатно на две недели в Тайланд.

Совпадения с реальными событиями случайны, если что ;-)

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

Большая же часть рефакторит не то, нет так, как надо, и не тогда, когда надо. В php примером является ранний мегасвязанный zend, когда ООП ради ООП, и на простые операции 100500 вызовов функций плюс сверхвысокая связанность. Неплохим являются слабо связанные компоненты symfony2, но и там есть некий overengineering.

Сегодня я даю своим программистам время на рефакторинг, так как сам вырос в менеджера проектов из ведущего программиста (в прошлом прикладное ПО, затем web development).
Потому что помню о техническом долге и стремлюсь его уменьшать.

Завершу словами песни из 17 мгновений весны: «а в общем, нужно просто помнить долг от первого мгновения до последнего».

Желаю всем времени на рефакторинг и нужных скиллов!
Разработка, здравый смысл
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама
ХАБЫ
Разработка веб-сайтов
4k авторов, 9,3k публикаций
Машинное обучение
232 автора, 486 публикаций
PHP
1,4k авторов, 2,4k публикаций
Разработка под e-commerce
113 авторов, 331 публикация
Математика
526 авторов, 1k публикаций
Data Mining
317 авторов, 680 публикаций
Программирование
2,7k авторов, 6k публикаций
Google API
111 авторов, 137 публикаций
Node.JS
401 автор, 721 публикация
IT-стандарты
261 автор, 493 публикации
Все хабы
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама
+112
68,9k
322


@Cord карма
409,5
рейтинг0,0 Написать
Team Lead
ПОХОЖИЕ ПУБЛИКАЦИИ
16 апреля 2015 в 13:34 Dagaz: Пинки здравому смыслу (часть 5)
+22
13,8k
67
7
24 марта 2015 в 16:34 Dagaz: Пинки здравому смыслу (часть 4)
+17
8,6k
31
4
3 июня 2014 в 16:17 О здравом смысле и руководстве компаний
+100
42,8k
170
109
САМОЕ ЧИТАЕМОЕ
Разработка
Сейчас
Сутки
Неделя
Месяц
Как «пробить» человека в Интернет: используем операторы Google и логику
+79
61,7k
831
55
Секрет быстрого программирования: не задумывайтесь
+12
7,7k
80
18
Mozilla Firefox. Проблемы адаптивной вёрстки (баг, который чуть не рассорил компанию)
+13
4k
17
8
Комментарии: Райффайзен, Альфа-Банк и ВТБ24
+12
3,8k
13
8
Почему вам может пригодиться собственный Twitter-бот и как создать его за полчаса
+8
1k
22
0
Комментарии (170) отслеживать новые: в почте в трекере

misterio 8 марта 2013 в 21:27 +3
Прям узнается множество проектов
ответить
Athari 8 марта 2013 в 23:28 +22
Да ничего не узнаётся. Не знаю, откуда авторы берут рассказы про проекты, в которых код либо изначально правильный, либо становится таким эволюционно. Не бывает таких.



Перевод на русский
ответить
misterio 8 марта 2013 в 23:30 +1
Ну рефакторинг это тоже момент эволюции :)
ответить
mayorovp 9 марта 2013 в 09:08 –11
Низ схемы надо переделать — у блока не может быть несколько входов.
ответить
wrmax 9 марта 2013 в 13:54 (комментарий был изменён) +2
Не знаю, откуда авторы берут рассказы про проекты, в которых код либо изначально правильный, либо становится таким эволюционно. Не бывает таких.

Софт для космических аппаратов и систем жизнеобеспечения, по идее должен быть написан идеально.
ответить
Athari 9 марта 2013 в 14:08 +2
Если по-честному, то между «Are you done yet?» и «Good code» надо протянуть стрелку «Да, и опоздали на пять лет и вложили в десять раз больше ресурсов». :) Проблема в том, что, во-первых, бизнес в большинстве своём не может себе позволить такую задержку, и, во-вторых, не хочет тратить столько ресурсов на получение идеального кода. Обычно это экономически нецелесообразно. Космос и жизнеобеспечение — здесь исключение, потому что первый, второй и третий приоритеты занимают надёжность, надёжность и надёжность.
ответить
Siddthartha 9 марта 2013 в 17:29 (комментарий был изменён) +1
так это нормальный, опытный подход к разработке. быстрое прототипирование (говнокод) и последовательное улучшение с рефакторингом почаще.
«все сразу по правильному» — делается только при избытке бабла, и то не всегда оправдывается.
действительно узнается, классический пример фейсбук — чтобы идея заработала достаточно было говнокода в первой версии.
ответить
Informatik 8 марта 2013 в 21:46 +23
Здраво. Но как не зря говорится — нет ничего более постоянного, чем временное. В реальной жизни на рефакторинг времени может просто не остаться, а потом все это превратится в снежный ком. По возможности лучше учиться сразу делать хорошо. И потом все относительно, может быть ваш говнокод для кого-то суперархитектура и наоборот.
ответить
s0rr0w 8 марта 2013 в 23:21 +6
На рефакторинг как раз время не остается, если всегда пытаться делать хорошо. Такой вот странный парадокс. Пример с меню из статьи очень хорошо показывает, что иногда нет смысла что-то делать на отличненько, пока не станет понятно, что это действительно нужно. А то получится, что сделали не просто хорошо, а великолепно, но это нафиг никому не нужно.

Другими словами, идеальный код, как бы грустно это не звучало, противоречит требованиям бизнеса. Бизнес продает решение, а не качество кода. Качество помогает в высококонкурентной среде, и стремиться к нему нужно, но никогда не перегибать палку.
ответить
lany 9 марта 2013 в 11:59 +3
Между идеальным кодом и говнокодом есть множество промежуточных звеньев. Хороший программист умеет набросать хороший (но не идеальный) код для проверки идеи быстрее, чем он бы или плохой программист писали говнокод. Когда, к примеру, выделение метода занимает у человека полминуты, этот подход становится предпочтительнее копипасты, даже если код всего дважды повторяется.
ответить
VolCh 9 марта 2013 в 15:07 0
Пускай даже не быстрее, а столько же по времени или на несколько процентов дольше.
ответить
tbicr 8 марта 2013 в 21:58 –2
Вася и Петя одновременно начали писать один и тот же продукт...
ответить
Informatik 8 марта 2013 в 22:35 +6
Два типа мышления. Вася — продавец, он думает про то, как срубить бабла и, следовательно, про маркетинг, себестоимость и т.д. Петя — художник, он может очень хорошо выполнять свою работу и написать совершенный код.

Каждый должен заниматься своим делом. Продавец должен заниматься продажами, программист должен писать код и с продавцом выстраивать отношения, чтобы его код продавали. В принципе если человек хорошо пишет код, то его с руками оторвут, и будут вкладывать деньги в развитие в некоторых компаниях.
ответить
iCoderXXI 3 апреля 2013 в 16:24 +1
Невозможно написать хороший код ранее, чем понятна бизнес-логика. А бизнес-логика, в новых нишах, зачастую, дело совершенно туманное, пока в жизни не протестируешь кучу вариантов.

Поэтому на стадии тестирования надо писать быстро, лишь бы работало. Если идея себя оправдает, то уже переписать как надо. Если не оправдает — в топку.

Все правильно написано в статье.

Есть и третий путь. Когда наметилось русло, в котором тестируются одноформатные или очень схожие идеи, то есть смысл автоматизировать процесс тестирования. Я вот ровно этим занимаюсь последние пол-года.
ответить
spiritedflow 8 марта 2013 в 23:03 (комментарий был изменён) +31
Такую фигню можно сколько угодно генерировать:

Вася и Петя одновременно начали писать один и тот же продукт.

Вася был «ориентирован на результат» и начал сразу писать говнокод не продумав толком архитектуру. А Петя начал решение задачи с описания продукта со стороны пользователя, потом сделал тесты, и только потом начать писать. Писал не больше и не меньше, а ровно столько, чтобы все тесты прошлись.

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

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

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

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

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

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

Нет, Вася не винит себя, он винит судьбу. Ну почему ему не попался тот «Петя», который перфекционист и идеалист, с которого все ржут? Почему ему попался практичный Петя, который с умом и в меру использовал известные практики, тем самым оставив говнокод Васи далеко позади?
ответить
dkukushkin 9 марта 2013 в 01:39 +7
Ваш вариант кажется более правдоподобным :)
ответить
arvitaly 9 марта 2013 в 05:44 +4
Такую фигню можно сколько угодно генерировать в любую сторону.
ответить
VolCh 9 марта 2013 в 06:06 +13
Включая варианты «Вася на все забил и пил пиво на диване, а Петя продал квартиру, но стартап не стрельнул» :)
ответить
tbicr 9 марта 2013 в 12:09 +1
Если ничего не делать вероятность того что не стрельнит 100%. Вообще я бы подходил к данному вопросу с точки зрения вероятности, вместо всяких «если, то, но», тк риски есть везде. Изначально для меня суть была в том, что завтра может быть уже поздно, и чем раньше прийдешь от идеи к реализации тем меньше времени уйдет на осознание того что проект не стрельнит или обгонишь конкурентов и начнешь снимать сливки. Вообщем обыгрывается ситуация что из «хорошо», «быстро», «дешево» можно выбрать только два пункта с учетом того что нужно дешево, а время критично.
ответить
yuretsz 11 марта 2013 в 00:26 0
Ну так Вася остался при своих, с диваном и пивом, а Петя без квартиры бутылки по помойкам собирает. Такие придуманные истории бесмысленны по сути.
ответить
VolCh 11 марта 2013 в 00:54 +1
Допустим, что нужно быстро (хотя не факт, это в искусственных сравнениях одна идея конкурентам одновременно приходит и оба решают её реализовывать), но вот нужно ли отказываться от «хорошо» ради «дешево» вопрос открытый. Если будет плохо и дешево, то вы запуститесь раньше, но вот время реакции на фидбэк будет уже не быстрое. И если миллионы с первого дня старта не предполагаются, чтобы на второй день посадить команду дорогих профи, то кто-то увидев вашу плохую реализацию идеи может сделать хорошую, быстро и дорого и быстро имеющуюся у вас фору пройдет и вас обойдет.
ответить
spiritedflow 8 марта 2013 в 22:09 (комментарий был изменён) +6
Надо же! Одна статья говорит что тесты обязательны. Другая статья говорит что тесты обязательны. И при этом вторая — это ответ на первую.

PS: TDD в этой статье под словом «рефакторинг», потому что рефакторинг по Фаулеру, это всегда тесты, тесты, тесты и только потом действия.
ответить
Cord 9 марта 2013 в 00:16 0
Про тесты. Я считаю, критические места должны быть покрыты тестами (отправка заказа, логи платежей и тд), а на каждый чих тест на первом этапе не нужен — YAGNI. Но не всегда это возможно.
ответить
bendingunit22 9 марта 2013 в 12:08 +1
Если говорить в контексте TDD, тесты покрываются кодом, а не код — тестами.
ответить
u_story 8 марта 2013 в 22:11 +8
У меня почему другие мысли в голове.

Нужно добавить новую фичу.
— вариант А: мы ищем куда бы её запихнуть в коде. Добавляем. Отваливается функционал в другом месте. Тратим время на поиски проблемы и её устранение. Тесты не пишутся потому, что невозможно понять, как и что тут можно протестировать автоматически.
— вариант В: поиск места куда вставить функционал занимает у нас 30 секунд. Добавляем функционал, покрываем тестами, всё отлично работает.

и т.д.
ответить
qw1 8 марта 2013 в 22:14 +2
В сюжете статьи оказывается, что дерево категорий выкидываем, берём облако тегов.
Куча тестов поломалась бы (поскольку меняется интерфейс глобально) и их починка выльется в ощутимые трудозатраты.
ответить
spiritedflow 8 марта 2013 в 22:29 (комментарий был изменён) +4
Если выкидываете модуль, то просто выкидываете и тесты для него. Интеграционные и функциональные надо будет править, да, как и весь нормальный код, который использовал категории.

А что про статью, то:
Сразу скажу — не моя идея, в статье «Проектирования больше нет?» сам Мартин Фаулер писал об эволюционном рефакторинге.

идём по ссылке, а там:
У практик, с помощью которых осуществляется сглаживание, есть множество составляющих. В основе всех их лежит Тестирование и Непрерывная интеграция.

ответить
SiPlus 8 марта 2013 в 22:26 (комментарий был изменён) +2
Сначала надо сделать полностью функциональный прототип, в котором допускать антишаблоны и код а-ля индус, а затем переписать чисто и структурированно.

Добавлять новую функциональность надо сначала в отдельной ветке, и после этого переписать так, чтобы вписывалось в основной код.
ответить
PQR 8 марта 2013 в 22:44 0
Затем мы делаем сводный отчет за час руками в php
Я тоже раньше так делал, а потом открыл для себя сводные таблицы в Excel! На удивление «GROUP BY» в сводных таблицах в Excel во многих случаях работает даже быстрее, чем в MySQL.
ответить
qw1 8 марта 2013 в 22:53 0
Что делать, если результат надо отдать конечному пользователю на web-странице?
ответить
gandjustas 8 марта 2013 в 23:08 –2
Ты не поверишь, но есть прекрасные средства, которые это реализуют. Excel Services в SharePoint например.
ответить
qw1 8 марта 2013 в 23:15 –2
Речь была о PHP.
Но допустим, платформу мы вправе выбирать.
Ставим заказчику Sharepoint и заставляем купить?
ответить
gandjustas 9 марта 2013 в 00:25 0
Ставим заказчику office365 за 500 рублей в месяц. Это примерно один день работы программиста. Что даже за несколько лет выгоднее чем поддерживать код.
ответить
qw1 9 марта 2013 в 02:38 0
Всё там не так просто…
A WCF endpoint is required

По-любому, поддержка программиста будет нужна. И более квалифицированная, чем потребует наговнокоженный php-генератор, сосущий данные из MySQL
ответить
gandjustas 9 марта 2013 в 02:46 0
Есть rest интерфейс для вытягивания диаграмм и данных. Поддержка программиста нужна чтобы урл написать один раз.
ответить
qw1 9 марта 2013 в 02:48 0
Я не про вывод результата, а про ввод данных в генератор отчёта
ответить
qw1 9 марта 2013 в 02:43 0
И второй вопрос: 500 руб — это на аккаунт?
Т.е. заказчик должен авторизоваться как в нашем приложении, так на Office365, а если такой отчёт нужен как страница для клиентов, их тоже в этот аккаунт офиса пускать?
ответить
gandjustas 9 марта 2013 в 02:50 –2
Нет, приложение на PHP получает данные из excel на SharePoint. Для этого лицензии не нужны. Дальше они как есть передаются во view. Диаграммы из excel можно прямо картинкой забирать. Если нужно отфильтровать по клиенту, то можно это сделать на стороне приложения.
ответить
qw1 9 марта 2013 в 02:58 +9
Кажется, при такой архитектуре Office365 тут как собаке пятая нога (ну или похоже на попытку впарить сервисы микрософт).

Получается, надо писать
1. wcf-endpoint, выкачивающий данные из SQL (который тоже надо поддерживать, т.к. все варианты join-ов сразу не предусмотришь, а join-нить в excel через xLOOKUP медленно) — обязательно на Windows Server + IIS, никто больше WCF не захостит
2. excel-файл в облаке MS, подключенный к источнику данных и содержащий сводную таблицу, который надо поддерживать при изменения отчёта
3. оплачивать аккаунт Office365 и следить на его конфигурацией (URL-ы подключений)
4. иметь веб часть на PHP (теперь уж поставили IIS в шаге 1, можно и ASP), которая из облака по REST вытянет данные из excel и представит в html-виде

и всё это вместо простейшего php/asp-скрипта, который по ADO подключится к базе, сделает SQL-запрос и выплюнет результат в HTML-таблицу
ответить
gandjustas 9 марта 2013 в 20:44 0
ОМГ зачем это все? Excel умеет втягивать данные из любого ODBC-совместимого источника. Никаких WCF, IIS не нужно.
Одним GET запросом можно забрать данные из Excel на стороне PHP, еще два запроса нужны для авторизации.

Недостаток — обновлять данные надо ручками (макросом, скриптом на VBS), o365 не умеет сам обновлять внешние данные в excel, только в on-premise варианте.

Это все имеет смысл если расчеты сложнее одной функции агрегации, типа sum или avg. Я знаю проекты, которые на таком ad-hoc решении прожили довольно долго.
ответить
qw1 9 марта 2013 в 21:41 0
Речь о десктопном excel или web-excel в office365?
ответить
gandjustas 10 марта 2013 в 03:52 0
Создать таблицы в десктопном excel, положить на портал, тянуть данные через веб.
ответить
qw1 10 марта 2013 в 13:07 (комментарий был изменён) 0
Допустим, обновление документа на сервере из ODBC-источника возможно (Хотя сомневаюсь — обычный сценарий работы с ШП — юзер открывает документ в обычном excel и обновляет из ODBC-источников, которые настроены у него в системе локально, используя свои логины-пароли подключений к БД, затем сохраняет документ обратно)

Но безопасно ли открывать свою БД наружу в интернет?
ответить
gandjustas 10 марта 2013 в 14:10 0
Ограничение прав пользователя в базе + Надежный пароль + SSL (если БД поддерживает), почему нет?

При использовании excel services как раз не надо давать пользователям сам документ, только данные \диаграммы из него. В onpremise можно настроить обновление на сервере, без открытия самого документа.
ответить
qw1 10 марта 2013 в 15:05 0
1. есть риски, что базу тупо задосят (http-серверы давно на публике и более-менее умеют противостоять, в отличие от sql)

2. on-premise это другой ценовой сегмент. аргумент «500 руб в месяц» не прокатывает
ответить
vsespb 9 марта 2013 в 02:56 +3
Пару раз так сделаем и всё оставшееся время будем решать проблемы деплоя и интеграции.
ответить
tushev 8 марта 2013 в 23:21 0
А мой заказчик раньше делал отчеты в сводных таблицах Эксель, а потом попросил меня написать аналог на PHP. В Экселе ему приходилось делать слишком много лишних движений, а он хотел чтобы все было по одному клику.
ответить
easyman 9 марта 2013 в 00:21 0
Как вам не стыдно. Надо было показать ему, как записывается макрос в Excel.
ответить
tushev 9 марта 2013 в 00:42 0
Тогда уточню. Раньше они делали отчеты врнучную для своих клиентов. А сейчас они хотят чтобы клиенты сами могли заказывать отчеты через веб интерфейс в режиме онлайн. Система написана на PHP.

А генерация сводных отчетов на PHP из базы данных — на самом деле достаточно простая (не дорогая) задача. Делаем выборку из БД, крутим циклы, добавляем значения в матрицу. Потом пересчитываем ячейки этой матрицы.

Но про макросы в Эксель, это вы правильно подметили. В некоторых ситуациях это замечательно.
ответить
gandjustas 8 марта 2013 в 22:44 +4
В статье «стартап-ловушка» говорится о том что нужно «Do right things» даже в стартапе. Двигаясь в неверном направлении невозможно достигнуть успеха. Невозможно получить качественный продукт, постоянно экономя на качестве. Правда фокус чересчур программерский.

В этой статье написано о том как «Do things right». О том что эволюция прототипов эффективнее, чем Big Design Upfront. О том что частые релизы, важнее вылизывания.

Эти вещи не противоречат друг другу.
ответить
Cord 8 марта 2013 в 22:56 (комментарий был изменён) 0
В комментах пошла тема, вот гады, не дают написать нормально.
В этой статье я хотел показать пример, почему иногда нужно писать сначала криво. А также добавил, что думать о себе как об архитекторе, и реально переписать уметь нужное вовремя и хорошо — разные вещи.

Как пример, нам достался проект считалки хайлоад. Разработчики там хранили уникальные айди юзеров как комбинацию куки и еще других вещей хз где, а потом для повышения производительности «отрефакторили», что записываться айди стал в мемкешд. А че, типа быстро работает. То, что такое ACID и что мемкешд стирает ключи в процессе работы — ну не бд это, как, видимо, думали — это не про наших парней.

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

И таких примеров море. Эффект Даннига-Крюгера в действии
ответить
gandjustas 8 марта 2013 в 23:07 +3
Писать надо не криво, а минимально реализуя функционал. То есть KISS. Это и есть основополагающий принцип для «Do things right».

Про считалку — отказ от durable хранилища противоречит «Do right things».

Причем тут эффект Даннига-Крюгера не понял.
ответить
Cord 8 марта 2013 в 23:28 +2
Согласен.

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

Эффект при том, что люди считали себя умнее, чем на самом деле, и уверенность в своем уме и уровне ослепляет, что ведет к ошибкам
ответить
wartur 9 марта 2013 в 11:30 –10
Золотые слова!

ответить
ncix 9 марта 2013 в 22:11 (комментарий был изменён) 0
Невозможно получить качественный продукт, постоянно экономя на качестве
Пока вы делаете качественный 3 года, конкуренты сделали «средненько» за год. Да много недовольных, но паровоз уже поехал. Через 3 года вы закончите первую итерацию, а ваш конкурент, делавший «ширпотреб» прошел уже 3 итерации, и бабок нарубил и клиента лучше понимает.

Вот если вы выходите на более-менее стабильный рынок со стратегией «порвать конкурентов качеством» тогда да. Только так.
ответить
gandjustas 10 марта 2013 в 03:52 0
Начнем сначала, чтобы были «on the same page». Есть стратегия обеспечения качества, описанная во множестве методологий. Например для кода: проведение ревью, тестирование, устранение ошибок перед разработкой нового функционала. Для интерфейса: проработка сценариев использования, usability тестирование. И так далее.

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

При этом никто не договорит что нужно добавиться максимального качества, это скорее вредно, чем полезно. Но вот минимальный уровень качества обеспечить необходимо, и для этого есть довольно мало способов и нету никаких обходных путей.
ответить
printf 8 марта 2013 в 22:45 +6
Очень важно вовремя остановиться, иначе получится говнокод ради говнокода. Взять и переписать — звучит хорошо, но на практике иногда приводит к спонтанной гибели проекта, по разным причинам.

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

Все хорошо в меру, и говнокод, и рефакторинг.
ответить
qw1 8 марта 2013 в 22:58 +3
Автор не указал главного: если система написана модульно (на примере XAML — каждый блок интерфейса вынесен в user-control, имеет понятный интерфейс и простой код для связи этих блоков), то легко экспериментировать, перетасовывая блоки и подкручивая их параметры.

Если всё написано одним большим блоком говнокода, чтобы перенести поле ввода на 30 пикселей выше и ничего не поломать, надо час времени.
Это будет сильно сдерживать эволюцию проекта, программеры будут сопротивляться внесению изменений.
ответить
Cord 8 марта 2013 в 23:06 –1
Да, модульность крутая тема. Но иногда бывает, не знаешь, какие модули завтра будешь делить, какие объединять. Поэтому декомпозицию ИМХО стоит делать после пары итерации уже, когда ясно, что сделали нужное. А то начали соцсеть, пришли к инет-магазину, потому что остальное юзерам, кроме товаров, бывших одним из 10 разделов, нафиг не уперлось.
ответить
ilblackdragon 9 марта 2013 в 11:27 +4
Как раз этот пример скорее в пользу модульности изначально — делали соц. сеть, при этом каждый кусок функционала был реализован в отдельном модуле: пользователи+авторизация отедльно, социальность отдельно, магазин отдельно, еще 9 разделов в 9 отдельных модулях.

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

А если все изначально в одном месиве написать — где нельзя разобрать где начинается магазин и заканчивает лента друзей — то тогда потребуется итерация только на то что бы вытащить функционал инет-магазина.

А завтра окажется, что магазин стал популярным, и пользователи назад хотят ленту — так как хотят видеть что их друзья купили — и оп, надо поднимать старый код и вытаскивать куски социальности. Вместо того что бы просто врубить модуль социальности обратно — подкрутить то что может отсатло (если API других модулей поменялись) и вкрутить обратно темплейты.
ответить
tushev 8 марта 2013 в 23:07 +4
Руководитель проекта должнен хорошо чувствовать границу в эволюции проекта, до которой говонокод разрешен, и после которой говнокод запрещен.

Иначе получется ситуация: «Пока можно говнокодить… все еще можно… еще немного поговнокодим… Ааааа… Покатился снежный ком говнокода и похоронил проект.»
ответить
НЛО прилетело и опубликовало эту надпись здесь
Cord 8 марта 2013 в 23:21 +1
Роберт опытен и многое предвидит.

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

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

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

А лучший способ влезть в шкуру клиента и понять его задачи — дать ему пластелин, чтобы он сваял макет. А потом вы ему из золота (чуть не написал «гранита») отольете его протип.

Но тратить золото (время программистов и других специалистов) на задачи, которые решает пластилиновый протип, имхо неверно.
ответить
wartur 9 марта 2013 в 11:36 0
Но тратить золото (время программистов и других специалистов) на задачи, которые решает пластилиновый протип, имхо неверно.

Я еще скажу, если разработчики заведомо видят, что задача обречена на провал, то у них самих возникает обида за вероятно потраченное в пустую время и соответственно понижается мотивация.
ответить
VolCh 9 марта 2013 в 15:10 +1
У меня в таких ситуациях возникает желание как раз писать «идеальный» код. Хоть к резюме можно будет приложить :)
ответить
wartur 9 марта 2013 в 20:05 0
Кстати да =) Можно.
ответить
Cord 8 марта 2013 в 23:30 0
Так что на сотой итерации должен быть крутой код

Если его нет, вопрос qa
ответить
gandjustas 8 марта 2013 в 23:32 0
Количество костылей растет когда с самого начала есть попытки создать «идеальную архитектуру». Простой и прямолинейный код легко менять, легко перемещать и легко развивать. Как только появляются паттерны резко код перестает быть простым и любое изменение, не укладывающееся в «идеальную» архитектуру, производит костыль. Потом применяется «паттерн» чтобы исправить костыль, но со временем это порождает еще больше костылей.
ответить
tushev 8 марта 2013 в 23:17 +2
мегасвязанный zend, когда ООП ради ООП, и на простые операции 100500 вызовов функций плюс сверхвысокая связанность
Автор покусился на священную корову Zend Frameword, критиковать которую, во многих кругах считается опастной ересью. Но я с автором полностью согласен.
ответить
Cord 8 марта 2013 в 23:25 0
Говорят, он стал лучше.

Но чем прет Симфони — бери и юзай отдельные куски. Философия Юникс в действии. SOLID, low coupling, high cohesion — все давно известно.

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

Хотя фреймворк, если на нем все писать, достойный
ответить
vip_delete 8 марта 2013 в 23:30 –2
Те, кто постоянно говнокодят, не смогут сделать эволюционный рефакторинг в суперархитектуру. А те, кто смогут, никогда не говнокодят и пишут сразу нормальный код, и он работает даже без тестов.
ответить
qw1 8 марта 2013 в 23:34 0
Значит, надо на говнокоде понять, какие требования к проекту и нанять других программистов, которые по этим требованиям напишут красивый код
ответить
remal 9 марта 2013 в 02:22 +3
А тех, кто понимает что проще здесь и сейчас вот в этом месте написать говнокод лишь бы работало, т.к. того требует бизнес, не существует, по вашему?

Мне, почему-то, всегда казалось, что просто кодить, пусть и качественно, не поднимая головы и не интересуясь о чем думают коллеги, ПМ, QA и даже заказчик, — это крайне безответственно.
ответить
VolCh 9 марта 2013 в 03:55 +1
По-моему, безответственно это, только если совмещаешь несколько или даже все роли. А если ты именно разработчик, то, ты не то что не должен, а просто не имеешь права принимать решения, сильно и неоднозначно влияющие на экономическую эффективность, в частности на баланс между сроками (и стоимостью) разработки и поддержки, в том числе писать «говнокод» или использовать «лучшие практики». Просто это не твоя зона ответственности, даже сли считаешь, что ты компетентен. Минимальные требования к качеству кода и максимальные к сроку должны быть тобой получены от того, кто несет ответственность за эффективность решения бизнес-задачи. Можешь сделать быстрее, не уменьшая качество — ради бога. Можешь сделать качественнее, не выходя за сроки — тоже хорошо. Но вот делать менее качественно или более долго не имеешь права. Максимум можешь выступить с предложением «давайте качество будет похуже, но сроки сократятся на порядок» или «давайте срок увеличим в 1,5 раза, но качество будет выше на порядок».

А вообще «говнокод» и «лишь бы работало» не синонимы. Вполне можно минимальными усилиями значительно поднять качество кода при его создании или по горячим следам, пока технический долг не начал обрастать процентами (говнокод заработал — потратил 5 минут на небольшой рефакторинг, хотя бы этот говнокод изолируя и создавая ему контракт/интерфейс, пускай неоптимальный, но явный), особенно с современными IDE, которые многую рутинную работу по созданию и изменению интерфейсов могут автоматизировать.
ответить
remal 10 марта 2013 в 02:22 0
Так я нигде и не писал, что разработчик должен принимать такие решения в одиночку. Не должен, разумеется. Но там, где «стандартный» разработчик потратит неделю, допустим, на реализацию change request'а, я потрачу денек потому что задумался каковы реальные цели заказчика и предложил измененную версию его запроса, которая будет удовлетворять его цели и, одновременно, будет стоить нам куда как меньше времени. Цифры, конечно, взяты с потолка.
ответить
VolCh 10 марта 2013 в 02:33 0
Имхо, сначала предложить, а уж потом день тратить. И в ожидании ответа на предложение работать либо над задачей сне меньшим приоритетом (если зависимости и общий дедлайн позволяют), либо над текущей в первоначальной формулировке. В общем чтобы у проекта в целом не было задержек, если новую формулировку задачи не примут.
ответить
zarincheg 8 марта 2013 в 23:35 0
Хорошая статья и обсуждение в комментах)
В текущем проекте после того как была «сформирована» архитектура, потом переформирована и снова и снова. Пришел к мысли о «проектировании через эксперимент». Когда важные архитектурные изменения, но не фундаментальные, вносятся в соответствии с реальными требованиями и поведением пользователей и системы под их воздействием.
ответить
zorgrhrd 8 марта 2013 в 23:37 +2
Я обычно пишу так: быстренько пишем рабочий код под задачу, и рефакторим по мере необходимости, но делать это я стараюсь заблаговременно, т.е. если вижу что в дальнейшем расширение функционала может споткнуться о текущую реализацию, при появлении времени делаю рефакторинг. Так же иногда быстро пишешь говнокод чтобы проверить идею, затем рефакторишь. Правда программирование для меня это больше хобби.
ответить
vip_delete 8 марта 2013 в 23:47 +3
Так всегда и бывает, у хорошего программиста всегда идет background refactoring.
ответить
Lol4t0 8 марта 2013 в 23:41 +5
Почему-то часто встречаю альтернативы — сделать «неправильно и быстро» или «правильно и долго». На практике же это часто выглядит как сделать «неправильно и долго» или «правильно и быстро».

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

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

Вообще я считаю, что говнокод может быть приемлем только там, где он может быть локализован. Если у вас ошибки в основополагающих вещах, то цена их исправления может оказаться слишком высокой.
ответить
Cord 8 марта 2013 в 23:56 +2
Вообще, это очень многогранная проблема. Мой опыт отличается от вашего, обычно либо «правильно и долго», либо «неправильно и долго». Поэтому для решения бизнес-задач и появилось чередование «быстро и неправильно» с «долго и правильно».

А аспекта два. Первый — это заблуждение людей, что они могут сделать правильно. Простой пример — на собеседовании спрашиваю, что такое инкапсуляция. Человек уверен в себе и читает определение. Теперь прошу пример из жизни — молчит. Вы рулите машиной, не видя деталей ее реализации, а имея только интерфейс. И человек смущается, понимания нет. И добиваю — ну окей, разобрались что это, а зачем оно? и вот ответ осмысленный, типа чтобы не порождать неявных зависимостей и кривой граф циклический, или чтобы состояние объекта кто угодно извне не менял (вечный спор геттеры и сеттеры против паблик), способны дать немногие

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

То есть имеют инструмент, но все за и против не взвешивают, что дает overengineeering, а потом нежелание менять слишком рано усложненный код.

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

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

И обратно, если вы уже нашли нужный функционал и попросили запилить стабильно, чтобы оно работало, а люди тестами не покрыли и оставили говнокод, это писец
ответить
Cord 9 марта 2013 в 00:01 +1
То есть я согласен, что нужно думать

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

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

Это трудно сразу принять, меня год учили этому хорошие учителя, спасибо им.
ответить
ToSHiC 9 марта 2013 в 00:05 +1
Мне кажется, вы про одно и то же пишете :) Что сначала надо подумать и максимально использовать известные факты, а когда появятся новые — подумать ещё раз.
ответить
Lol4t0 9 марта 2013 в 00:12 (комментарий был изменён) 0
Нужно правильно представлять себе задачу, которую решаешь. И писать код соответственно. Не нужно ни переоценивать ее, ни недооцнивать.

Даже в случае прототипа нужно написать достаточно хорший код, чтобы иметь возможность закончить его до коллапса архитектуры. Если вы не сможете зарелизить проект, то и обратную связь не получите, ведь так?
ответить
Cord 9 марта 2013 в 00:36 0
Работающий код — это самое первое требование, конечно
ответить
bachin 9 марта 2013 в 23:23 0
работающий код — понятие относительное, а не абсолютное.
если код работает в 3 случаях из 5 — все согласятся что это говнокод (но если все-таки иногда работает — значит еще не совсем треш)
если гипотетичести существует (но практически встречается раз в 100 лет) ситуация, когда код падает — это ведь тоже не идеальный код? но стоит ли всерьез рассматривать такую ситуацию?
где же проходит граница между «работающим» и «неработающим» кодом?
ответить
qw1 9 марта 2013 в 00:18 (комментарий был изменён) +1
Почему-то часто встречаю альтернативы — сделать «неправильно и быстро» или «правильно и долго». На практике же это часто выглядит как сделать «неправильно и долго» или «правильно и быстро».

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

Например, все модули должны стыковаться через Dependency Injection. Но кто-то заленился объявлять интерфейс, регистрировать его в контейнере и вызвал напрямую. В итоге получилось быстрее, но хуже тестируется.

Ещё пример: вместо того, чтобы разобраться с какой-то тонкостью ORM, пишем прямой SQL. Сиюминутно быстрее, в будущем сложнее рефыакторить

Другой пример. Принято использовать паттерн MVVM, но вот что-то не придумывается сходу, как через binding сделать. Надо гуглить, думать или читать исходники компонента. Вместо этого пишется небольшой костыль, выполняющий бизнес логику не в Presenter, а во View. Проблема решена, закоммитили, забыли. Затем этот Presenter подсунули другому View — костыль придётся копипастить.
ответить
Lol4t0 9 марта 2013 в 00:27 0
В итоге получилось быстрее, но хуже тестируется.
Вы же не забыли прибавить время отлова багов в условиях отсутствия теста ко времени разработки?

То же самое и во втором слуае. Подсовывающему сначала придется отойти от шока, «как так, у нас же MVVM, а бизнес логика в другом View не работает», разобраться в чем дело, скопировать и отладить костыль в новом окружении (это хорошо, если костыль подойдет).

И вот если все это посчитать, то может оказаться, что в итоге-то вышло дольше.
ответить
qw1 9 марта 2013 в 00:35 0
Большая вероятность, что непротестированный модуль править не будут. А второй View у этого Presenter-а не появится.
Особенно эта вероятность велика, если прототипу жить недолго до очередного большого изменения требований, которое вызовет серьёзное переписывание и выкидывание этого кода.
ответить
qw1 9 марта 2013 в 00:42 0
И вот если все это посчитать, то может оказаться, что в итоге-то вышло дольше.

Иногда дольше — это лучше.

Вариант 1: написали вообще без тестов, кое-как запустили, получили финансирование. говнокодим дальше.
Вариант 2: не уложились по срокам, проект закрыт.
ответить
Lol4t0 9 марта 2013 в 00:48 0
Все ваши примеры применимы, когда между событиями «начали писать» и «закончили писать» есть такой чекпоинт, как релиз, в результате которого все может поменяться.
ответить
qw1 9 марта 2013 в 01:13 0
Событие «закончили писать» как правило не наступает после первого релиза ))
ответить
VolCh 9 марта 2013 в 01:41 +1
говнокод может быть приемлем только там, где он может быть локализован


+100. Один из способов я предлагал в прошлом топике. Пускай не покрывать код тестами, но писать его имея тесты в ввидую Постоянно думать «как я это буду тестировать»…
ответить
funca 9 марта 2013 в 00:30 0
c2.com/cgi/wiki?MakeItWorkMakeItRightMakeItFast — хороший код получается с третьего раза :)
ответить
dkukushkin 9 марта 2013 в 02:13 0
У конкурентов начинается срач между ведущими, которым жалко менять спроектированное меню и две недели крутого правильного программирования, плюс у них замылен глаз. В итоге мы получили две недели времени.

А что было бы, если бы в этой конкретной ситуации трехуровневое меню оказалось правильным выбором?

Конкуренты экономят уйму времени, т.к. их меню обновлялется автоматически. А вы бы тратили драгоценное время своих программистов на «Вась, а ну добавь как еще один подпункт для сковородок...». И ведь признайтесь — раз оно работает, то лень было бы делать правильную архитектуру, вроде проще руками добавить пару пунктов…
ответить
dkukushkin 9 марта 2013 в 02:18 0
На мой взгляд, при минимальном планировании, такие вещи как меню изменяются не часто. Предварительно нужно продумать все «за» и «против», сделать прототип, оценить…

Так что в данной ситуации, похоже, конкуренты имеют преимущество.
ответить
s0rr0w 9 марта 2013 в 02:41 +2
Все зависит от области применения… Где-то стоит и потратить время на универсальное решение, а где-то это и вредно на начальном этапе развития, когда не понятно, что останется, а что отомрет.

С другой стороны, возьмем простую арифметику. Создать меню в HTML — пусть час работы. Добавить туда новый пункт — минут 10 (с учетом всех сопутствующих процедур, в виде проверки, добавления в репозиторий и прочего...). Написать универсальное меню — пусть 40 часов. На него ведь завязано очень много всего. Вопрос, сколько изменений можно вносить руками, чтобы это наконец стало затратным? Ответ: 234. Этого на всю жизнь данной версии сайта может хватить. Побеждает не тот, кто сделал правильно, а кто предоставил решение потребителям раньше всех.
ответить
qw1 9 марта 2013 в 02:45 0
Универсальное меню можно таскать из проекта в проект.
ответить
s0rr0w 9 марта 2013 в 02:56 0
Можно конечно же. А нужно?

Приведу несколько примеров из собственной жизни. В процессе разработки проекта применялось три подхода:
Тупняк в виде меню в HTML
Чуть менее тупо. Структура хранилась в файлике, выводилась универсальным темплейтом, в том числе с учетом прав
Универсальное меню, полное управление с UI


Так вот, самый сильный скачок в плане удобства внесения правок был в переходе от тупняка на уровень выше. А последующий шаг лично я уже оцениваю как излишнее усложнение. Использование менюшки происходило раз в квартал, это не тот уровень модификаций, который требовал бы реально универсального решения. Но душа и врожденный перфекционизм требовали «сделать красиво». В последующих проектах я вернулся ко второму варианту.
ответить
dkukushkin 9 марта 2013 в 11:16 (комментарий был изменён) +1
Вопрос, сколько изменений можно вносить руками, чтобы это наконец стало затратным? Ответ: 234

Два момента:

1. Это только кажется «10 минут». Вы отвлекаете программиста, выводите из контекста. Потом он пойдет пить кофе, т.к. не сможет сосредоточиться.

2. Хороший архитектор это не тот, кто делает сам каждый кирпичик. Вполне можно не клепать самим HTML-меню а купить готовое. Я однажды пришел к выводу, что делать контрол под проект — практически всегда плохая идея. Хорошее меню — уже отдельный проект на несколько месяцев работы.
ответить
s0rr0w 9 марта 2013 в 13:37 0
1. Я в эти 10 минут включил и смену потока. Скопировать одну строчку и поменять два значения в новой строчке не занимает более 1й минуты работы

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

ответить
dkukushkin 9 марта 2013 в 14:05 (комментарий был изменён) 0
1. Я в эти 10 минут включил и смену потока. Скопировать одну строчку и поменять два значения в новой строчке не занимает более 1й минуты работы

Для правильных языков (.Net, Java) вы сначала достаете из репозитория нужну ветку (1-2 мин.), открываете проект в студии (до 5 мин, если большой проект), находите эту страницу, исправляете (1-2 мин.), компилите, запускаете, проверяте что все работает (до 5 мин.), коммитите изменения в репозиторий (1-2 мин.), деплоите новую версию на сервер (если вы имеете права — 1-2 мин., при этом сайт будет не доступен.).

Итого, для сайта на .Net (на Java будет то же самое) — от 14 до 18 минут только изменение, без учета смены контекста.
ответить
s0rr0w 9 марта 2013 в 14:11 +4
<styob_mode>Зачем такие дорогие технологии используете? :) </styob_mode>
ответить
dkukushkin 9 марта 2013 в 14:21 (комментарий был изменён) –4
Зачем такие дорогие технологии используете? :)

Ну а почему одни люди носят обувь за $300-500, а другие дороже $20-50 ничего в жизни не обували?

Это высший класс. Да, технологии дорогие, но есть люди, которые не гонятся за дешивизной. И мне приятнее работать с такими людьми.
ответить
lair 9 марта 2013 в 20:06 0
… точнее — зачем использовать такие дорогие технологии с таким дешевым железом, что проект открывается до пяти минут?
ответить
dkukushkin 9 марта 2013 в 21:20 0
А причем тут железо? Вы NuGet используете? Репозиторий пакетов используете? Сколько зависимостей в вашем проекте?
ответить
lair 9 марта 2013 в 21:23 (комментарий был изменён) 0
NuGet и репозиторий пакетов не влияют на время открытия.

Ну и да, не важно, сколько зависимостей, проект не должен открываться столько времени, это непродуктивная трата времени разработчика. SSD и память нынче недороги.
ответить
dkukushkin 9 марта 2013 в 21:28 0
А вы NuGet используете только для внешних библиотек, или и для своих? У вас есть свой (внутренний) репозиторий-NuGet для пакетов, или храните их вместе с исходниками?
ответить
lair 9 марта 2013 в 21:29 0
Пакеты хранятся в версионнике (чтобы гарантировать стабильность). Соответственно, сколько их, уже не важно.
ответить
dkukushkin 9 марта 2013 в 21:42 (комментарий был изменён) 0
Классическим решением является свой NuGet-репозиторий. При первом запуске происходит авторизация и скачиваются пакеты (с учетом всех зависимостей). Потеря 2-3 минут единоразово не критична.

Можно хранить пакеты и с исходным кодом — есть плюсы и минусы такого решения. В таком случае у вас уйдет больше времени на постоянное обновление папки с пакетами (в итоге может даже больше потеряете).
ответить
lair 9 марта 2013 в 21:56 0
Классическим решением является свой NuGet-репозиторий.

Вы про это «классическое» решение расскажите Хамблу/Фарли, хорошо?

Потеря 2-3 минут единоразово не критична.

То-то вы выше на это жалуетесь, да.
ответить
dkukushkin 10 марта 2013 в 00:01 0
То-то вы выше на это жалуетесь, да.

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

А вот в вашем проекте сколько времени уйдет на передеплой старой версии с мелким изменением и ручным тестированием?
ответить
lair 10 марта 2013 в 00:08 0
А вот в вашем проекте сколько времени уйдет на передеплой старой версии с мелким изменением и ручным тестированием?

А почему такой упор на ручное тестирование?

А вообще — в пределах 15 минут, из которых 10 — это пречекин и деплой. И это время, вкупе с забором версии, как раз уходит на вход-выход из контекста.
ответить
dkukushkin 10 марта 2013 в 00:16 (комментарий был изменён) 0
А вообще — в пределах 15 минут, из которых 10 — это пречекин и деплой

Ну вот видите: 10 минут. Никак ни одна минута :)

По переключению контекста за 2.5 минуты — мне до вас далеко (у меня уйдет минут 20-30). Я пишу код в измененном состоянии сознания, в своего рода трансе. Могу и просто писать, но эффективность во много раз ниже.
ответить
lair 10 марта 2013 в 00:19 +1
Ну вот видите: 10 минут. Никак ни одна минута

А я и не утверждал, что одна минута. Но по факту, как раз в 15 минут можно уложить правку и смену контекста.

Я пишу код в измененном состоянии сознания, в своего рода трансе. Могу и просто писать, но эффективность во много раз ниже.

Могу вам только посочувствовать.
ответить
dkukushkin 10 марта 2013 в 12:04 (комментарий был изменён) 0
А я и не утверждал, что одна минута. Но по факту, как раз в 15 минут можно уложить правку и смену контекста.

Утверждал s0rr0w. У него получилось 1 мин. + 9 мин. на переключение. А у вас 10 мин. + 5 мин. на переключение. У вас сшилком быстро происходит переключение контекста, у большниства программистов займет значительно больше 5 минут.
Я для себя вывел формулу: не более 5 переключений в день. Кстати, многие с кем обсуждал — согласились и даже приводили в подтверждение некие исследования.
ответить
lair 11 марта 2013 в 12:12 0
А у вас 10 мин. + 5 мин. на переключение.

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

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

Может быть, это повод работать над собой?

Я для себя вывел формулу: не более 5 переключений в день.

Сочувствую вам. У меня переключений контекста в день десятки.
ответить
dkukushkin 11 марта 2013 в 19:00 0
Сочувствую вам. У меня переключений контекста в день десятки.

Просто имейте в виду: у многих людей переключение отнимает значительно больше времени. Если будете менеджерить — учитывайте эту особенность. И это вовсе не значит, что эти люди менее эффективны (может и наоборот — умеют копать глубоко).
ответить
lair 11 марта 2013 в 19:08 +1
Я в это («значительно больше времени») поверю только в том случае, если увижу, что человек реально за рабочий день не больше пяти раз отрывается от работы на что угодно, включая разговоры с коллегами и уж тем более — чтение интернетиков.

А так — Embrace Interruptions.
ответить
dkukushkin 11 марта 2013 в 20:08 0
что человек реально за рабочий день не больше пяти раз отрывается от работы на что угодно

Правильно.

Исключение можно сделать для механическай работы, которая не требует погружения и обдумывания.
ответить
lair 11 марта 2013 в 23:15 0
Так вот, я таких никогда (!) не видел.
ответить
dkukushkin 12 марта 2013 в 00:49 0
Так вот, я таких никогда (!) не видел.

Зависит от работы. Если работа сложная — бывало и на несколько дней забывал про форумы и хабры. Скайп специально отключал.

А вот если что-либо нудное — то перерывы помогают не умереть от тоски.

В среднем случае (не очень сложная работа) неожиданное срочное задание минут 30 оттягивает.
ответить
lair 12 марта 2013 в 10:11 0
Я могу повторить еще раз: я таких никогда не видел.
ответить
dkukushkin 12 марта 2013 в 15:22 (комментарий был изменён) 0
Я могу повторить еще раз: я таких никогда не видел.

Эффект избирательности. Даже если увидите — не поверите, будете думать что человек мухлюет :)
Почитайте статью, посмотрите обсуждение. Сколько в среднем в день ваши коллеги решают задач (посмотрите выписку из Jira). Везде увидите это магическое число 5-7, даже если задачи мелкие.
И не ставьте знак равенства между отвлечением на просмотр новостей/статей и выполнением работы.
ответить
lair 12 марта 2013 в 15:24 +1
Почему же, поверю. Если и когда увижу.

Сколько в среднем в день ваши коллеги решают задач (посмотрите выписку из Jira)

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

И не ставьте знак равенства между отвлечением на просмотр новостей/статей и выполнением работы.

А вот это как раз неверно. Потому что смена контекста-то происходит, просто вы отказываетесь ее признавать.
ответить
dkukushkin 12 марта 2013 в 15:33 0
А вот это как раз неверно. Потому что смена контекста-то происходит, просто вы отказываетесь ее признавать.

Почему же отказываюсь? Признаю.
Но в момент отдыха я могу продолжать думать о прерванном деле и решать проблемы в фоновом режиме. То есть когда сам прервал и не даю сильной нагрузки — процесс переходит в фоновый режим и затем быстро восстанавливается.
ответить
lair 12 марта 2013 в 15:35 +1
Но в момент отдыха я могу продолжать думать о прерванном деле и решать проблемы в фоновом режиме.

Просмотр новостей/статей — не отдых. И, самое главное, рутинная работа («добавить строчку в меню»), ничем не отличается от чтения статей на хабре по нагрузке на мозг, и, если является плановой задачей, точно так же активируется вами. Так что нет никакой разницы по стоимости смены контекста.
ответить
dkukushkin 12 марта 2013 в 16:24 +1
Просмотр новостей/статей — не отдых.

Здесь градация. Не да/нет, а множество оттенков. Кроме того, зависит от вашего отношения к новостям: если вы биржевый трейдер, то для вас это действительно не отдых.

рутинная работа («добавить строчку в меню»), ничем не отличается от чтения статей на хабре по нагрузке на мозг

Смотря что и как читать. Я сложные статьи отмечаю и читаю когда есть время на обдумывание.
ответить
lair 12 марта 2013 в 16:25 0
В итоге ваше «правило» обрастает таким количеством оговорок, что в практической жизни становится неприменимо.

Мой же критерий доверия остается очень простым и прямолинейным.
ответить
dkukushkin 12 марта 2013 в 16:34 0
В итоге ваше «правило» обрастает таким количеством оговорок, что в практической жизни становится неприменимо.

Ну… Психология не точная наука.

Мой же критерий доверия остается очень простым и прямолинейным.

Какого доверия?

Мы ведь говорили о экономической целесообразности автоматизации ручного труда и о опасности недооценивания времени на переключение контекста.
ответить
lair 12 марта 2013 в 16:52 0
Доверия к утверждению «у большей части людей переключение занимает значительно больше времени».
ответить
dkukushkin 12 марта 2013 в 17:21 0
Доверия к утверждению «у большей части людей переключение занимает значительно больше времени».

Это нужно провести соц. опрос в среде программистов.
ответить
lair 12 марта 2013 в 17:30 0
Соцопрос бессмысленнен, потому что опирается на внутреннее предубеждение.

По факту полезнее сравнение результата двух контрольных групп после года работы по двум разным методикам.
ответить
dkukushkin 13 марта 2013 в 14:09 0
Соцопрос бессмысленнен, потому что опирается на внутреннее предубеждение.

А почему вы считаете что оно ошибочно? Есть причина так считать?
ответить
lair 13 марта 2013 в 15:30 0
Потому что мнение человека о том, как ему комфортнее работать, основанное только на предубеждении, может быть корректным, а может и не быть корректным. Нельзя сравнивать вещи, которые ты не пробовал.

Что характерно, именно на этом основывается обучение: вы сначала научитесь, как правильно, а потом будете говорить, что вам так неудобно… если все еще будет неудобно.
ответить
qw1 12 марта 2013 в 21:32 (комментарий был изменён) 0
Я могу повторить еще раз: я таких никогда не видел.
Бывает, исправил одну строчку и не можешь о ней забыть 30 минут.
Думаешь: а всё ли правильно сделал, а учёл ли все граничные случаи. Иногда бывает, что при прокручивании в голове недавно правленного кода находишь баг где-то рядом, возвращаешься и доделываешь.
ответить
bav 9 марта 2013 в 11:06 +1
Автор почему то считает, что невозможно писать быстро и в тоже время без «говнокода». И кстати это будет быстрее и проще. Говнокод — это не панацея быстрого результата
ответить
bendingunit22 9 марта 2013 в 12:03 +10
Автор, Мартин и Фаулер пишут о том, что следую принципам KISS и YAGNI, необходимо выбирать самый простые алгоритмы и решения, удовлетворяющие текущим требованиям. А использование TDD позволить в дальнейшем, когда требования изменятся и усложнятся, безболезненно внедрять более сложные архитектурные решения а алгоритмы.

А вот о том, что простой код — это говнокод, и тем более, что говнокод обязателен, они точно не пишут, не стоит вводить читателей в заблуждение ;)
ответить
bendingunit22 9 марта 2013 в 12:21 0
Опечатки не успел поправить :)
ответить
dstarcev 9 марта 2013 в 13:27 +4
Почему-то всегда подразумевается, что делать хорошо — значит делать долго. Говнокод дает выигрыш в скорости разработки только очень маленьких проектов. А хороший код почти сразу начинает давать свои плоды, заметно снижая время на расширение и внесение изменений в проект.
ответить
HoochieMen 9 марта 2013 в 15:45 0
Полностью разделяю вашу точку зрения. Как то посвятил месяц на скелет фреймворка для внутреннего пользования, делая его модульным, легко расширяемым, необходимые хелперы, возможность переопределения любых частей модуля (контроллер, модели, вьюхи,js-lib,conf), написал базовые модули и прочие удобные вещи для себя. В результате сейчас при необходимости добавить новую фичу или даже большой модуль и т.д. времени уходит меньше чем писать тоже самое самым жестким хардкодом)
ответить
Vitamon 9 марта 2013 в 15:17 +2
Говнокод — это как мина в поле — обезвреживание в десятки-сотни раз дороже ее установки. И стратегия «throw over the wall» — не работает. У нас на проекте предшественники в базовом модуле накрутили какашек для «ускорения» процесса, и это дало метастазы во все остальные модули. В итоге построили высотку на гнилом фундаменте. И теперь чтобы все переписать и заменить на вменяемый код потребуется не один пресловутый человеко-месяц. И процесс разработки на этом проекте примерно такой: 2-3 дня разбираешься в говнокоде, пытаясь понять, что же он должен был делать, и в надеждах что его можно спасти рефакторингом, потом понимаешь что это никогда не работало и работать не могло и за 1-2 дня все переписывается с нуля. В итоге, колоссальные потери времени на самых простых фичах.
ответить
qw1 9 марта 2013 в 15:35 0
Самое смешное, что легко называть чужой код говнокодом.
Так же после вас придёт поколение поддерживать, что вы написали, и так же будет плеваться: «наговнокодили, а нам теперь всё переписывать и рефакторить» ))
ответить
Vitamon 9 марта 2013 в 15:40 +7
По этому поводу есть объективный критерий: image
ответить
VolCh 9 марта 2013 в 16:03 +2
Количество WTF сильно зависит от знакомства того, кто читает код, с приемами и шаблонами того, кто его писал. Если разработчик и ревьвер представители одной, так сказать, школы, то количество будет минимальным, хоть в случае спагетти, хоть в случае перенасыщения ООП- и архитектурными патернами.
ответить
dstarcev 10 марта 2013 в 13:17 0
Прежде чем проводить ревью, нужно ознакомиться со стилевыми и архитектурными правилами, принятыми в проекте. Тогда многие вкусовые WTF отпадут сами собой.
ответить
VolCh 10 марта 2013 в 13:36 0
Явно сформулированных их может и не быть.
ответить
dstarcev 10 марта 2013 в 13:46 0
Я бы тогда с них начал)
ответить
VolCh 9 марта 2013 в 16:04 0
Усиливать связанность и ослаблять связность проще чем ослаблять связанность и усиливать связность :)
ответить
Albert_73 9 марта 2013 в 15:54 +2
В реальной жизни в 99% случаев будет так

«В это же время за неделю мы по кликам, статистике, аналитики конверсии заказов поняли, что нужна линейная категоризация, выбрасываем категории и делаем облако тэгов...» которое не работает и более того рушит почему-то базу данных и одновременно рвёт разметку на нашем втором сайте который никак не связан с этим приложением, а выброшенные категории дали рут доступ к нашему серверу!

Если серьъёзно, то все эти споры всегда упускают одну важную деталь — О каких приложениях идёт речь? Сложность и ответственность являются определяющими. Если вы пишите никому не нужный пет-стартап с картинками и котиками то волне подходит говнокод как вариант времяпрепровождения. И никакого рефакторинга там никогда не понадобится, кстати. Если же вы взяли у бандитов десять миллионов долларов и пишите подпольное казино или взяли у государства миллиард и пишите почту России то подход должен быть с большим колличеством метрик.
ответить
VolCh 9 марта 2013 в 16:09 0
Эх, если бы «владельцы» госпроектов относились к ним как многие стартаперы к своим, никому ненужным проектам…
ответить
lair 9 марта 2013 в 20:09 0
взяли у государства миллиард и пишите почту России то подход должен быть с большим колличеством метрик.

Скажите честно, вам приходилось работать с госструктурами? (я про РФ, конечно)
ответить
MaksSlesarenko 9 марта 2013 в 16:11 +1
В php примером является ранний мегасвязанный zend, когда ООП ради ООП


не совсем понятно, что в зенде имеется ввиду под многосвязаностью, и как это относится к ООП ради ООП. Можно поподробнее?

Зенд всегда был набором библиотек натыреныхпортированных с других фреймворков, поэтому они все были разрозненные и обязку для них нужно было писать самому ручками. К примеру, ACL вобще ничего не знал по MVC, также как и AMF, REST, Tool. На вскидку, могу вспомнить Date, Config, View на которых были зависимости в других компонентах, все остальное нужно прикручивать самому.

В симфони все немножко не так, он более монолитен и все компоненты подогнаны друг под друга, ручками писать, практически, ничего не нужно.
ответить
merkuriy 9 марта 2013 в 16:46 0
Почему никто не вспомнил про такое слово как — Agile!? Ведь описанное в топике пересекается с принципами этой методологии. На каждую итерацию разработки берём самые важные и ценные пользовательские истории (фичи, желания, требования, хотелки, фидбеки) и разрабатываем только их, получая результаты в кратчайшие сроки. И так с каждой итерацией, быстро реагируя на изменения пользовательских историй, дорабатываем только то, что оказалось востребованным, и выкидываем то, что оказалось не востребованным и разрабатывая фичи под новые пользовательские истории.

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

Нельзя разумно допускать ошибок, которые характерны малой квалификации, опытности или незнанию азов, теории и правил поведении при определённых используемых программных средств и языков программирования, правил, принятых на проекте и вообще в команде — если при этом ты знаешь, что это будет ошибкой такого уровня. Если увидел такие ошибки в чужом коде — укажи на них его автору, минимальными усилиями поправьте и продолжайте работу.
ответить
VolCh 9 марта 2013 в 17:24 0
По-моему, речь о возможности по разному писать код в пределах каждой итерации. Допустим решили сделать в текущей простое плоское меню на HTML, только навскидку 5 вариантов:
— жесткий хардкод в шаблоне. Максимум урлы хелперами генерируются. Добавить пункт меню — нужно ручками в исходниках писать теги li, а, может img и т. п.
— какой-то захардкоженный массив, который в шаблоне циклом выводится. Добавить пункт — элемент в исходниках в массив добавить, возможно перекомпилировать, в любом случае деплоить
— то же, но файлик или таблица в БД, откуда массив заполняется. добавить пункт — файлик отредактировать или табличку, в исходники лезть не нужно
— то же, но есть полноценная админка
— автоматически формируемое меню на основе списка подключенных модулей, к каждому модулю добавляется метаинформация о его отображении в меню или для отображения используется существующая метаинформация.

При этом ещё любой пункт может быть сделан качественно (покрыт тестами, задокументирован, тщательно подобраны имена сущностей, отмечены будущие возможные todo и т. п.), а может быть сделан по принципу «лишь бы работало» (тестов нет, документации нет, имена типа a1, a2 и т. п.), а может только частично за качеством следили. В общем вариантов масса и какой из них счесть «минимально необходимым» напрямую к Agile не относится, это вопрос QA.
ответить
bendingunit22 9 марта 2013 в 17:58 0
Кстати, в подобного рода публикациях почему-то никогда не упоминается квалификация разработчиков, а это не последний фактор, влияющий на качество кода. Квалифицированный, опытный программист никогда не опустится до уровня говнокода просто потому, что не сможет. А неопытный или попросту ленивый всегда найдет отговорку (сроки, прототип, дедлайн), призванную оправдать низкую квалификацию. При этом стоимость разработки будет идентична, а вот в стоимости поддержки выиграет хороший (не путать с идеальным) код — это очевидно.

И не стоит забывать, что из трех ползунков качество должно быть постоянным. Об этом говорят и ДеМарко, и Фаулер и дядя Боб.
ответить
Throwable 10 марта 2013 в 14:03 0
Проблема в том, что рефакторинг кода никогда не запланирован в проекте. Когда код заработал, тестовая группа отчитлась, и менеджер ставит следующее задание о добавлении функционала. Рефакторинг в среде менеджеров (и уж тем более клиентов) — вещь немодная, и воспринимается как оправдание. В итогде код быстро обрастает говном как снежный ком. И наступает этап, когда рефакторить уже обросший функционалом код не представляется возможным. А поддержку этого дерьма делать приходится. Время на поиск ошибки увеличивается в разы, а при добавлении нового функционала всегда что-нибудь отваливается. Поэтому изначально нужно продумать хорошо скелет и прототип системы, что называтся, положить рельсы.

Тем не менее, можно идти и вашим путем, если запланировать полный рефакторинг (читай — переписать с нуля) с версии 2.0. Новая архитектура будет разработана с учетом опыта и потребностей реально работающей системы.
ответить
s0rr0w 10 марта 2013 в 14:49 0
Но снова таки без учета будущих требований. Пока вы пишите вторую версию, бизнес не стоит на месте, и вполне возможно, что вы еще не дописали, а уже нужно снова рефакторить. А еще старую систему поддерживать надо. У меня была такая ситуация. Пришлось на конкретном примере показать, что про старую систему лучше всего забыть, иначе новая никогда не будет написана.
ответить
qw1 10 марта 2013 в 15:15 0
Я думаю, тут речь о рельсах под технологиями, а не под поведением и бизнес-требованиями.
Например, сразу используем трехзвенку, а не двух. Или сразу берём мощный генератор отчётов, а не собираем на коленке.
ответить
bendingunit22 11 марта 2013 в 00:56 0
Рефакторинг нужно проводить непрерывно. Три недели разрабатываем, неделю рефакторим — это не самый удачный подход. Удачный — сделали фичу (задачу), отрефакторили тесты, отрефакторили код. Время на рефакторинг закладывается при оценке задачи, точно так же, как и время на написание тестов.
ответить
bendingunit22 11 марта 2013 в 00:59 0
Ну а рефакторинг легаси кода — это отдельная история. Фаулер рекомендует сначала покрыть код функциональными тестами, чтоб зафиксировать поведение, и только потом приступать к рефакторингу. Такая задача, действительно, может потребовать серьезных затрат.
ответить
Bagobor 11 марта 2013 в 22:10 0
Модельный пример довольно однобокий и больше касается не написания кода, а стратегий приложения усилий что бы опредить конкурентов. Но в долгосрочной перспективе вполне может быть конкурент который знает как правильно, и будет писать это правильно месяц. Через месяц выкатывает — вы умираете или выкидываете текущий говнокод что бы переписать на новый «правильный» лад.
В общем тут все зависит от стоимости кода. Если его можно переписать за неделю. И это может сделать любой программист с улицы — отлично.
Если этот код написал некий «математик» и никто не можешь его даже прочитать — то другое.
А статья скорее о том что модель\прототип надо иметь как можно раньше, и как можно раньше начинать тестировать на пользователях, особенно если это массовый продукт, такой как сайт.
Конечно все мое _имхо_.
ответить
kemsky 11 марта 2013 в 22:28 0
Еще ни разу я не видел, чтобы говнокод приносил пользу, наоборот: саппорт, фиксы, миграции на новый фреймворк/платформу — все проходит очень болезненно, а некоторые вещи просто невозможны. Авторы говнокода к этому моменту обычно говнокодят что-то новое или уходят (они ведь сделали свое дело), фикс говнокодером говнокода является говнокодом в квадрате и скорее всего не будет сделан вовремя. Не нужно писать совершенный код, среднего и не очень хорошего качества достаточно, чтобы сильно облегчить себе и другим людям жизнь.
ответить
s0rr0w 12 марта 2013 в 00:04 0
Все зависит от точки зрения, что именно считать говнокодом. Для меня говнокод это не тот код, который написан в спагетти-стиле, а тот, который не решает поставленную задачу. Я видел немало людей, которые увидев тот подход, который мы используем, и тот код, который мы пишем, говорили одну фразу: «Что за говно?». Зато я точно уверен, что с поставленной задачей мы справляемся на ура.
ответить
VolCh 12 марта 2013 в 00:27 0
Просто частенько бывает, что не все задачи стоящие перед кодом заказчиком озвучиваются или вообще имеются в виду. А потом всплывают. Скажем, когда взял другого исполнителя на модификацию.
ответить
s0rr0w 12 марта 2013 в 00:35 0
Заказчик часто что-то не договаривает, путается в показаниях, не смотрит дальше своего носа, и, зачастую, описывает проблематику полугодичной давности. Вот тут в игру должен вструпать архитектор, который предвидит проблемы до того, как они возникнут. Другими словами, архитектура приложения должна в первую очередь учитывать будущие модификации. Единственный способ это сделать, который мне известен, это конфигураторы и конструкторы. Т.е сначала пишется конструктор, а потом уже на нем выполняется основная задача.
ответить
VolCh 12 марта 2013 в 00:40 0
Далеко не каждый заказчик согласен будет заплатить за разработку конфигуратора или конструктора. А если разбивать стоимость на нескольких заказчиков (грубо говоря, сделать коробочный продукт), то это уже другая бизнес-модель, по-моему. Не разработка софта на заказ, а продажа конфигуратора и услуг по конфигурации.
ответить
s0rr0w 12 марта 2013 в 00:49 0
Открою большой секрет. Только никому, ладно?

Есть технологии, благодаря которым конструкторы можно создавать невероятно быстро. Например XML.
Я за два дня написал то, что продается другими компаниями банкам за сотни тысяч долларов :)

Если вернуться к нашим беседам чуть раньше, я приводил пример шаблонизатора на XML, который можно написать за неделю (базис пару дней пишется). Это не тот срок, который может серьезно пошатнуть финансовое благополучие заказчика.
ответить
VolCh 12 марта 2013 в 01:13 +1
Как я понимаю, XML в таком случае лишь формат хранения конфига. Его обработку все равно нужно будет писать. И по сути не важно как хранится конфиг — XML, YAML, JSON, INI, в БД, захардкожен с выносом в массив/объект или вообще прямо в коде. То есть по идее то, что вы написали я бы мог написать «в лоб» условно за день.

Шаблонизатор весьма частный случай, шаблон описывает представление данных в разных форматах, но он не может описывать логику их обработки. Или это уже будет не шаблонизатор,, а второй PHP :)

В общем я с трудом представляюю себе конфигуратор для достаточно широкого круга задач (как бизнес, так и технических), без того чтобы язык его конфигурирования не перерос в язык программирования (пускай не символьный, а графический) со всеми вытекающими. Что-то узкоспециализированное — вполне. А реализовать произвольную логику — нет.
ответить
s0rr0w 12 марта 2013 в 01:28 0
Задача конструктора — решать маленький спектр задач наилучшим способом. Приведу еще один пример, где это работает в полную силу. В современных x86 процессорах сложные макрооперации (CISC) транслируются в микрооперации (RISC). Потому что так проще всего перестраивать их и наиболее эффективно использовать исполнительные устройства. Такая технология как Hyper Threading была бы неэффективна или вообще невозможна без внедрения декодирования макроопераций.

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

Любой ЯП — конфигуратор для широкого круга задач. Написать на этом языке еще один язык, но более специализированный — тоже один из вариантов решения задачи. Предлагаю посмотреть немного шире на программирование :)
ответить
Изображение

dyvniy M
Автор темы, Администратор
Администратор
Аватара
dyvniy M
Автор темы, Администратор
Администратор
Возраст: 41
Репутация: 1
Лояльность: 1
Сообщения: 3579
Зарегистрирован: Ср, 10 октября 2012
С нами: 11 лет 5 месяцев
Профессия: Программист
Откуда: Россия, Москва
ICQ Сайт Skype ВКонтакте

#47 dyvniy » Пн, 6 марта 2017, 16:39:41

Хороший компьютерщик сейчас - как хороший конюх в начале 20-го века, хороший радист в середине или хороший специалист по электронике в 70-х.
Профессия нужная, распространённая и, вроде, в будущем востребованная. А потом приходит будущее и оказывается, что всё не так.
http://www.computerra.ru/88131/linux-aging/
3й комментарий

https://ru.wikipedia.org/wiki/Открытое_письмо_любителям
Изображение

dyvniy M
Автор темы, Администратор
Администратор
Аватара
dyvniy M
Автор темы, Администратор
Администратор
Возраст: 41
Репутация: 1
Лояльность: 1
Сообщения: 3579
Зарегистрирован: Ср, 10 октября 2012
С нами: 11 лет 5 месяцев
Профессия: Программист
Откуда: Россия, Москва
ICQ Сайт Skype ВКонтакте

#48 dyvniy » Чт, 27 апреля 2017, 17:26:57

Писать программы надо как Стивен Кинг пишет книги
https://habrahabr.ru/company/infopulse/blog/173017/
Изображение


Название раздела: Программирование (под Desktop и Android)
Описание: Разработка и отладка приложений. Упор на 3D-графику.

Быстрый ответ


Введите код в точности так, как вы его видите. Регистр символов не имеет значения.
Код подтверждения
:) ;) :hihi: :P :hah: :haha: :angel: :( :st: :_( :cool: 8-| :beee: :ham: :rrr: :grr: :* :secret: :stupid: :music: Ещё смайлики…
   

Вернуться в «Программирование (под Desktop и Android)»

Кто сейчас на форуме (по активности за 15 минут)

Сейчас этот раздел просматривают: 6 гостей