Python для собеседований

Однажды задолбался задавать на собеседованиях одни и те же вопросы без fun’а, родил функцию на Python. Веселился, придумывая. Кажется, решавшие задачку тоже получали свою порцию.
Собсно, вот код (Python 3.x):

import 'os'

func readFileId(names=[], mode):
    _ = ''
    id = -1
    for n in names:
        with os.open(n, 'w') as f:
            _ += f.read()
        f.close()
    print 'default: ' + id + ', actual: ' + _
    return id ? _ : id

Надо найти в нём ошибки. В зависимости от упоротости и перфекционизма количество ошибок от X до Z (подумал и решил таки не публиковать числа, лишняя подсказка получается). Кому и игнор PEP8 спать не мешает.

Суть упражнения (вполне типового, похожим джавистов на сертификациях кошмарят) в следующем:

  • Проверка знания языка.
  • Проверка внимательности.
  • Проверка умения думать над кодом.
  • Иногда показывает уровень чувства прекрасного.

Т.к. собираюсь написать более задорный вариант, этот «палю». Применять его больше не буду. Развлекайтесь.

PS. Тем, кто не согласен и у кого что-то не получается: пжлст, не пишите мне, что вы не поняли код, что это плохое упражнение и прочее. Значит, не для вас. Не беда.

Архитектура костыля

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

Архитектура является тем более гибкой, чем больше в ней мест, в которые вы можете воткнуть костыль без переписывания остального кода. Костыль — ветвление, хардкод, жесть категории «if user == petrov { kill all }».

И никак иначе. Остальное не работает.


Фигня в том, что реальный мир, с которым соприкасается ваш софт, с его реальными людьми и прочими занятными явлениями является миром костылей. Мы вынуждены компенсировать чужие ошибки, например. Вынуждены учитывать, что в окружении сервиса любой элемент может упасть в любой момент времени. Мы должны учитывать пьяного дядю Васю на буровом тракторе в Кукуевке, испокон веков стоящей на трансгалактическом кабеле связи. Бухгалтеров. Детей с их разрушительными лапами. Распинаться так могу ещё долго.
И вот всё это хоть как надёжно друг с другом интегрируется только потому, что в каждом сервисе есть вёдра if’ов. Даже если вы по наивной прозрачности мозга выпустили в свет хрустальный сервис, уже через год в нём будет вот это вот всё. Окажется, что в стороннем API ошибка (или ошибки, если считать таковыми разработчиков API). Или к вам зайдёт очень грустная помощница очень главного директора с просьбой больше не делать с её директором то, что мы задумали делать со всеми. Или вам очень-очень надо оптимизироваться, ужимаясь в худенькую квоту серверов. Или клиент пишет «отправлять вам запросы могу ТОЛЬКО ТАК, всего вам хорошего, держитесь». Или бага в базе данных (тикет болтается с 2013 года), а вы это обнаружили за минуту до выкатки. Или от вас очень захотели работающего рендеринга сайта на IE под Mac OS образца 2007 года.
Так нафига страдать нервами по факту? Заранее, всё можно предусмотреть заранее. Не упарываться по фабрикам, возвращающим фабрики (привет джавистам). Не унифицировать всё до нечитаемой одной строчки. Не стремиться избавлять код от лишнего (что нередко не лишнее, но те части нужной реальности, что не попадают в вашу чистую модель). Не городить тонну абстракций. Пара лет эксплуатации и на активно живущем сервисе вас проклянут, пытаясь не убиться в попытках сберечь красоту (забьют болт и начнут запросто костылить, что будет гораздо уродливее на фоне ваших абстракций).
Архитектура (и код) должна отражать реальный мир. Реальную задачу и её прогнозируемые вариации. API отдаёт пять видов ошибок (не смогли разработчики в унификацию, потому в одном случае код есть, в другом нет, в третьем список ID хардкодом в тексте сообщения, в четвёртом списка нет аще, в пятом код ошибки в некоторых случаях является кодом удачной операции)? Делайте пять классов на каждый вид. Не, блин, унифицируйте, блин. Завтра они добавят шестую ошибку. Послезавтра заказчик попросит в третьем варианте ошибки дополнять своими данными. И всё, хана вашим красотам.

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

Code coverage

