Как стать автором
Обновить

Как я спас несколько жизней оптимизацией и немного о работе в Zeptolab

Время на прочтение30 мин
Количество просмотров38K
Всего голосов 56: ↑50 и ↓6+44
Комментарии62

Комментарии 62

Сможете угадать, чем один кандидат отличался от остальных?

«model_handler.cpp» архитектурным мышлением?
Хорошее архитектурное мышление было не только у этого кандидата
Надо было добавить в статью голосование за лучший код :)
>Хорошее архитектурное мышление было не только у этого кандидата
Может у кандидата и было архитектурное мышление, но код его вызывает ужас. Хочется взять и переписать.

Считаю также, что при написании Zeptolab-овского кода (был знаком с ним не понаслышке) «хорошее архитектурное мышление» применялось чуть чаще чем никогда, а во фреймворке в ряде мест было UD по стандарту.
Но ведь главное, что компилятор хавает и все работает :)
UD UB
Дмитрий, бесспорно, ошибки в коде у нас есть. Мало того, я думаю, что в некотором количестве они будут в коде компании всегда. Но в то же время я считаю, что качество кода и технических решений у нас — на высочайшем уровне, и оно только повышается от проекта к проекту.

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

Про свое время работы в Zeptolab помню все до мельчайших подробностей и с ужасом вспоминаю до сих пор.
Но было и прекрасное: например, холодильник и шкаф с едой. Они настолько волшебны, что больше месяца не позволяли мне уволиться :)
Я знаю, чем точно выделяется один файл — в Game.cpp есть читаемые комментариии

P.s. а еще бросается в глаза код-стиль, но я не на С++
кандидат — Game.cpp? мне он отличился даже не комментариями, а тем, что все процедуры на страничку умещаются + стиль
Только у одного комментарии к коду.
В самом первом, который на Glut, тоже есть комменты (вероятно, кодировка попорчена).

Но тот, который Game.cpp, и вправду очень неплохо откомментирован: методы короткие и простые — не откомментированы в стиле «а здесь мы в переменную c запишем сумму переменных a + b», а в более сложных — комментарий присутствует.
кодировку поправил, спасибо
Имена методов неудачные.
Тот же откомментированный «IsLevelRunning» делает не то, что написано в его имени. Это скорее «VerifyIsLevelsRunning» или как-то так. Если бы имя было правильное — комментарий был бы не нужен.
Давайте прикинем, чуть-чуть:
ЕслиУровеньЗапущен
ПроверитьЕслиУровеньЗапущен

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

В том же ruby можно юзать "?" в именах методов и там считается хорошим стилем методы возвращающие true/false запаковывать в имена типа «empty?» тут такой возможности как я понимаю нет, поэтому используется вопросительный стиль IsBlaBla?, но без знака '?'
Вообще Krypt прав, так как метод совсем не отвечат принципу Single Responsibility, что чревато сложной расширяемостью и прочими недостатками. Если я вижу метод IsXXX, это значит, что метод проверит состояние и вернет результат, больше ничего.
Тут же корректным (да и то не полностью) названием было бы UpdateRestartTimerAfterRestartLevelIfNeedAndReturnIsLevelRunningState(), некрасиво как-то.
Даже комментарий не зря автор кода оставил, так как метод внутри непрозрачный и название несоответствует действию.

Код метода, чтобы не скроллить по многу раз к классу Game.cpp
//Внутри управляем рестартом, а наружу выдаем текущее состояние уровня (false - на паузе)
bool Game::IsLevelRunning(float dt) {
    if(wantRestart) {
        if(restartTimer < 0.0) {
            if(isLevelRunning) {
                Restart();
                wantRestart = false;
            }
        } else {
            restartTimer -= dt;
        }
    }
    return isLevelRunning;
}
Я с тобой абсолютно согласен на все 146%, но согласись что твой коммент и Krypt всё же сильно разные и именно его VerifyIs от Is ничем не отличается кроме длины, что в принципе не имеет смысла.
Да, я наверное вник в суть вашего спора лишь поверхностно, потому и мой комментарий такой.

К тому же, не знал про такую интересную особенность ruby, спасибо.
Во втором тоже есть
Game.cpp — нет одинаковых кусков кода, во всех остальных увидел, что половину можно вынести в функции)
Так как спасли жизни то?

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

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

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

