Разработка с Дарьей Матвеевой – Telegram
Разработка с Дарьей Матвеевой
75 subscribers
15 photos
15 links
Этот блог про разработку на Java. Пишу про проблемы, с которыми сталкиваюсь, и их решения.
Download Telegram
Делаем репликацию базы данных.➡️
Добавляем кэш и CDN.➡️
Добавляем общее хранилище данных о сессиях - реализуем stateless-архитектуру.➡️
Развертываем систему в 2-х дата-центрах.➡️
Добавляем очереди сообщений и инструменты для логгирования, CI/CD и сбора метрик.➡️
Делаем шардирование БД.
В этом посте рассмотрим поиск заданного списка слов в миллионах документов, на основе примера задачи из книги “Cracking the coding interview”.

У нас есть миллион документов, и список слов. Нужно найти все документы, которые содержат все заданные слова. Слова в документе могут располагаться в произвольном порядке. Но слово не должно быть частью какого-то другого слова. Например, “кофе” не равно “кофемашина”.

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

https://dmatveeva.github.io/search-words-in-millon-docs/
Channel name was changed to «System Design с Дарьей Матвеевой»
Сейчас наша команда активно ищет новых разработчиков на Java, и я уже несколько недель участвую в собеседованиях.
Наблюдения:

▫️ Теперь понимаю, почему иногда, будучи кандидатом, получала вопросы, казавшиеся странными.
Например вопрос интервьюера, много ли вы писали кода на рабочем месте? Казалось бы, конечно, ведь я разработчик. Но вот например один из кандидатов сказал, что уже несколько месяцев не пишет код, а занимается задачами devops, хотя в резюме как раз указано разработчик .

▫️ Обычно наш тимлид дает несколько фрагментов кода и просит найти и исправить ошибку. И почему-то кандидаты неохотно пишут код. Большинство людей просто размышляли вслух, всего пару человек писали и исправляли. Один из них правда не приблизился к решению, но начал активно рефакторить существующие классы, из-за чего решение перестало компилироваться.

▫️И уже несколько человек сказали, что долго работали в реактивном стэке, и поэтому забыли Hibernate.
👍2😁2
Сейчас на нашем проекте идет активный перевод существующих spring boot микросервисов с oracle на postgres. Задача разработчика - адаптировать нативные запросы, затем завести микросервис локально у себя на машине и вызвать пару эндпойнтов, чтобы убедиться в минимальной работоспособности. Затем микросервис развертывается на дев стенде и передается в тестирование QA команде.
Этот процесс осложняется тем, что микросервисы часто имеют множество зависимостей от других микросервисов, и чтобы запустить один, нужно запустить несколько других.
И вдобавок, не все сервисы содержат юнит-тесты.
Поэтому нужно было писать довольно много тестов. И очень удобно оказалось запускать их лишь для репозиториев с нативными запросами, не поднимая весь контекст спринга:

1. К тестовому классу добавила аннотацию DataJpaTest (вместо SpringBootTest, которая поднимает весь контекст)
2. DataJpaTest использует embedded in-memory БД. Чтобы подключиться к нужной базе, использовала AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
3. Ну и ActiveProfile("test"), чтобы Spring Boot подхватил параметры подключения к базе из профиля test в test-application.yml

И когда нативные запросы отлажены с помощью такой конфигурации, для тестирования эндпойнтов использую MockMvc.
А в планах разобраться с WireMock, чтобы мокировать запросы к другим сервисам, и, соответственно, избавиться от необходимости дополнительно их развертывать.

#рабочее
3👍1🔥1
Продолжаю заметки по миграции spring boot микросервисов с oracle на postgres.
Во время адаптации миграции несколько раз сталкивалась с особенностями конвертации полей различных типов в двух БД.
Вот несколько примеров:

✔️ В oracle в нативном запросе есть джойн по колонкам с типами varchar and number.
Например:
create table employee ( id number )
create table tasks ( id number, employee_id varchar )

select * from employee e join tasks t on e.id = t.employee_id;


Oracle неявно делает конвертацию to_number(t.employee_id)=e.id, и если в таблице employee колонка employee_id содержит только строки, которые можно конвертировать в число, то запрос отработает нормально. Но postgres выдаст ошибку, и для решения нужно будет явно привести один тип к другому.

✔️Изначально в oracle в таблице БД есть колонка с типом number, а в коде, в сущности hibernate, она маппится на поле с типом String. В postgres колонка мигрирует с типом bigint. При работе приложения, oracle спокойно делает конвертацию, а postgres выдает ошибку на несоответствие типов.
Решение - заменить тип поля в сущности на Long.
Чуть было не пропустила эту ошибку, т.к. на первых порах писала тесты лишь для тех методов репозиториев, где объявлены нативные запросы. А она обнаружилась случайно как раз для сущности, для которой нет таких методов. После этого начала писать тесты вообще для всех сущностей и отловила не одну такую ситуацию.

✔️ В oracle в таблице БД есть колонка с типом varchar, которая маппится на поле с типом boolean. Предполагается, что в БД значения колонки 0/1.
Опять же, oracle конвертирует, а для корректной работы в postgres, нужно добавить аннотацию @Type(type="org.hibernate.type.NumericBooleanType") на поле сущности.

#рабочее
🫡3
Продолжение заметок по миграции spring boot микросервисов с oracle на postgresql.

1. Конструкция limit в postgresql заменяет подзапрос с аналитической функцией row_number в oracle.

Postgresql:
select product_id
from product
order by create_date limit 1

Oracle
:
select product_id
from (
select product_id, row_number() over (order by modify_date) as rn
from product
) t
where t.rn=1


2. Склейка строк через || в postgreql не null-безопасна в отличии от oracle. Если один из аргументов is null, то вся строка превратится в null. Поэтому лучше использовать функции concat и concat_ws.

3. Неочевидные ошибки вида Error near 'type', Error near 'precision'
Оказалось, что type и precision - это ключевые слова в postgresql, и при использовании их в качестве алиасов требуется указать as.

4. Insert и not null поля.
Cоздание сущности employee (через hibernate) работало в oracle, а в postgresql стало падать с ошибкой, что не заполнено обязательное поле is_retired.
Оказалось, что в oracle поле в таблице employee было объявлено с конструкцией on null, а в postgresql мигрировало без него, т.к. нет прямого аналога:

Oracle:
create table employee (
is_retired numeric default on null 0 not null
)

Postgresql:
create table employee (
is_retired numeric not null default 0
)

А если в postgresql явно передается null, то это переопределяет default.
В итоге пришлось в коде явно прописать дефолтное значение для атрибута isRetired.

#рабочее
🔥4👍1
https://dmatveeva.github.io/sql-relational-theory-1/

В статье – обзор первой главы книги “Sql и реляционная теория” Дж. Дейта.

Что такое реляционная модель и зачем она нужна разработчику?

При изучении sql реляционная модель обычно упоминается мимоходом, а основной упор делается на изучение языка sql, или даже какого-то его диалекта, например для oracle. Между тем, SQL и реляционная теория - не одно и то же, а профессионал в области баз данных должен знать реляционную теорию, т.к. вся область знания об управлении базами данных построена на ней. Разработчик может использовать БД разных вендоров, различные диалекты, но базовые принципы всегда останутся те же самые.
👍21