Кратко про тему, на которой иногда копья ломаем. Code coverage — штука, которую в 3/4 мест агрессивно игнорируют, а в другой 1/4 агрессивно используют. Равнодушные встречаются не так уж часто.

Вся фигня в том, что это количественная метрика, на такие у разработчиков аллергия ещё со времён попыток оценить работу через LOC (кто больше строчек написал, тот и победил). Доведённый до абсолюта CC звучит вот так:
У тебя код тестами покрыт?
Да.
А почему покрытие 53%?
Потому, что остальной код — это обёртки с сотней тупых get/set.
И что? У нас покрытие должно быть 100%!
Иди нафиг, я увольняюсь.
Расскажу байку из жизни. Контекст: Python, сервис с некоторым покрытием тестами и некоторой документацией, живёт в production не первый год. Нахожу багу. Исправляю. Вроде исправилось, ништяк. Выкатываю. Проходит совсем немного времени. Сервис падает. Как оказалось, фикс баги открыл доступ к куску коду, который пару лет (емнип) не исполнялся вообще. И если бы хоть раз выполнился, сразу упал бы, что и произошло, там явная ошибка категории «что будет, если у null вызвать метод». Не хватило всего одного однострочного тупого теста, чтобы избежать пятисотящего прода.
Так вот. В нынешних условиях главная и важнейшая роль code coverage — показать вам код, который НЕ покрыт тестами и, быть может, вообще никогда не дёргался. Это полезно и для самопроверки (а не забыл ли я MyCoreServiceTest написать). Полезно для сторонней проверки (а есть ли в our.core.service вообще тесты). Полезно для оценки покрытия тестами ветвлений в том, что вы всё-таки решили потестировать (внезапно один if оказался за кадром).
Давайте ещё раз, пока не кинулись сразу же закидывать тухлыми тапками. На практике code coverage НЕ о том, СКОЛЬКО у вас тестов, фиг с ним. Он о том, есть ли вообще у вас тесты в нужных местах, а в ряде случаев и про качество этих тестов. Всё.

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

Легаси

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

Знаю, конечно. Интранет и до тебя был отличным, и как ты ушёл остался замечательным, даже лучше стал. Ты же там видел только костыли и легаси – потому что мыслишь узко. Бойцы типа тебя – не те кто инфраструктуру пилит, которую якобы не очень видно на фоне кораблей, бороздящих просторы созвездия Лебедя, а те, у которых предел мечтаний отрефакторить код, чтобы можно было прикрутить любимый (модный, надежный, whatever) фреймворк.

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

Не сомневаюсь, что без меня везде становится только лучше, но любимая мозоль (легаси) была задета. Отсюда и тема.


Начну с формальностей. «Официальное» толкование термина в Википедии само по себе кажется вариантом legacy, потому озвучу свой вариант, которым в голове постоянно оперирую и который подспудно везде подразумеваю.
Легаси — код, для которого через AND (со|на)блюдается следующее:

  1. Находится в production’е, т.е. каким-либо образом используется на текущий момент.
  2. Вносить в него изменения либо невозможно, либо неадекватно дорого.
  3. Не в полной мере удовлетворяет актуальным требованиям, при этом количество таких требований со временем возрастает.

По номерам пунктов и разверну.


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

Во-2-х. Кейс с потолка. Программа библиотечного учёта. Вроде работает, библиотекари даже прижизненный томик Льва Толстого подарили на радостях. Спустя год потребовалось добавить новое поле к карточке. Да фигня, там же тех полей и так много, скопипасть соседнее, переименуй, вот и всё, десять минут работы. Разработчик смотрит в код. Документации, к слову, нет, потому в код смотрит прям сразу. Делает чай. Смотрит ещё раз. Закуривает. Смотрит. Чертит схемы на бумажках. Добавляет сто строк кода и спустя сутки без сна рапортует об успехе. Одно поле. Сто строк. Сутки работы. Знакомо, нет? Если нет, не завидую, у вас впереди свежесть эмоций от осмысления пропасти между простотой задачи и сложностью реализации. Одна из самых характерных черт легаси. Таких задач всё больше. Каждое впиливание в легаси нового продуктового заказа делает код сложнее для впиливания следующего заказа. Лапша из костылей. Если потом упороться и собрать годовую статистику «потратили столько часов, а, казалось бы, должны были столько», волосы дыбом мурашками шевелятся. Дешевле было заново сервис написать. Год, другой, третий жуют кактус. На четвёртый героически переписывают. Ура.

