Pull to refresh
3
0
Обидин Михаил @mrsantak

User

Send message

вполне возможна всякая фигня типа трех подряд промахов при 95% вероятности попадания.

Типичный X-COM :) Вообще забавно, что его куча народу до сих пор обвиняют в читерстве с рандомом в пользу компа на высокой сложности. При том, что там уже всё отреверсили и доказали, что читерство есть только в сторону игроку на низхких уровнях сложности.

И какой же европейский суд штрафанул amazon за то что тот работал в его стране без представительства?

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

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

Это называется "слышал звон, но не знаю где он". Спектр использования хеш функций не ограничивается криптографией. И там где стойкость хеш функции не важна, абсолютно нормально использовать MD5. Гоните в шею специалистов, которые не понимают сферу применимости инструмента в котором они "специализируются".

Dark Messiah - это и есть спин-офф. Просто когда вышла пятая часть героев во вселенной случился перезапуск (в ходе которого и исчезли все роботы) и основной игрой стали именно герои, а M&M, Dark Messiah и всякие Clash of Heroes стали спин-офом. А так Dark Messiah вполне себе каноничная часть продолжающая сюжет пятерки.

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

Если у вас нет синдрома отличника, то нифига подобного. Матан, физику и английский реально самому спокойно сдать (да и со списыванием там всё сложно). Не сдать остальные предметы надо постараться, ибо трояк вам натянут если вы хотябы пару дней подготовке выделите.

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

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

Я сам проходил пару раз Might & Magic XIII

Последняя версия - это десятка, и она уже по вселенной после перезапуска. Последняя версия M&M по "старой" вселенной - это IX.

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

Ой, да конечно. Там точно так же реализация своих интересов, которые слабо скореллированы с интересами пользователя. Может авторам интересно тулзу на вот этом конкретном ЯП/фреймворке/либе/подходе пилить, может портфолио с крутым и сложным кодом иметь, может своё ЧСВ почесать, может желание исправить фатальный недостаток существующего софта, а может и тоже бабло (которое далеко не всегда от конечных пользователей приходит, mozilla foundation и canonical тому пример). Много причин, и создание качественно ПО решающего проблемы пользователей там зачастую далеко не на первом месте. Так что не надо тут из авторов опенсорса святых на битве со злом корпораций изображать.

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

Я тут осознал что в этом примере прогон тестов и деплой занимают не просто 2 часа времени, а 2 часа времени девопса. Т.е. оно еще и не автоматизировано нихрена, но виновата в этом монолитная архитектура, да.

Видел, например, как контекст спринга минуту стартует для кода, который не будет выполняться.

Для этого боженька придумал Lazy бины :)

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

Да что угодно лучше аннотаций в Java!

Вы таки забыли про EJB до версии 3. По сравнению с той жестью не то что аннотации прекрасны, там народ с любовью xml конфиги принимал лишь бы не заниматься противоестественным сексом с этим монстром.

В случе с jooq то что вы можете генерить модель для вашей схемы базы не сзначит что вы к ней привязаны. Т.е. вы можете просто ссылаться на таблицы/колонки по именам - в таком случае вы просто потеряете типобезопасность (которая впрочем и так далека от идеала). Более того, вы можете в параллель несколько моделей держать, или, если хочется, создавать их прям в рантайме (так например мы делаем для сложных вычислимых полей). Ну т.е. штуки типа:

insertInto("Users")
        .set("id", userId)
        .set("name", name)
        .set("country", country)
        .set("role", user)

никак вас не ограничивают, вам доступны все расширения вашей СУБД, весь её синтаксис, просто sql запрос собирается не строкой, а вот таким dsl, который позволяет получить базовый комплишен в ide и минимальные проверки синтаксиса на этапе компиляции (например не получится случайно воткнуть where после groupBy и т.д.).

Нет, для ORM эти мапперы - это лишь вершина айзберга. Основная идея ORM не в том, что за вас result set мапят на ваши объекты, а в том, что вы вообюще работаете не с таблицами в базе данных, вместо этого вы работает только с объектами вашего ЯП. По-сути ORM пытается сделать вид, что у вас под капотом не какой-нибудь postgres, а некая бд в которой прям ваши дата классы лежат.

Тут 3 ключевых отличия:

  1. Вы всё еще вынуждены сами писать sql запросы, пусть и с кучей сахара.

  2. Вы всё еще вынуждены сами мапить то что возвращает либа на ваши data классы.

  3. Это всё работает только с плоскими объектами. Вытащить обхект и все его связи можно только в ручном режиме.

