Вот уже на протяжении нескольких меясцев я занимаюсь своим хобби проектом параллельно с работой и наконец закончил его создание и решил поделиться им. Знаю что на пикабу не любят рекламу поэтому упомяну что проект о котором я рассказываю абсолютно не коммерческий и думаю еще очень долго им не будет.
Данный пост будет в формате такой небольшой истории: о том как у меня родилась идея, в чем был ее смысл, как я сделал мобильное приложение которое получало воторженные отзывы и имело уже хороший трафик, как я его потерял, и теперь возродил заново.
Бесплатный курс по Java.
Примерно пару лет назад, когда я еще заканчивал университет и думал о будущей работе, у меня возникла идея сделать обучающее мобильное приложение, которое охватит актуальный roadmap по Java бекенд-разработке – и подготовлюсь к собесу, и сделаю что-то полезное, двух зайцев одним выстрелом, так сказать.
Приложение должно было стать эдакой шпаргалкой по всему roadmap: короткие уроки, в каждом из которых без воды отражается суть того или иного класса, функции и т.д., с примерами, каждый из которых показывал бы конкретный реальный кейс применения технологии. То есть я не хотел делать утомительные лекции, или сухую документацию. Мне хотелось создать пояснения для себя с минимумом текста, но максимально отражающие суть, насколько это возможно, при этом сохраняя стилистическую грамотность и достаточность пояснений – ведь это потом будут читать люди. То есть это должны были быть скорее не лекции а уроки чтобы если чтото забыл быстро перечитать и уловить суть.
Ну вот, например — все знают, чем отличается абстрактный класс от интерфейса, это легко найти на любом сайте. Но вот полностью понять, когда использовать интерфейс, а когда абстрактный класс, чтобы в процессе разработки не возникало вопросов, – уже сложнее. Мне хотелось выписать все возможные кейсы, когда пригодится одно, а когда другое, и отразить это в коротких примерах. Чтобы потом, готовясь к собесу, не искать это долго на StackOverflow и подобных ресурсах.
Несколько месяцев я тщательно шерстил подборки вопросов на собеседования, различные форумы, чтобы разобраться во всем необходимом для интервью. В итоге получилась большая подборка из 200 уроков, покрывающая весь roadmap Java-бэкенда.
Java Backend Roadmap
И сделал я их именно такими, какими хотел: в каждом уроке – короткое объяснение, когда использовать технологию, и небольшой пример, отражающий это.
Вот, например, как я объясняю, когда а процессе разработке разработке может возникнуть необходимость создать абстрактный класс:
Пояснение когда может пригодиться абстрактный класс в Java.
А после – пример, отражающий это (приведен фрагмент, так как целиком он не вместится):
Пример когда может пригодиться абстрактный класс в Java.
Да, небольшая фишка моих туториалов – комментарии немного объемнее, чем обычно в примерах кода в интернете. Но это просто потому что я считаю, что пояснения прямо в коде помогут лучше понять материал.
Поскольку долго вникать в мобильную разработку я не хотел, решил быстро собрать приложение на FlutterFlow. Примерно за неделю справился и выложил. Выглядело оно так:
Мое обучающее приложение: Java бекенд от А до Я
Для получения первых отзывов есть два пути: либо реклама, либо бесплатно размещать ссылки на своё приложение на популярных ресурсах. Второй вариант занял бы слишком много времени, поэтому я решил инвестировать в рекламу. К счастью, результаты не заставили себя долго ждать — почти сразу пошли положительные (а часто даже восторженные) отзывы. Вот некоторые из них:
Отзывы о приложении
Рекламу мне удалось настроить довольно эффективно: стоимость скачивания в среднем была меньше двух рублей, а CTR – хорошим. В общем, было и недорого, и приятно осознавать, что делаю что-то полезное.
Но, к сожалению, счастье длилось недолго. Случился Гугл:
Печалька :(
В письме написали что-то типа "вы забанены по пунктам 8.3 и 10.3 нашего соглашения и бла-бла-бла... в общем идите н****" :). Разбаниться невозможно. Немного погрустил, конечно, но основной целью было мое обучение, так что пережил. Говорят, такая проблема возникает, если Google находит связанный с твоим аккаунтом ранее заблокированный аккаунт, но я ни разу в жизни не видел другого. Гугл есть Гугл – знаю, что он банит аккаунты пачками просто потому, что "ему что-то показалось", а что именно – не скажет. Вывод: Гугл – зло, ребята :) Что тут еще сказать не знаю.
Через пару лет захотелось снова выложить весь материал, немного его отредактировав, но уже в формате сайта, а не приложения.
Думаю много кому будет полезно, ведь бесплатный, структурированный ресурс покрывающий весь Java-бэкенд найти в интернете наверное не так просто, тем более который глубоко поясняет сложные темы типа:
"Зачем нужен Spring Framework и почему он стал настолько прорывным в 2000-х?"
"Как Spring работает внутри и какую роль играет DispatcherServlet?"
"Абстрактные классы vs Интерфейсы"
"Внутренний класс vs Статический класс"
"Уровни изоляции транзакций"
Различные паттерны проектирования
...и многое другое. Ресурс даже затрагивает DevOps и объясняет Docker – опять же, коротко, ясно и с примерами.
Еще раз подчеркну: текущий материал на сайте не будет продаваться. Если когда-нибудь и появится монетизация, она не коснется этих уроков и будет не скоро. Заглядывайте, кому интересно: CodOrbits.com. Надеюсь, поможет в подготовке.
На будующее у меня довольно много планов касемо этого проекта, хочу добавить задачи, тесты, возможно некий эмулятор real-time собеседования, хочу добавить целый раздел с разбором типичных задач по HashMap которые есть на любом интервью по Java, также раздел с алгоритмами хочу добавить и многое другое.
В сайт вложено много сил. Дизайн — кастомный. Как видите, старался сделать его современным и приятным. "Modern", как это у нас в русских деревнях говорят 😊. На написание и оформление двухсот уроков на страницах сайта тоже ушло немало времени — нейросетки с такой задачей пока адекватно спарвиться не смогут. В добавок в процессе разработки сайта открывал для себя Next.js, ведь фронтенд сайта построен именно на нём.
Буду очень благодарен за любой тёплый отзыв. Если появятся вопросы — можете смело написать мне через форму или почту на сайте.
Буду рад, если мой проект хоть немного поможет вам на пути к успеху. Желаю всем продуктивной учёбы и крутых карьерных достижений! Пока-пока 👋
Назрел такой вопрос. Сейчас нейросеть хорошо пишет код. Ответьте мне честно, есть ли те, кто официально работают и зарабатывают деньги, работая java разработчиком, которые просто просят нейросеть генерировать код и таким образом спокойно работая? То есть практически не прикладываю усилия.
...которая работает на первых Android-смартфонах в мире, компьютерах из 90-х и даже Mac'ах! Часть 2.
Иногда у меня лежит душа просто взять и написать какую-нибудь небольшую игрушку с нуля, без использования готовых движков. В процессе разработки я ставлю перед собой интересные задачки: игра должна весить как можно меньше, работать на как можно большем числе платформ и использовать нетипичный для меня архитектурный паттерн. Недавно я начал писать ремейк классических «танчиков» и в рамках серии статей готов рассказать о всех деталях разработки трёхмерной игры с нуля в 2025 году. Если вам интересно узнать, как работают небольшие 3D-демки «под капотом» от написания фреймворка до разработки геймплея — жду вас под катом!
❯ Предисловие
Ещё в начале этого года, мне взбрело в голову проверить насколько концепция «Write once, run anywhere» правдива. Все мы знаем, что Java достаточно обширно используется в Enterprise-секторе по типу банков, Android-гаджетах в качестве языка, на котором написано около 80% системы и даже в смарт-карточках, куда входят привычные нам SIM и банковские карты.
Изначально я хотел написать игру, которая работала бы не только на самых первых Android-смартфонах в мире, но ещё и на ретро-кнопочных телефонах, и при всём этом была 3D. В течении недели, я успел написать некоторые наработки для трёхмерной гоночки с примитивной физикой на основе «линий»:
В игре был мультиреднер для M3G и MascotCapsule... не хуже игр Fishlabs :))
Но затем я понял, что лишаюсь очень многих фич языка. Дело в том, что игры для Java-телефонов писались не столько на самой «джаве», сколько на её своеобразном диалекте. В мире C/C++ такой подход принято называть «C с классами», но в случае Java - подход заключался в написании большей части логики в одном-двух классах для улучшения производительности игры. Наследование, полиморфизм и абстракции на кнопочных телефонах использовать не рекомендуется. Кроме того, версия JDK в кнопочных телефонах была на уровне 1.3 — а значит, никаких дженериков и иных полезных фишек Java.
Про разработку игр для кнопочных телефонов я писал отдельную статью. Дабы не отвлекать вас от прочтения этой, ссылку оставлю в закрепленном комментарии :)
По итогу я решил сфокусироваться на относительно свежем HTC Dream — первом серийном Android-смартфоне в мире, который вышел в далёком 2008 году с Android 1.0 на борту. В нём используется уже не JVM, а своя виртуальная машина Dalvik с собственным байткодом и версией JDK — 1.5, да и процессор здесь значительно помощнее, а следовательно и куда больше возможностей для разработки!
Поскольку игру я разрабатываю и отлаживаю на ПК, у меня также есть отдельный билд и для ретро-компьютеров с GPU из 90-х и нулевых. И в рамках статьи, мы, конечно же, сделаем с вами практические тесты!
❯ Рендер
В первой части мы с вами закончили на том, что написали основу для игры — фреймворк, который включает в себя рендерер, менеджер ресурсов на слабых ссылках, некое подобие графа сцены с компонентной системой и загрузчик уровней. Но этого всё ещё мало для 3D-игры и, что самое важное, все эти модули ещё не оптимизированы.
Например, если грузить уровень «в лоб» и на каждый кубик выделять по отдельному игровому объекту, который «рисует сам себя отдельно» — мы быстро столкнемся с тем, что количество вызовов отрисовки (DIP'ов) превысит все разумные нормы. Для уровня в 16x16 блоков это уже целых 256 DIP'ов - а вкупе с другими танчиками и UI - не менее 260-270.
Самая базовая оптимизация в таком случае — это отсечение по пирамиде видимости (Frustum culling). Концепция простая: для отрисовки всего, что мы видим с вами на экране используется три матрицы размерности 4x4: мировая (позиция и поворот объекта в мире), вида (камера, позиция из «глаз») и проекции. При перемножении, они образуют так называемую WorldViewProjection-матрицу и если каждую вершину модели умножить на эту матрицу — то мы получаем её позицию в Clip-Space (или NDC) пространстве. Далее растеризатор берёт каждые три трансформированные вершины в качестве углов треугольника и отрисовывает их в рендертаргет - в нашем случае, это экран. Именно за счёт перспективной матрицы проекции и Z-буфера, мы с вами и получаем тот самый эффект трёхмерного пространства.
Если взять произведение матрицы вида с матрицей проекции и разбить её на плоскости, соответствующие каждой стороне мира (вверх, вниз, влево, вправо, вперёд, назад) — то путём выполнения простейшей проверки можно понять — находится ли точка мирового пространства в текущей позиции камеры:
Далее проверить попадает ли наш кубик или танчик в кадр — дело техники. Есть два подхода: подсчитать Bounding-sphere для модели (радиус относительно самой нижней и самой верхней вершины), или Bounding-box. В самом простом случае, можно обойтись проверкой самой нижней и самой верхней точки Bounding-box'а, однако в некоторых случаях такой алгоритм может давать сбой — например если уткнутся в «стенку» носом в игре:
publicboolean isMeshRendererInFrustum(MeshRenderer renderer) { float x = renderer.Parent.Position.X; float y = renderer.Parent.Position.Y; float z = renderer.Parent.Position.Z; Vector min = renderer.Mesh.BoundingMin; Vector max = renderer.Mesh.BoundingMax;
Конкретно в нашем случае, такая оптимизация помогает сэкономить около 100 DIP'ов и даёт неплохой прирост FPS. На Galaxy S3 с Mali 400MP4 мы получаем стабильные 60FPS, в то время как на Xperia Play — около 30... Что-ж, этого всё равно мало, тем более для смартфона, в котором GPU — кровный брат Xenos в Xbox 360...
Нарисовать 256 кубиков для GPU, даже мобильного — не проблема, особенно если они не бьют по филлрейту. Однако на классических мобильных GPU был строгий бюджет на число DIP'ов — в идеале не более 100, иначе FPS заметно просаживается даже на примитивной геометрии. Поэтому для оптимизации можно использовать технику батчинга: объединяем все кубики с одним материалом в сцене в одну большую модель и рисуем за один вызов DIPUP:
После этого, FPS поднимается до очень приятных значений - целых 45! Однако есть и обратная сторона: эта техника очень сильно бьёт не только по памяти, но и в случае динамического батчинга (танки ведь уничтожают кубики) - по процессору. Однако можно и далее оптимизировать этот алгоритм путём разбиения батчей на сетку, чтобы отсекать невидимые группы "кубиков" :)
Следующая тема — это материалы для поверхностей, описывающие внешний вид модели на экране. В первой статье я написал базовую систему материалов, которая оборачивала в себе набор рендерстейтов и парочку текстур: Diffuse и Detail. Но мало кто помнит, что ещё до шейдеров, в FFP был довольно мощный инструмент, именуемый комбайнерами. По сути, комбайнеры — это возможность задействования сразу нескольких текстурных юнитов для смешивания двух и более текстур за один вызов отрисовки.
Пример использования комбайнеров — плавное смешивание двух текстур на ландшафте с использованием маски. Эдакая вариация техники Splat mapping
Поэтому я решил написать загрузчик для материалов, описанных в простом текстовом формате по типу ini-файлов. В секции Texture описываются используемые текстуры, которые затем подгружаются из пула ресурсов, в RenderStates — напрямую указаны поля в классе Material, а в Combiners — очень-очень примитивная вариация на тему шейдеров!
Изначально я хотел сделать чтобы материалы описывали эдакий набор инструкций как «шейдеры» в Quake 3. Однако учитывая отсутствие лямбд в Java 1.5, реализация на интерфейсах (и тем более на рефлексии) не впечатлила своей производительностью и я решил сделать «программируемыми» только сами комбайнеры. Суть простая: отдельные псевдо-шейдеры реализуют интерфейс FixedFunctionShader и в теле метода onApply применяют необходимые операции над комбайнерами. При этом строго запрещается менять стейт самого графического API кроме биндинга текстур:
Затем при вызове отрисовки модели, рендерер выполняет «инструкции» для таких комбайнеров по одному и если нужно — откатывается до простой «однотекстурной» версии (драйвер GLES на Mali-400 и VideoCore IV не поддерживает комбайнеры, несмотря на то, что спецификация требует их поддержки). Получается довольно шустро:
if(GPUClass.QualityLevel >= com.monobogdan.engine.GPUClass.QUALITY_LEVEL_NORMAL) { for (int i = 0; i < Material.COMBINER_STAGE_COUNT; i++) { // Reset combiner state glActiveTexture(GL_TEXTURE0 + i); glDisable(GL_TEXTURE_2D); }
for (int i = 0; i < material.Shaders.length; i++) { Material.ShaderInstance instance = material.Shaders[i];
glActiveTexture(GL_TEXTURE0 + i); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); glEnable(GL_TEXTURE_2D); instance.Shader.onApply(material, i, instance.Params); } } else { // Single texture fallback for very slow GPU's glActiveTexture(GL_TEXTURE0); setState(GL_TEXTURE_2D, material.Textures[0] != null); material.Textures[0].bind(); }
Наполовину кирпичный танк — видели ли вы когда-нибудь такой камуфляж? :)
Следующая тема — рендеринг текста. В более ранних статьях я обычно не парился над демками и просто рисовал текст нативными средствами системы в текстуру, а затем рисовал полноэкранный квад. Такая методика работает шустро на смартфонах, но очень тормозная на ПК и более того, такая текстура занимает слишком много VRAM! Однако чаще всего я использую так называемые битмапные шрифты, которые состоят из атласа — текстуры с «запеченными» буквами и информации о том, где какой символ в ней находится. Для генерации таких шрифтов я использую утилиту BMFont, а сам код рендеринга получается очень простым:
publicvoid drawString(BitmapFont font, Vector color, float x, float y, String str) { if(font == null) thrownew NullPointerException("font was null");
if(str == null) return;
int sz = font.Size / 2;
for(int i = 0; i < str.length(); i++) { char chr = str.charAt(i);
В целом, далее особо оптимизировать и нечего для рендерера. Инстансинга в FFP нет, шейдеров — тоже, а рендер идентичный и на Android, и на ПК. Поэтому имеем что имеем!
❯ Аллокации
Однако когда я начал отлаживать игру на смартфонах, я заметил резкие просадки кадров и абсолютно нестабильный FPS. При этом характер лагов был константный: раз в 2-3 секунды просадка в 20 кадров. Заглянув в logcat, я обнаружил что Dalvik постоянно вызывает GC (сборщик мусора) и блокирует все потоки на невероятные 16мс — даже для простейших объектов в «куче»! В зависимости от устройства, Dalvik выделяет от 8 до 32Мб памяти для каждого приложения - что очень немного!
В первой статье я рассказывал о том, что большинство объектов у меня мутабельные и предполагают аллокацию не в update/draw, а в конструкторе компонента. Это касается векторов, матриц и иных примитивных классов для различных расчетов — ведь в отличии от .NET, в Java нет Value-типов, которые можно выделить на стеке, кроме примитивов. Например, если в C# написать такой код для сложения двух векторов:
struct Vector3 { publicfloat X, Y, Z;
public Vector3(float x, float y, float z) { X = x; Y = y; Z = z; }
publicstatic Vector3 operator +(Vector3 a, Vector3 b) { returnnew Vector3(a.X + b.X, a.Y + b.y, a.Z + b.z); } }
...
Transform.Position += Velocity;
То из-за того, что Vector3 — простая структура без ссылок на управляемые объекты, которая не требует контроля от GC, рантайм .NET выделит её на стеке, а не в куче и автоматически удалит при выходе из скоупа метода, где она использовалась. Если попытаться сделать такое в Java:
public static Vector3 add(Vector3 a, Vector3 b) { returnnew Vector3(a.X + b.X, a.Y + b.y, a.Z + b.z); }
То мы получим аллокацию для каждого объекта, вызывающий этот участок кода на каждый кадр. И когда придёт время вызывать GC — он обязательно тормознет игру и вызовет огромные фризы, прямо как в Minecraft на ПК. Главный нюанс здесь в том, что Dalvik оптимизирован под минимальное потребление памяти и поэтому начинает слишком часто вызывать GC, тормозя работу игры. В смартфонах с большим объёмом ОЗУ (хотя-бы 1Гб) таких проблем уже нет.
Но как я уже и сказал выше — мои игровые объекты и компоненты написаны так, чтобы не нагружать ни GC, ни кучу, но сборщик мусора всё равно продолжает тормозить игру, а значит нужно максимально экономить аллокации. Начав профайлить код, я обнаружил что огромное число аллокаций приходится на... итераторы! Да-да, та же самая проблема, что и в примере с векторами: даже несмотря на крошечный вес в памяти, итерации в каждом кадре засоряют хип и по итогу вызывают GC. Решение: перевести все индексированные списки на классический for:
for(int i = 0; i < GameObjects.size(); i++) { GameObjects.get(i).onUpdate(); }
// Second pass for late updates for(int i = 0; i < GameObjects.size(); i++) GameObjects.get(i).onLateUpdate();
И после этого, частота вызова GC наконец-то стабилизировалась!
❯ Ввод
Отдельный вопрос — это грамотная обработка ввода. Хочется чтобы наша игра поддерживала не только клавиатуру, но и геймпады, а на смартфонах — ещё и виртуальные джойстики. Чтобы не размазывать подсистему ввода в игре на 150 источников как в Unity, есть смысл её абстрагировать на некий виртуальный геймпад с необходимыми для игры кнопками: в нашем случае это стрелки и кнопка стрельбы.
Затем необходимо замаппить физические кнопки на наш виртуальный геймпад. Для этого, на смартфонах я сделал таблицу с маппингом, которая подходит для большинства игровых гаджетов: Xperia Play, игровых консолей на Android'е из 2012-го и даже смартфонов с аппаратными QWERTY-клавиатурами. И если захочется добавить возможность переназначения кнопок — это тоже не станет проблемой!
По итогу, у нас есть унифицированное управление на ПК и смартфонах, покататься в нашей демке можно даже на легендарной Xperia Play!
Для смартфонов без аппаратной клавиатуры, виртуальный геймпад пишется буквально за 5 минут. Главное — использовать относительные нормализованные координаты для адаптивности и учитывать Aspect Ratio устройства, который может быть разным:
Пришло время протестировать то, что мы успели с вами сделать за неделю. И сегодня в тестах участвует сразу несколько машинок: Asus eeePC 4G в роли «компьютера из 90-х», Sony Ericsson Xperia Play, iPhone 4S с нюансом и Samsung Galaxy Y Pro. Все гаджеты по своему хороши, имеют разные GPU и всех их объединяет статус легендарных.
Начинаем с SE Xperia Play 2011 года выпуска, который изначально позиционировался как игровой смартфон. По сути, Xperia Play - чуточку переделанный Xperia Pro, где QWERTY-клавиатуру заменили на геймпад, при этом аппаратная платформа почти всех "сонериков" 2011 года идентичная: чипсет Qualcomm MSM8250 с ARMv7-совместимым ядром Scorpio на частоте 1ГГц и GPU Adreno 205 (ребрендинг ATI Imageon Z430, на архитектуре Xenos), 512Мб ОЗУ типа DDR1 и 512Мб флэш-памяти. С смартфонами в те годы была такая же ситуация, как и с компьютерами в начале нулевых: прогресс был слишком быстрым и уже в 2012 году, Xperia Play не тянул многие свежие игры из-за слабенького процессора и GPU! Но в нашем случае, он показывает себя неплохо и стабильно тянет рендеринг уровня и танчика в 40-45 FPS... В играх на Unity3D, Adreno 205 таким результатом похвастаться не мог.
Переходим к iPhone 4S, который, как я уже сказал, с некоторым нюансом: это китайская реплика на Android. При этом довольно интересен тот факт, что у копии очень крутая IPS-матрица почти такого же разрешения (800x480 против 960x640), как и на оригинальном айфоне. Работает "клон" на базе чипсета MediaTek MT6515 2012 года выпуска с одним ядром Cortex-A9, работающим на частоте 1ГГц и GPU PowerVR SGX531 Ultra. Также в смартфоне установлено 256Мб оперативной памяти и 256Мб постоянной - в общем, типичный бюджетник тех лет. GPU от PowerVR - главное достоинство этого смартфона в плане гейминга, наша демка спокойно выдаёт 50-60 стабильных FPS. Я считаю что это прекрасный результат.
ERTY-клавиатурой, но и очень диковинным (и родственным Raspberry Pi) процессором Broadcom BCM21553 с одним ARMv6-совместимым ядром на частоте 832МГц и крайне необычным GPU собственной разработки VideoCore IV. Дело в том, что GPU в чипсетах Broadcom выполняет роль системного монитора и по архитектуре заметно отличается от классических видеоускорителей. По сути, это DSP с очень крутым векторным сопроцессором из-за чего его отчасти можно назвать софтрендером. Однако ранние драйвера для этого GPU были очень сырыми из-за чего большинство игр выдавали артефакты или работали очень медленно. Наша игрушка - не исключение, всего лишь 20 FPS при 240x320...
Переходим к довольно необычной машинке: Asus eeePC 4G. Первые модели легендарной линейки нетбуков отличались очень низкой ценой, довольно слабым и прожорливым процессором Celeron M 353 на архитектуре Dothan (прямой поток Pentium III Tualatin) и частоте 900МГц, встроенной графикой Intel GMA900 с поддержкой пиксельных шейдеров 2.0 и довольно небольшим объёмом ОЗУ в 512Мб типа DDR2. Здесь я проводил тесты на JRE 1.7 - и получил почти 60 FPS... за вычетом того, что раз в 3-4 секунды я получаю микрофризы и нагрузку на процессор в 80%. Однако сама JRE здесь не причём: такая высокая нагрузка связана с тем, что у GPU нет аппаратного вершинного конвейера и поэтому вся трансформация геометрии происходит на процессоре. Такой вот нюанс:
❯ Заключение
Вот такая статья о разработке 3D-игры с нуля у нас с вами получилась. Прошлые статьи в этой рубрике я писал в стиле туториала, но в этой я решил рассмотреть конкретные кейсы и архитектурные решения. И может она не настолько простая и понятная, как статья про разработку «самолетиков» или Top-Down стрелялки по зомби, думаю своего читателя она точно нашла! Если вам интересно, с кодом можно ознакомиться на моём Github.
А если вам интересна тематика ремонта, моддинга и программирования для гаджетов прошлых лет — подписывайтесь на мой Telegram-канал «Клуб фанатов балдежа», куда я выкладываю бэкстейджи статей, ссылки на новые статьи и видео, а также иногда выкладываю полезные посты и щитпостю. А ролики (не всегда дублирующие статьи) можно найти на моём YouTube канале.
Что думаете о таком формате статей?
Очень важно! Разыскиваются девайсы для будущих статей!
Друзья! Для подготовки статей с разработкой самопальных игрушек под необычные устройства, объявляется розыск телефонов и консолей! В 2000-х годах, китайцы часто делали дешевые телефоны с игровым уклоном — обычно у них было подобие геймпада (джойстика) или хотя бы две кнопки с верхней части устройства, выполняющие функцию A/B, а также предустановлены эмуляторы NES/Sega. Фишка в том, что на таких телефонах можно выполнять нативный код и портировать на них новые эмуляторы, чем я и хочу заняться и написать об этом подробную статью и записать видео! Если у вас есть телефон подобного формата и вы готовы его задонатить или продать, пожалуйста напишите мне в Telegram (@monobogdan) или в комментарии. Также интересуют смартфоны-консоли на Android (на рынке РФ точно была Func Much-01), там будет контент чуточку другого формата :)
А также я ищу старые (2010-2014) подделки на брендовые смартфоны Samsung, Apple и т. п. Они зачастую работают на весьма интересных чипсетах и поддаются хорошему моддингу, парочку статей уже вышло, но у меня ещё есть идеи по их моддингу! Также может у кого-то остались самые первые смартфоны Xiaomi (серии Mi), Meizu (ещё на Exynos) или телефоны Motorola на Linux (например, EM30, RAZR V8, ROKR Z6, ROKR E2, ROKR E5, ZINE ZN5 и т. п., о них я хотел бы подготовить специальную статью и видео т. к. на самом деле они работали на очень мощных для своих лет процессорах, поддавались серьезному моддингу и были способны запустить даже Quake!). Всем большое спасибо за донаты!
Приветствую, дорогие жители Pikabu.ru! Я инженер-программист станков с ЧПУ. Всю свою взрослую жизнь работаю на металлообрабатывающих предприятиях. Сейчас я пишу управляющие программы для обработки изделий нефтегазовой отрасли.
Когда-то давно, в 2013 году, я пришел на завод учеником оператора станков. Тогда мне казалось, что какие-то потусторонние силы управляют этой машиной. Тяга к развитию в этой сфере росла очень быстро, интерес вызывало буквально любое изделие, которое я делал. Первое время я просто зубрил действия, которые нужно было предпринимать для обработки, так как специфика давалась с трудом. Но всё же получалось у меня всё хорошо.
Через шесть месяцев я стал «оператором станков с ЧПУ». На тот момент я получал неплохие деньги, но со временем ситуация ухудшалась. К 2015 году я уже был женат, и денег совсем не хватало на жизнь. Штат расширялся, приходили новые люди — с опытом и без. Так как я работал по сдельной системе, зарплата была мизерной.
Смотря на всё это, мы с семьёй решили переехать в Казань, так как в нашем городе нас ничего не держало, кроме родителей. На тот момент у меня была Нексия 2004 года, за которую меня всё время «булила» жена =D. Мы загрузили машину всеми своими пожитками и поехали покорять Татарстан.
Ах да, чуть не забыл... Перед выездом мы вообще не знали, куда едем — даже квартиру не арендовали. Единственное, что сделали заранее — посмотрели вакансии, какие есть в городе, и всё.
По приезду мы начали обзванивать арендодателей квартир — денег было очень мало. Даже пришлось сдать всё золото, какое было... После нудных обзвонов и просмотров квартир мы очень сильно устали: ни одна квартира не была пригодна для жилья. Но случилось чудо — под вечер, когда уже смеркалось, мы позвонили по удачному объявлению и нашли квартиру — очень приличную и за небольшие деньги. Квартира, кстати, была на улице Музыкальной. Хозяева оказались хорошими людьми.
На следующий день начали договариваться о собеседованиях. И, к удивлению, быстро нашли работу: я устроился на завод, супруга — в IT-организацию рекрутером.
Казалось бы, при чём тут вообще Java? Когда пойдёт рассказ об этом? Всё по порядку.
Через некоторое время моей супруге предложили должность в новом городе. Так как она занималась подбором IT-специалистов, её рассмотрели как кандидата и пригласили на собеседование в город Иннополис. Мы впервые тогда услышали об этом городе и начали изучать информацию по нему и были приятно удивлены. Сама мысль, что город новый, давала какую-то надежду. Оказалось, город совсем молодой, стройка шла полным ходом. По всей России приглашали IT-спецов с релокацией и разными плюшками. В итоге супругу взяли на работу, и мы переехали.
После переезда я сильно задумался: а там ли я работаю, где хочу? Всю жизнь на заводе? Не, это не про меня. И я начал искать IT-курсы с нуля. Изучая рынок, понял, что самый востребованный язык — это Java. Нашёл курсы молодого бойца Java в КФУ (Казанский (Приволжский) федеральный университет). Учёба сперва пошла довольно плавно, но со временем я заметил, что теряю фокус и не могу сфокусировать себя по полной. Постоянные вопросы самому себе и преподавателям — как это всё работает — не давали никакого результата, я чувствовал, что упёрся в стену, и никто не мог объяснить мне и поставить на путь истинный, дать конкретную базу по программированию. В итоге ничего хорошего не произошло: я потерял веру в себя, был просто полностью опустошён из-за этого. Вдобавок меня ещё и сократили с работы. Начался самый грустный период, в который любая попытка взяться за программирование самостоятельно, даже просто выучить БАЗУ — просто БАЗУ, Карл! — заканчивалась ничем. Не понимая, что происходит, я просто опустил руки и забил на это.
В итоге, не реализовав себя как IT-специалиста, и с текущей работы меня тоже попёрли — мы уехали обратно на родину.
P.S. Если увижу интерес — продолжу дальше свой рассказ.
Поздравляю, вы написали хуевый код на Джаве ) Никогда такого не было пиздеж, каждый первый спициалист с скиллбокса не даст соврать и вот опять! Ну все, Джава мертва, старый унылый кусок говна, пора выкидывать, ведь тупой рандом написал на ней говно...
Но давайте, раз уж мы тут ниибать специалисты, подумаем еще 2 минуточки, над этим ниибически ахуительным тезисом "ахахха язык_название_1 полнае гавно". Попробуем так сказать в анализ, логику, экстраполяцию даже, не побоюсь этого сложного слова.
Можно ли написать говно на ЛЮБОМ языке? Отвечает эксперт(я): ага, ващще изи. Ну тоесть гдето сложновато, так как некоторые языки и их инструментарий будут упорно препятствовать, но бля - была бы цель!
Хммммм, а можно ли написать красиво на ЛЮБОМ языке? Опять отвечает иксперт(я): ну, это конечто блять уметь надо, но вообще - да! Все языки существуют для решения определённых проблем. Некоторые узкоспециализированны, и красивые решения там требуют таки навыков, понимания области применения, и опыта. Но - сделать красиво, и местами элегантно - можно на любом языке. Даже (прости госпади) на Руби.
Я уже устал расписывать что тот же JavaScript (над которым ржут тупорылые неумехи более десятка лет, и который конечно нонче более ускоспециализирован чем его, хммм, скажем для простоты терминов "старший брат" TypeScript) можно и "типизировать", и писать надежно, модульно, и даже красиво. БЫЛО БЫ УМЕНИЕ, ДА ЖЕЛАНИЕ. Да и php, второй по цитируемости в шуточкаж долбаебами язык - уже давно умеет и в типизацию, и вообще во все на свете. И позволяет создавать реально красивый код. Но - поток идиотиков, сравнивающих вот эти пальцы (рдни языки) с жопами (другие языки), не разбирающихся ни в отм ни в другом - он блять неисчерпаем...
А по поводу конкретного примера из поста, на который я отвечаю - мне уже даже лень расписывать НАСКОЛЬКО чувак нихуя не понял ни в Джаве, ни в конкретно этой, простой в принципе иерархии классов, ни блять даже в самом ООП...
К чему я все это (ДА НЕ ПЕЧЕТ У МЕНЯ!11!!)?
Господа "шутники". Имейте ввиду, что вы создаете негативный окрас языкам, в которых ничего не смыслите. Люди "снаружи" индустрии, да и просто те кто не очень разбирается - они же ж по этим шуточкам составят мнение, и понесут его в массы...