В-3-х, актуальные требования. Тут четыре вектора.
Продуктовые требования. Есть простое эмпирическое правило: если хочешь получить легаси со старта, напиши сервис ровно по ТЗ. Тютя в тютю. Мир меняется, люди меняются, да чего там, гречка дорожает. Сегодня одно ТЗ, а уже через год жизни в production хотелок накидывают столько и таких, что повторно написанное ТЗ породило бы другой сервис. Хороший код обладает запасом гибкости, позволяющим менять сервис точечно, и прочности, позволяющей сохранить при всех изменениях исходную архитектуру. Легаси же этим не обладает. Потому часть задач не делается сейчас. Часть не сделается никогда. Часть делается в муках. Новых требований всё больше, нового [полезного] кода всё меньше.
Требования стабильности. Новые версии софта выпускаются не только потому, что дяденькам for fun чиселкам плюс-плюс делать, но ещё и потому, что есть security fixes, например. Или вдруг обнаруживается memory leak (который вы счастливо прохлопываете в продакшене, старательно убивая worker’ы uWSGI после малого N запросов). Или «о, блин, народ, мы тут sleep десятисекундный забыли, простите, вот новая версия». В который раз настоятельно советую читать changelog’и MongoDB и Java. Возможно, на сотом багфиксе что-то станет более понятным в контексте «надо обновляться».
Ресурсные требования. Если у вас сто машин на десять сервисов, а вам нужно ещё два сервиса добавить, но некуда, начинаете думать и смотреть с лупой на код. Мне с этой позиции интересен недавний микрокейс. Стоял nginx 1.10, в который впилили скрипт на Lua, который генерировал uuid для request’ов. Стоял давно, впилили тоже давно. Работает и ладно. Нормальный талантливый человек пройдёт мимо. Ненормальный мыслит узко и вспоминает, что в nginx 1.11 добавили штатный request_id через SSL RAND_bytes, потому что? Потому этот скрипт можно выпилить, апнув nginx. Профит. Если масштабировать этот подход к тем десяти сервисам… вот кажется, что всё-таки после массовых обновлений всего можно там выпилить, сям подпилить, вон там «само» ускорится. И потому пару машинок уже можно отобрать.
Наконец, требования современности. Код на Java 1.2 (релиз 1998 года), на дворе Java 1.9 (2017 год), на рынке джависты с опытом Java 1.6, 1.7, 1.8. Проблема ясна? Или другой вариант: в коде Django 1.6 (релиз 2013 года), на дворе Django 1.11 (релиз 2017 года, к слову, последний релиз с поддержкой Python 2.7, вдруг кому интересно ещё раз подумать о том, что такое легаси на практике). С каждой новой выходящей версией чего-нибудь теряется поддержка старого чего-нибудь. Поддержка людьми, поддержка рынком, поддержка информацией, банальная техническая поддержка («мы эту фичу сделали только с версии N.M»).

Таким макаром в самом кошмарном варианте вы получаете чудище из страшных снов разработчиков, пользователей и заказчиков: фичи не добавляются, поддерживать тошно, ресурсы жрёт как не в себя, болтается на стремительно устаревающем техностеке, дырявое аки решето. Самое время, чтобы подумать «ой, чёт хочу вкрутить свой любимый фреймворк, надо бы порефакторить!» ^_^
Самое, пожалуй, фиговое, что заполучить легаси очень просто. Достаточно поступать вот так:

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

Если совсем кратко, то сначала не подумать о проблемах, потом забить болт на проблемы. Вуаля.


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

Нинужные знания и умения

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