Если это время потратить на игровой процесс, оно не будет бесцельно прожитым :)
Хм, забавно.
Автор model_handler знает про дублирование констант при компиляции и поэтому завернул их в namespace. Но ведь это cpp-файл, он не будет include-ится много раз. Может это кто-нибудь объяснить мне, новичку в C++, зачем?
Безымянные namespace нужны, чтобы символы не «торчали» наружу этого модуля трансляции.
Для этой же цели можно использовать ключевое слово static. Однако, у него есть еще несколько значений, поэтому рекомендуется все-таки использовать безымянные namespace.
namespace-scope константы имеют internal linkage по-умолчанию, если нигде не имеется extern declaration на них, так что это лишнее.
Относительно кандидатов — зависит от того в какую сторону «отличается» кандидат, в выгодную или нет. Я каждое решение могу выделить на фоне остальных:
1. Напоминает мне о JS напиханностью кода в одну строчку.
2. 100% студент или школьник («лабораторную работу» напоминает)
3. Python стиль — подчëркивания в начале имени переменной и конструктор инициализирующий как-то слишком много всего (не характерно для Python, но что-то есть).
4. Ruby? — не могу описать впечатление, скорее просто из-за вложенности и использования лямда-функции
5. Сишник, который больше всех похож на С++, но в последнем методе сдался и написал на С (указатель на list) :)
Game.cpp. Намного лучше знает о C++11. Это видно по использованию: использование генератора случайных чисел из STL(это лучше rand), auto, кортежи, лямбда функции.
А про remove_if не знает, и auto можно было использовать более эффективно.
Похоже, что это новый вариант вступительного задания от zeptolab)
Про каждого кандидата из перечисленных можно сказать, что он что-то знает лучше или хуже остальных. Но один из кандидатов отличается в реальном мире от остальных. Подсказка: образование и возраст всех кандидатов примерно одинаковые.
Девушка? =)
Бинго! Осталось найти исходник
Склоняюсь к Game.cpp, поскольку девочки более опрятные чем мальчики как и этот исходник
Второй?
да
Неужели стиль комментариев и орфографические ошибки ее выдают? :)
Семантически тоже есть интересные отличия
Нет никакой последовательности. Функции есть написанные слитно и через подчёркивание, с маленькой и большой буквы. Где-то отступы одни, где-то другие.
Это хороший аргумент, если не хочется никого обидеть.

Код отличается общим невысоким качеством: куча глобальных переменных, классы с открытыми данными, единственный const на весь приведенный код.
Как намекнули на пол — через воспоминание сразу подумал на искомого автора\
//////если удалено 4 маленького-создать новый большой/////
    bool create_big=1;

 glClearDepth( 1.0f );              // Разрешить очистку буфера глубины

/////////корабль столкнулся-игра закончилась/////////
            if ((depth[0]!=1)||(depth[1]!=1)||(depth[2]!=1))	
                game_end=1;

Все комментарии очевидны.
Хотел сказать, не хватает только init // Инициализация, но тут есть:

int main(int argc, char **argv)//Главная часть

«для полета коробляб» — не очень-то грамотная и внимательная девушка.
На мой взгляд, по одной опечатке не стоит судить так строго
//////если удалено 4 маленького-создать новый большой/////
Имея синдром острого перфекционизма, очень болезненно воспринимаю тире, не обрамленное пробелами.
Кроме того, дико режет глаз «непостоянство» форматирования кода, например в списке параметров при вызове функции:

glVertex3f( 0.0,0.0, 0.5f);


Левая скобка отделена пробелом от параметров, правая — нет. После первой запятой нет пробела, после второй — есть.
Потому что это классика разработчика, а не кодера-задрота.
Простой, понятный код, АЛГОРИТМА для команды
Именно такого плана программистов и нанимает google.
Один из кандидатов — девушка и в коде это как-то просматривается. Я wannabe-программист для Arduino, но, полагаю, что этот вывод следует из ваших слов.
Единственный человек включает свои файлы через #include <>, очевидно он знает про флажок компилятора -I, возможно умеет пользоваться системами сборки.
Game.cpp — какой-то код красивый, в смысле форматирования. Плюс комментарии, которые туда органично вписаны.
З.Ы. В код не вникал, я полугуманитарий.
Это на грани индусского кода:
if (Logic::IsInside(*(asteroid->GetPoints()), shot->GetCoord()))
    return true;
else
    return false;

Вместо:
return Logic::IsInside(*(asteroid->GetPoints()), shot->GetCoord())
Я с вами согласен, но есть противоположное мнение у некоторых уважаемых людей