Я не силён в шарпе, так что примеры будут для java. По-сути в вашем примере есть 3 проблемы:

  1. Много boilerplate кода между самим sql запросом и началом фактической обработки result set'а.

  2. Маппинг результатов запроса на объекты ЯП. Индексация по номерам колонок ненадежна, очень легко ошибиться, особенно когда мы достаём звёздочку, а не конкретный набор колонок, сложно рефакторить. Нет никакой типобезопасности.

  3. Запрос в виде строки. Большие, иногда нужно формировать разные запросы в зависимости от параметров (например когда нужно отфильтровать результаты только если пользователь ввел фильтры и только по тем колонкам которые указал пользователь.)

Первая проблема в мире java решается просто, вместо сырого jdbc используем какой-нибудь spring jdbcTemplate, по-сути всё тоже самое, просто синтаксис короче:

jdbcTemplate.query("SELECT * FROM Users", new UserMapper());

Где UserMapper может быть задан как-то так

public class UserMapper implements RowMapper<User> {
    @Override
    public User mapRow(ResultSet rs, int rowNum) throws SQLException {
        return new User(
          rs.getInt("ID"),
          rs.getString("FIRST_NAME"),
          rs.getString("LAST_NAME"),
          rs.getString("EMAIL")
        );
    }
}

Проблемы 2 и 3 всё еще толком не решены.

И тут приходят более сложные библиотеки, например mybatis. В простых случая достаточно создать интерфейс типа такого:

public interface UserMapper {
  @Select("SELECT * FROM Users WHERE ID = #{id}")
  User selectUser(int id);
}

И либа сгенерит вам объект который реализует этот интерфейс и выполняет запрос. В более сложных случаях нужно писать конфиг маппера (какие колонки на акие поля объекта мапить), если запросы большие то их тоже целесообразно утащить в xml конфиг. Есть более-менее вменяемый шаблонизатор для составляения sql запросов, которые не сводятся к preparedStatement'ам. Есть библиотеки типа Spring Data JDBC, в которых вы просто создаёте интерфейс типа

interface UserRepository extends CrudRepository<User, Long>, WithInsert<User> {}

и либа опять таки сгенерит для вас объект с кучей методов. Есть довольно странный функционал который позволяет сформировать запрос на основании названия метода (т.е. если у вас будет метод selectByEmail, то либа сгенерит для него запрос типа select * from Users where Email = ?), можно самому указать запрос в виде аннотации, и т.д. В общем, всё очень похоже на уже упомянутый mybatis.

Ну и лично мой люьимец - это jooq, содержит в себе dsl на java который легко мапится в sql, т.е. вместо select * from Users where id = ? мы пишем что-то типа selectFrom("Users").where(eq("id", id)). Это прикольно, позволяет легко и безопасно прогрмано собирать запросы не боясь иньекций. Также позволяет переиспользовать части запросов. Еще можно использовать возможности языка, чтобы прикрутить синтаксический сахар к sql. Например, если вам нужно написать insert в таблицу с 10 колонками, то в класическом sql вы вынуждены сначала перечислить все колоники, а потом перечислить все значения в том же порядке, и удачи вам нигде не перепуать порядок. Тут же можно сделать insert с update-like синтаксисом:

insertInto("Users")
        .set("id", userId)
        .set("name", name)
        .set("country", country)
        .set("role", user.role)

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

insertInto(Users)
        .set(Users.id, userId)
        .set(Users.name, name)
        .set(Users.country, country)
        .set(Users.role, role)

Где класс Users - генерится во время сборки, а значит если вы переименуете колонку в бд и забудете обновить запрос, то узнаете вы это на этапе компиляции. Более того, при генерации у вас колонкам будут присвоены типы, и вы можете эти типы кастомизировать. В данном случае name может быть только типа String, userId только типа UserId, а role типа Role. И это всё будет проверяться на этапе компиляции. Тоже самое и с select запросами. Вот такой код

selectFrom(Users)
    .where(eq(Users.id, userId))
    .fetchOne(new UserMapper())

вернёт объект User и потребует вот такой маппер:

class UserMapper implements RecordMapper<UsersRecord, User> {
  @Override
  public User map(UsersRecord record) {
    return new User(
        record.id,
        record.name,
        record.country,
        record.role
    )
  }
}

где UsersRecord - это опять таки сгенерённый класс.

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

Проблема этой фразы в том, что она неявно противопоставляет монолит и подходящее решение. А это противопоставление ложно, очень часто именно монолит является оптимальным решением.

Information

Rating
Does not participate
Location
München, Bayern, Германия
Date of birth
Registered
Activity

Specialization

Backend Developer
Java