Если вы живёте не в мире бесплатных фей и платонических бабочек, вы получаете деньги за то, что делаете что-то, что приносит деньги работодателю. Такой вот понятный и простой бартер, к которому зачастую сводятся причины многих решений, если покопаться. Соответственно, работодатель через прищур смотрит на вас рационально: будет ли Вася приносить прибыль? как долго? а сколько?
При этом как-то… ну, слишком наивно считать, что Вася — это только оклад. Совсем уж наивно считать, что Вася — это 180 рабочих часов в месяц (2160 час в год при 22-дневном рабочем месяце).
Во-первых, ежегодно Вася болеет. По моим наблюдениям дней десять в год минимум (-80 часов). Я вот сам сейчас уже третью неделю с трудом выкарабкиваюсь из волны ОРВИ с осложнениями.
Во-вторых, ежегодно Вася берёт отпуск. Недели две хотя бы (-80 часов), хоть знал бойцов, исправно выбирающих за год весь лимит.
В-третьих, Вася человек, а у людей ежегодно случаются всякие штуки вроде «срочно отвезти дедушку в больницу» или «канализацию прорвало, закрываю дыру телом». Пусть три раза в год, -24 часа.
В-четвёртых, если Вася живёт в России, по производственному календарю у него не 2160 рабочих часов в 2017 году, например, но 2024.
Что получилось? 1840 номинальных рабочих часов. Это минус почти два рабочих месяца из первоначального наивного числа. А теперь все посмотрим в зеркало и честно скажем отражению: очень, очень, очень редко обычный линейный разработчик без усиленной мотивации честно вот прям 8 часов работает. Попыриться в окно, пообедать, покурить, потрындеть про новые носки Путина и ярость Навального, посмотреть презентацию нового iPhone, почитать Твиттер и т.д. Реально человек работает 4..5 часа. Пишет код, усилено думает над задачами, вообще трудится на благо работодателя. Аксиома такая. Выведена поколениями всяких лидов, наблюдающих за контингентом и собою. Вы (разработчик) не работаете треть рабочего времени. Как минимум. Чтобы было менее больно, от 1840 срезаем 500, получаем 1340 часов. Или (чуть округлю) 110 часов в месяц. Вот столько работают люди на окладе в офисе.

Мораль: час работы разработчика стоит дорого. Дороже, чем вы думаете. При наивных расчётах час Петрова стоит 1К рублей, если оклад в 180К рублей. В реальности час стоит 1К рублей уже при окладе в 110К. На самом деле он стоит ещё больше, если включаем аренду рабочего места, оплату обязаловки (от электричества до интернета (стоимость бизнес-пакетов вас приятно удивит)) и прочее. Скажем, Васям почему-то не нравится думать о том, что каждый эпизод «Васин косяк привлёк двух других разработчиков на два часа» является эпизодом «на два часа стоимость часа Васи увеличилась на сумму стоимости часов этих двух разработчиков» (теперь занятнее думать о том, сколько же на самом деле стоят junior’ы, которых курируют тимлиды хотя бы на 25% рабочего времени, да?).
Главное, что надо понять, усвоить и зазубрить: разработчики обходятся работодателям дорого. Очень дорого, если сравнивать с трудовым ресурсом других отраслей. Всякий раз, когда разработчик ленится хотя бы посмотреть в документацию (божечки, как же бесят такие случаи) и в итоге дико тупит, вспоминаю, что оклад middle в Москве примерно равен двум окладам врача Скорой помощи в Москве. И учились эти врачи гораааздо дольше и суровее. И ответственности у них больше. А уж пользу обществу не измерить. Только вот те двое на дежурствах в пыль исходят, жизни спасая. А этот сидит в креслице в тепле и с потолка считывает результат функций.