http://avva.livejournal.com/2633281.html
</necromant mode>
Game.cpp мне наиболее симпатичен. Сразу выделяется на фоне остальных.
Сложно считать идеальным хотя бы одно решение.
Везде есть плюсы и минусы.
Что удивило что только в 2х решениях в цикл апдейта передается FrameDeltaTime. (без этого сложно делать такое как «пауза», «ускорение»\«замедление» игры).
И только в одном решении используется фиксированный шаг для апдейта. (В принципе можно без него — но сложно задачи для расчета непрерывной коллизии будет выше и просмотрев мельком код я нигде этого в полной мере не заметил).
В целом именно по коду положительно выделяются 2 решения. Но и там и там есть мелкие придирки.
В идеальном вариенте в главном цикле не должно быть аллокаций — те если вдруг геймдизайнер или художник захочет увеличить кол-во объектов — игра может потерять плавность. (ну и вообще удаление за линейное время это странно!).
Хотя я с С++ дружу не очень, но предпочтение отдал бы Game.cpp —
  • Нету magic numbers
  • Нету лишних include блоков
  • Используются возможности С++11
  • Методы краткие, в них все понятно
  • Приятный code-style, все четко и красиво
Второй кандидат. Это С программист. Глобальные переменные, классы — которые не классы, а примитивные структуры с публичными данными (попытки написать методы не в счет), и все написано функциями.
Мой взгляд, далекой от программирования девушки:
Первый — я хз что это, ни чего не поняла и читать сложно = «дочитала до конца строки забыла что начало было»… и это
Второй — кандидат явно девушка, по количеству слешей заметно… «и маленького» и типа «нарисовали пулю» мужчины, такое в комментах использовать не будут. Код не аккуратный, на мой взгляд грязноват. И это const float Pi=3.14159265358; мне кажется не правильно…
Третий — лучше, чем предыдущий но стиль страдает, но тоже страдает длинннннными переменными или чем там… вообщем ну так се…
Четвертый — молодец, приятно читать, даже ссылка на стак есть.
Кроме 2 и 4 все используют std::(что-то там)… я честно прогуглила, это вроде из плюсов, а плюсы меня пугают)
Про девушку угадали верно! А как же пятый кандидат?
Пятый видимо давно фрилансит), потому что код без пояснений, явно не в команде. И вот это убило мой мозг:
bool ModelHandler::withinBoundaries(const ObjectPtr& obj) const {
    return (obj->x() > (0 - _worldWidth * 0.1) && obj->x() < (_worldWidth * 1.1)
            && obj->y() > (0 - _worldHeight * 0.1) && obj->y() < (_worldHeight * 1.1));

мне кажется не культурно такие записи не пояснять, это как… «о дивный новый мир», там такой же слог.
Такие, наверное, да. Но для определенного кода нужен определенный уровень опыта и владения.
К примеру, следующий код особенно нет смысла комментировать, он от этого не станет понятнее, тем не менее такой код можно часто встретить в библиотеках типа libstdc++/libc++/boost.
template <typename It, typename Mapper>
struct map_iterator : std::iterator<
	typename It::iterator_category,
	std::remove_reference_t<apply_t<It, Mapper>>,
	std::ptrdiff_t,
	std::add_pointer_t<std::remove_reference_t<apply_t<It, Mapper>>>,
	apply_t<It, Mapper>>
{
	/// ...
};
Код вполне очевиден, если прочитать названия метода и переменных. Если убрать лишние скобки и отформатировать нормально, то вполне ничего:

bool ModelHandler::withinBoundaries(const ObjectPtr& obj) const {
    return -0.1 * _worldWidth  < obj->x() && obj->x() < _worldWidth  * 1.1 &&
           -0.1 * _worldHeight < obj->y() && obj->y() < _worldHeight * 1.1;
}


>например, про дерево отрезков, которое он же и независимо открыл одним из первых в мире и первый в России

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

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

А Михаил крут и по большому количеству более достоверных причин)
Да, конечно, имеется ввиду независимое переоткрытие. Ответ Михаила:

По моим сведениям в русскоязычной среде олимпиад по программированию эта структура данных не была известна примерно до 2000-го года. Я переоткрыл ее, применив впервые в 2000-м году, примерно тогда же сообразив про применения для групповых обновлений. Рассказав об этом Максиму Бабенко, получил отзыв, что ему такой подход раньше не встречался. Позже, на школьных сборах в Малоярославце обсудил первое применение дерева отрезков с Андреем Лопатиным, он тогда указал, что они начали его применять чуть позже (и по-моему тоже самостоятельно открыли).

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

Зарегистрируйтесь на Хабре, чтобы оставить комментарий