Итак, работодатель и прищур. Задача: нанять человека, который будет продуктивно и эффективно (очевидно, если вы два часа пишете строчку подключения к базе, вы работаете, да, но фигово) работать максимально возможное количество часов, с максимальной скоростью двигаясь к моменту релиза продукта, который пойдёт на рынок и начнёт приносить прибыль. Вроде бы всё хорошо… пока не начинаем думать о том, что жизнь сложнее. Следующий продукт тоже надо делать. И ещё один. А ещё избавляться от «автобуса» (потому в идеале по 2+ ротирующихся разработчика на сервис). И даже при удаче нанять будущего тимлида. В общем, губа не дура, особенно если учесть всё бОльшее проседание рынка senior’ов (бягуть на Запад и Восток).
Иными словами, хочется бойца, который хорошо решит не только текущую задачу, но и следующие. Хорошо — это когда маленький скрипт не требует $1K инстанс ежемесячно в облаке и когда ночью спать можно, а не на мониторинг коситься с опаской. Следующие — это любые. Любые. ЛЮБЫЕ. ЛЮБЫЕ. Понимаете?
Мир не стоит на месте. Бизнес идёт за миром и прогрессом. Вчера вы писали GOTO на BASIC, сегодня кошмарите нейронные сети, завтра будете разучивать «папа» с белковыми компьютерами. Ещё сегодня основным продуктом у вашей фирмы был Paint, а завтра для порабощения мира надо выпускать Photoshop. Разведёте руками? Вы не знаете, где хотя бы прочитать, как блюр делается? Вообще читать не умеете, Paint писали интуитивно? Ну ок, вас уволят, наймут умеющего. Устроит? Не думаю. Вы должны мочь идти вровень с цивилизацией. И работодатель хочет, чтобы вы могли. Выгоднее нанять на большой оклад настоящего специалиста, чем дюжину сантехников на мизерные оклады. На сантехников заработает потом вот этот крутой.
При этом работодатель всё-таки не всегда дурак. Потому проверяется не гениальная универсальность (никто не может знать всё). До меня не сразу дошло, но чем дальше, тем больше нравится такая трактовка: проверяется то, можете ли вы решать задачи, которые вам не надо решать прямо сейчас. Хихи. Звучит идиотски, ок. Однако. Нужно понять, насколько вы можете выйти за рамки своей раковины. Насколько способны учиться. Раскрыты ли ваши чакры (фигакры) новому, будущему. Есть ли у вас база для того, чтобы быстро (!) нарастить свежее мясо. Наконец, как вы вообще относитесь к профессии.

И вот тут грустное. Телепатов нет. Провидцев нет. Единственный хоть сколь надёжный способ оперативно понять, может ли человек выйти в будущем за рамки — узнать, вышел ли он за рамки уже сейчас. Рамки разработчики ставят себе убогие (пардон) — что сейчас не надо, то и не буду знать. Так на собеседовании и говорят прямым текстом. Был senior (!) джавист (!), который не ответил ни на один вопрос про работу GC. Ему не надо было никогда. Видимо, когда надо будет разбираться, почему сервер падает по OOM (а у таких бойцов он с гарантией однажды ляпнется), работодатель в идеальном мире смиренно дожидается, пока Вася пройдёт обычный цикл нехочузнаек: 1) почитаем StackOverflow — не, чёт не помогло, 2) погуглим уже полноценные статьи — не, чёт не помогло, 3) лаааадно, мы этого не любим, но пошли читать документацию… ойкакмного! мамочки! насяльника, мне нужна неделя, тут осинь сложный проблема!
Помните про реальную цену часа разработчика? Работодатель тоже помнит. Ни фига не интересно в будущем оплачивать вам сотню рабочих часов только потому, что вы принципиально или по лени природной не подбираете «лишние знания». Нет их лишних. Это у вас в прошлом, быть может, не было задач, которые решаются такими знаниями. Может быть, не было именно потому, что ваш тимлид знал, что нет смысла давать вам такие задачи, вон Вася более прокачан, лучше ему дать. Или просто так получилось. Или вы работали там, где такие задачи и такие проблемы возникают раз в десятилетие (а в соседнем отделе раз в неделю, сюрприз). Да тысяча причин. Солдаты учатся стрелять не потому, что каждый день убивают по врагу, но потому, что однажды война. И будет поздно учиться («чё, утром войну объявили? о, ну это… я на стрельбище пойду, хоть посмотрю, как у автомата приклад выглядит, настало время» — как-то так представляю).
И вот как… сидите вы и говорите, что не знаете элементарного. Вам оно казалось лишним. А работодатель сидит напротив и смотрит. А в голове у него тоска. Он уже понимает, что ни фига с вами не сделать Photoshop из Paint. Что после того, как вы сделаете буквально ту задачу, на которую сейчас срочно нанимают, будет головная боль на тему «куда девать такого кадра, он же только X знает и Y». Что ни фига байки «да ща за минуту нагуглю и освою» не работают. Тимлид тем временем тоже печалится. Он-то азартно задал вопрос «что такое хеширование, приведи примеры», а вы не ответили. Не надо было знать. Раз так, то вы не знаете, как работают hash-коллекции. А потому не решите в разумные сроки задачу «написать более специализированный и оптимальный dict, ибо у нас вооон там затык обнаружился». А если вдруг вас наймут и таки дадут эту задачу, то надо будет за вами каждую строчку по пять раз вычитывать. На всякий случай. Что не так уж интересно. А ещё надо будет вам однажды объяснить, что такое фингерпринты. И на всякий случай проконтролировать в будущем, что вы в PostgreSQL осилите выбрать нужный тип индекса. Сплошное веселье.
Итог: вас не наняли. Злые дядьки спрашивали странное. Пойду в бложик бяку про собеседования напишу. Кому ваще это хеширование надо?! Ни разу не требовалось! Мудаки, кароч.

Как-то так. Эссе получилось сырое и мятое, не везде заполнил переходные выводы и примеры. Потому давайте кратко основные тезисы ещё раз:

  1. Час работы разработчика стоит очень дорого.
  2. Работодатель [вынужденно] оплачивает ваши косяки, баги, бездельничанье, обучение, ликбез.
  3. Работодателю интереснее оплачивать не вышеперечисленное, но результативную и эффективную работу.
  4. Работодатель хочет нанимать разработчиков, которым может дать задачи не только настоящего, но и будущего.
  5. Работодатель уже сейчас хочет некоторую гарантию того, что вы умеете и любите учиться, знать, осваивать «ненужное», что вы видите перспективу.
  6. При прочих (каких?) равных к будущим проблемам больше готов тот разработчик, что знает и умеет больше уже сейчас.
  7. Рынок готов платить за таких разработчиков — достаточно посмотреть актуальные вакансии.

Безусловно, рынок платит и за тех, кто знает меньше. Платит, впрочем, тоже меньше. Часто очень меньше. Подумайте, возможно, всё не просто так.


PS. От поднятой проблемы легко увернуться, обвинив работодателя в нежелании оплачивать пере- и доквалификацию разработчика. Мол, нанимали как питониста, а сейчас вам джавист понадобился, так мне месяц по ночам не спать? Ясен пень, такие случаи оплачиваются. Если нет, бегите, вас обманывают. Эссе же о вечном споре: какие фундаментальные знания нинужны. Какие структуры данных не надо помнить. Какие алгоритмы выбросить из головы. Какие архитектуры, определения, математики, логики, факты считаются лишними в голове Васи, а какие в голове Пети. Имеет ли моральное право (а если не моральное, то нафига) Аристарх Ибульевич пытать на собеседовании бедного Олежку (который в Super Duper Software Ltd ажно целый Chief Senior Developer) на тему массивов (таких квадратненьких скобочек)? И как, наконец, вся эта бойня выглядит с точки зрения презренного золота? Потому не уворачивайтесь. Подумайте.

Азы проектирования схемы данных

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

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

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

Также на фоне современности с её NoSQL следует понимать и такое: у вас нет schemaless database, оставьте этот термин маркетологам. Ещё на заре изучения таких баз в учебниках писали, что схема с database level перешла на application level. Перешла. Не пропала. А если вы с азартом используете ту же MongoDB в режиме грабьубивай, в итоге обязательно окажется, что грабилиубивали себя же. Исключений не видел, зато читал миллиард рассказов о том, как всё заканчивалось плохо.
И последнее стратегическое правило. Относится к голове. Вы проектируете контейнер для данных, который позволит удобно оперировать этими данными. Вы НЕ решаете конкретную задачу. НИКОГДА, блин, не решайте только одну конкретную задачу в этой области. Вот аналогией ща.

Дано: деревенская семья выращивает груши, нуждается в ящиках для хранения и транспортировки. Вы такой ящик проектируете. Что разумное существо прикинет?
Во-первых, делать ящик именно для груш… нет. Завтра посадят яблони, послезавтра персики. И что, устраиваем зоопарк и конкурсы проектировщиков? Помните, что источники данных для ваших таблиц / коллекций со временем будут меняться. Не кардинально, но шаг влево-вправо всегда будет. Потому так же шатайте требования, старайтесь проектировать хранение для класса (фрукты), а не для экземпляра (груши).
Во-вторых, фруктов будет много. То, что сейчас вам кажется (или по ТЗ), что ящика достаточно… ваше «кажется» значит ровно ноль. Делайте ящик с учётом следующего: груш будет миллион, яблок пара сотен тысяч, и даже два мешка огурцов сбоку. Сегодня выращивает одна семья, завтра колхоз, послезавтра корпорация (в контексте ящиков это означает, что следует предусмотреть удобство хранения ящиков на складах, транспортировку сухогрузами и т.д.). Ваше решение должно быть масштабируемым «горизонтально». Типичная и обычная ошибка проектировщика заключается в недооценке количества данных. В худшем случае это приводит к написанию приложения с нуля. В обычном случае это приводит к нагромождению костылей, лишь бы запрос работал не сутки. Проверяйте свои идеи на миллионах, десятках миллионов строк / документов. Влейте синтетические данные и доведите базу до смерти, чтобы выяснить реальный практический предел. Он же и будет пределом применимости того, что вы сделали.
В-третьих, поставьте себя на место крестьянина. Для чего ему нужен ящик? Какие операции будут проводиться в первую очередь? Поднять, поставить, перенести, утилизировать, починить. Какие операции могут понадобиться? До чего крестьянин / колхоз / корпорация могут дойти через год? А через два? Так же и с базой. Как минимум, надо учесть все базовые кейсы (тут уже зависит от вашей головы, опыта и знаний). Не должно быть проблемой отработать MIN / MAX. Не должны JOIN’ы с поставщиками яблок выполняться часами. Фруктовая сумма за пять лет не должна укладывать базу на пол. Поймите следующее: были бы данные, а запросы найдутся. То, что сейчас крестьянин не будет делать аналитические срезы по грушам, вовсе не значит, что в будущем аналитики корпорации не захотят годовых отчётов. Ваша задача в том, чтобы это уже сейчас работало быстро и правильно. Тех, кто говорит «этого не будет», к проектированию не подпускайте. Будет ВСЁ.
Резюмирую:

  • Проектировать под решение класса задач, а не задачи.
  • Проектировать масштабируемое решение.
  • Проектировать не вещь в себе, но с учётом кейсов как обычных [для всех баз], так и текущих пользовательских, так и будущих.

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

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

О скорости разработки на

Кстати, занятная штука. Я вам ща шаблоном напишу. Вместо переменных вставляйте любимые языки по желанию.
Бытует мнение, что на языке X программы разрабатываются медленнее, чем на языке Y. Мнение это в 2017 году ошибочно по нескольким причинам.
Во-первых, не нанимайте плохих разработчиков, нанимайте хороших. Хорошие разработчики пишут хороший софт быстро. Что на языке X, что на языке Y. Аксиома такая.
Во-вторых, все топовые языки стремятся к тому, чтобы типовые задачи решались быстро. К тому же стремятся сообщества, поставляя библиотеки. Если вы на языке Y можете быстро написать что-либо, скорее всего, ровно так же быстро это напишется на языке X. И наоборот.
В-третьих, быстро вы делаете не продукт, но прототип. Продукты делаются долго и зачастую доля языка в них едва ли не самая малая. То, что затем прототип выкатывается в продакшен после слабого допиливания, да ещё и продуктом называется… ну, совесть у каждого своя. Считающим иначе предлагаю найти и прочитать “биографии” известных продуктов, а не страничек по продаже котов. Познавательно.
В-четвёртых, если разница между языками X и Y в написании кода прям совсем заметная (при прочем равном), скорее всего, вы просто ошиблись с выбором языка под задачу. Глупо писать драйвера на Python’е. Глупо писать веб-магазин на asm’е.
В-пятых, задумайтесь, быть может, вы оперируете слухами и домыслами, но не собственным опытом или наблюдениями. Повторюсь, на дворе 2017 год. PHP уже похож на язык программирования (и даже шустрит местами). Java далеко не медленная. JavaScript обзавёлся серверсайдом (и тоже местами шустреньким). На C++ пишут весьма высокоуровневый код. В Python появился Unicode. А уж с помощью современных IDE можно рутинный код даже не писать, но правым мизинцем лениво подписывать.
В-шестых, стоимость разработчика в 2017 году тоже несколько ровнее относительно стоимости железа. Давайте поправлю вот это красивое “железо становится дешевле” — на самом деле “старое железо стоит дешевле нового железа”. А новое железо как стоило ощутимо, так и стоит. Внезапно. Потому после глубоких и мудрых вычислений на бумажке карандашиком вполне может оказаться, что для вашего продукта (не прототипа в 1К строк!) таки дешевле senior Petia с его языком X, а не горящий глазами энтузиаст с языком Y. Это вот если распространить “медленнее-быстрее” на стратегическую перспективу, в которой вы уже через полугодие будете лихорадочно добавлять сервера, а сервис переписывать.
Как-то так, если кратко.