Ответ
package main
import (
"fmt"
)
func main() {
naturals := make(chan int)
squares := make(chan int)
go func() {
for x := 0; x <= 10; x++ {
naturals <- x
}
close(naturals)
}()
go func() {
for x := range naturals {
squares <- x * x
}
close(squares)
}()
for x := range squares {
fmt.Println(x)
}
}
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Вариант решения
package main
import (
"errors"
"fmt"
"os"
)
func main() {
file, err := os.Open("data.json")
if errors.Is(err, os.ErrNotExist) {
fmt.Println("File not found")
return
}
// Выполните какое-нибудь действие с файлом
defer file.Close()
}
Пишите свой вариант в комментариях
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Вариант решения
brandsMap := map[string]string{
"ford": "ford",
"audi": "ford",
"lada": "nil",
}
_, value := brandsMap["lada"]
fmt.Print(value) // true,
//value выдаст true или false, если ключ lada есть в brandsMap
Пишите свой вариант в комментариях.
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача, которая была популярна в своё время на собеседованиях в Amazon. Мы русифицировали её, но смысл остался тот же. Вам нужно продолжить последовательность.
Ответ
Вот один из возможных ответов на эту задачу. Последовательности сопоставлены буквы алфавита, закодированные в набор «П» и «К» — некоторых характеристик. Нужно найти что-то, чего в букве А три, в Б — две и т.д. Тут подходит количество прямых штрихов и кривых. Далее несложно догадаться, что букве Д соответствует, например, «ППППП», в случае её написания как на предложенном рисунке.
Последовательности сопоставлены буквы алфавита, закодированные в набор «П» и «К» — некоторых характеристик. Нужно найти что-то, чего в букве А три, в Б — две и т.д. Тут подходит количество прямых штрихов и кривых. Далее несложно догадаться, что букве Д соответствует, например, «ППППП», в случае её написания как на предложенном рисунке.
@golang_interview
Ответ
Вот один из возможных ответов на эту задачу. Последовательности сопоставлены буквы алфавита, закодированные в набор «П» и «К» — некоторых характеристик. Нужно найти что-то, чего в букве А три, в Б — две и т.д. Тут подходит количество прямых штрихов и кривых. Далее несложно догадаться, что букве Д соответствует, например, «ППППП», в случае её написания как на предложенном рисунке.
Последовательности сопоставлены буквы алфавита, закодированные в набор «П» и «К» — некоторых характеристик. Нужно найти что-то, чего в букве А три, в Б — две и т.д. Тут подходит количество прямых штрихов и кривых. Далее несложно догадаться, что букве Д соответствует, например, «ППППП», в случае её написания как на предложенном рисунке.
@golang_interview
На самом деле, не существует чётко определённого ограничения на количество запускаемых контейнеров на Docker. Тем менее, ограничение накладывает само оборудование.
Всего существует два основных фактора, которые могут ограничить число запускаемых контейнеров – размер вашего приложения и мощность вашего CPU. Если ваше приложение не изобилует функциями, и у вас есть большой запас мощности CPU, то вы можете запустить огромное количество контейнеров Docker одновременно.
✔️ Чем Docker Отличается От Hypervisor?
Опять же, ещё один вопрос собеседования по Docker для новичков, который потребует от вас знаний других инструментов для контейнеризации. Ответив на данный вопрос, вы покажете свою компетентность в сфере разработки в целом, а не только расскажете про использование Docker (что очень хорошо!).
По сути, здесь всё сводится к одной простой вещи – Hypervisor для стабильного функционирования потребует от вас обширного оборудования, тогда как Docker запускается лишь на операционной системе. Это позволяет Docker быть невероятно быстрым и выполнять задачи более плавно – в этом Hypervisor ему явно уступает.
#docker #junior #Go
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Описание:
Есть функция, которая принимает от всех модулей значение комиссии за предоставление услуг компании.
Размер комиссии может быть от 0 до 99.99
Максимальное количество знаков после запятой: 2
В базу данных записываются только целые значения, поэтому запятую приходится сдвигать на 2 знака.
Например для комиссии размером 1.5 значение в базе данных будет соответствовать 150
Работа с функцией не должна требовать каких-либо проверок перед отправкой значения.
Результат работы функции не должен требовать перепроверки со стороны модулей, т.е. возвращаемое значение всегда считается корректным.
Разработчик реализовал функцию проверки корректности ввода и преобразования вводимого значения.
Со стороны клиентов поступают жалобы на то, что вводимая ими комиссия записывается не верно или не записывается вовсе, однако все утверждают, что заполняют корректное значение с дробной частью или без.
Задание для разработчика:
Исправьте функцию проверки вводимого значения и дальнейшего преобразования для корректной записи в базу данных итогового значения.
Под данными для записи в базу данных подразумевается результат работы функции check_commission()
Задание для тестировщика:
Проверьте корректность работы фукнции изменяя входящее значение по вашему усмотрению.
В случае выявления ошибок опишите порядок действий, которые привели к ошибке.
Задание для системного аналитика: Напишите постановку данной задачи для разработчика с максимальной детализацией.
Готовое решение нужно предоставить в виде ссылки по кнопке "Share"
package main
// Импортируем библиотеки вывода и конвертации
import (
"fmt"
"strconv"
)
// Функция проверки комиссии
func check_commission(number string) uint64 {
// Конвертируем присланное значение из строки в число с запятой во временную переменную
tempValue, err := strconv.ParseFloat(number, 64)
// Если конвертация не получилась
if err != nil {
// Скажем об этом
fmt.Println("Введено не число:", number)
// И выйдем из функции
return 0
}
// Если конвертация удалась
// Умножим значение на 100, тем самым сдвинем запятую
tempValue = tempValue * 100
// Преобразуем значение в нужный тип данных
result := uint64(tempValue)
// Возвращаем корректное значение
return result
}
// Ввиду ограничений формы входящее значение от пользователя всегда в string
// Пеменная input будет эмулировать входящее значение
func main() {
// Проверяем маленькое значение
input := "0.01"
fmt.Println("Первое значение:", input)
fmt.Println("Преобразованное значение:", check_commission(input))
// Проверяем большое значение
input = "99.99"
fmt.Println("\nВторое значение:", input)
fmt.Println("Преобразованное значение:", check_commission(input))
// Проверяем если ввели не число
input = "неЧисло"
fmt.Println("\nСтроковое значение:", input)
fmt.Println("Преобразованное значение:", check_commission(input))
}
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Яндекс это же сайт, что я там буду делать?
Разговор с тимлидом команды Serverless Yandex Cloud про продуктовые исследования, фичеборды, виртуальные команды и топ-качества разработчиков.
Смотрите выпуск на YouTube канале Yandex Cloud ➡️
00:00 Приветствие
01:19 Как держать темп разработки в распределенной команде?
03:29 Про то, как работают виртуальные команды
07:50 Как получается удержать экспертизу в команде?
10:04 Про продуктовые исследования
15:04 Про работу с сообществом и custdev
19:23 Про фичеборд и голосование
23:35 Продукт для разработчиков
24:24 Про вклад стажёров в развитие продукта
28:18 "Яндекс это же сайт, что я там буду делать?" путь Андрея в Яндексе
30:45 Топ-качества разработчиков команды Serverless
35:02 Про плов и то, что объединяет
Разговор с тимлидом команды Serverless Yandex Cloud про продуктовые исследования, фичеборды, виртуальные команды и топ-качества разработчиков.
Смотрите выпуск на YouTube канале Yandex Cloud ➡️
00:00 Приветствие
01:19 Как держать темп разработки в распределенной команде?
03:29 Про то, как работают виртуальные команды
07:50 Как получается удержать экспертизу в команде?
10:04 Про продуктовые исследования
15:04 Про работу с сообществом и custdev
19:23 Про фичеборд и голосование
23:35 Продукт для разработчиков
24:24 Про вклад стажёров в развитие продукта
28:18 "Яндекс это же сайт, что я там буду делать?" путь Андрея в Яндексе
30:45 Топ-качества разработчиков команды Serverless
35:02 Про плов и то, что объединяет
YouTube
Команда Serverless в Yandex Cloud, топ-качества разработчиков
Сегодня говорим про продуктовые исследования, фичеборды, виртуальные команды и топ-качества разработчиков команды бессерверных вычислений в Yandex Cloud.
Смотрите новый выпуск подкаста "Про людей".
00:00 Приветствие
01:19 Как держать темп разработки в…
Смотрите новый выпуск подкаста "Про людей".
00:00 Приветствие
01:19 Как держать темп разработки в…
Микросервис для работы с балансом пользователей
Проблема:
В нашей компании есть много различных микросервисов. Многие из них так или иначе хотят взаимодействовать с балансом пользователя. На архитектурном комитете приняли решение централизовать работу с балансом пользователя в отдельный сервис.
Задача:
Необходимо реализовать микросервис для работы с балансом пользователей (зачисление средств, списание средств, перевод средств от пользователя к пользователю, а также метод получения баланса пользователя). Сервис должен предоставлять HTTP API и принимать/отдавать запросы/ответы в формате JSON.
Сценарии использования:
Далее описаны несколько упрощенных кейсов приближенных к реальности.
1. Сервис биллинга с помощью внешних мерчантов (аля через visa/mastercard) обработал зачисление денег на наш счет. Теперь биллингу нужно добавить эти деньги на баланс пользователя.
2. Пользователь хочет купить у нас какую-то услугу. Для этого у нас есть специальный сервис управления услугами, который перед применением услуги резервирует деньги на отдельном счете и потом списывает в доход компании.
3.Бухгалтерия раз в месяц хочет получить сводный отчет по всем пользователям в разрезе каждой услуги.
Требования к сервису:
1. Сервис должен предоставлять HTTP API с форматом JSON как при отправке запроса, так и при получении результата.
2.Язык разработки: Golang.
3.Фреймворки и библиотеки можно использовать любые.
4.Реляционная СУБД: MySQL или PostgreSQL.
5.Использование docker и docker-compose для поднятия и развертывания dev-среды.
6.Весь код должен быть выложен на Github с Readme файлом с инструкцией по запуску и примерами запросов/ответов (можно просто описать в Readme методы, можно через Postman, можно в Readme curl запросы скопировать, и так далее).
7.Если есть потребность в асинхронных сценариях, то использование любых систем очередей - допускается.
8.При возникновении вопросов по ТЗ оставляем принятие решения за кандидатом (в таком случае Readme файле к проекту должен быть указан список вопросов с которыми кандидат столкнулся и каким образом он их решил).
9.Разработка интерфейса в браузере НЕ ТРЕБУЕТСЯ. Взаимодействие с API предполагается посредством запросов из кода другого сервиса. Для тестирования можно использовать любой удобный инструмент. Например: в терминале через curl или Postman.
Будет плюсом:
Покрытие кода тестами.
Swagger файл для вашего API.
Реализовать сценарий разрезервирования денег, если услугу применить не удалось.
Основное задание (минимум):
Метод начисления средств на баланс. Принимает id пользователя и сколько средств зачислить. Метод резервирования средств с основного баланса на отдельном счете. Принимает id пользователя, ИД услуги, ИД заказа, стоимость. Метод признания выручки – списывает из резерва деньги, добавляет данные в отчет для бухгалтерии. Принимает id пользователя, ИД услуги, ИД заказа, сумму. Метод получения баланса пользователя. Принимает id пользователя.
Детали по заданию:
- По умолчанию сервис не содержит в себе никаких данных о балансах (пустая табличка в БД). Данные о балансе появляются при первом зачислении денег.
- Валидацию данных и обработку ошибок оставляем на усмотрение кандидата.
Список полей к методам не фиксированный. Перечислен лишь необходимый минимум. В рамках выполнения доп. заданий возможны дополнительные поля.
- Механизм миграции не нужен. Достаточно предоставить конечный SQL файл с созданием всех необходимых таблиц в БД.
- Баланс пользователя - очень важные данные в которых недопустимы ошибки (фактически мы работаем тут с реальными деньгами). Необходимо всегда держать баланс в актуальном состоянии и не допускать ситуаций когда баланс может уйти в минус.
- Мультивалютность реализовывать не требуется.
Дополнительные задания
Далее перечислены дополнительные задания. Они не являются обязательными, но их выполнение даст существенный плюс перед другими кандидатами.
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Forwarded from Golang
Задача разработать сервис, через который продавцы смогут передавать нам свои товары пачками в формате excel (xlsx). UI делать не нужно, достаточно только API.
Сервис принимает на вход ссылку на файл и id продавца, к чьему аккаунту будут привязаны загружаемые товары. Сервис читает файл и сохраняет, либо обновляет товары в БД. Обновление будет происходить, если пара (id продавца, offer_id) уже есть у нас в базе. В ответ на запрос выдаёт краткую статистику: количество созданных товаров, обновлённых, удалённых и количество строк с ошибками (например цена отрицательная, либо вообще не число).
Для проверки работоспособности сервиса нужно так же реализовать метод, с помощью которого можно будет достать список товаров из базы. Метод должен принимать на вход id продавца, offer_id, подстрока названия товара (по тексту "теле" находились и "телефоны", и "телевизоры"). Ни один параметр не является обязательным, все указанные параметры применяются через логический оператор "AND".
В каждой строке скачанного файла будет содержаться отдельный товар. Колонки в файле и соответствующие значения полей товара следующие:
- offer_id уникальный идентификатор товара в системе продавца
- name название товара
- price цена в рублях
- quantity количество товара на складе продавца
- available true/false, в случае false продавец хочет удалить товар из нашей базы
Наши ожидания
- язык программирования Go
- предоставлена инструкция по запуску приложения. В идеале (но не обязательно) – использовать контейнеризацию с возможностью запустить проект командой docker run/docker-compose up
- в качестве БД использована Postgres
- код выложен на github
Усложнения
- написаны тесты
- проведено нагрузочное тестирование с целью понять, с какой скоростью сервис может переваривать файлы
- реализована асинхронная схема работы, т.е. сервис принимает запрос, сразу возвращает id задания и в отдельной горутине начинает его выполнять. Клиент может узнать статус задания отдельным запросом.
ставьте ❤️, если подобный контент вам полезен
@Golang_google
Please open Telegram to view this post
VIEW IN TELEGRAM
Необходимо создать HTTP-сервис, способный ограничивать количество запросов (rate limit) из одной подсети IPv4. Если ограничения отсутствуют, то нужно выдавать одинаковый статический контент.
Требования:
язык: Go
код должен быть выложен на GitHub
ответ должен соответствовать спецификации RFC 6585
IP должен извлекаться из заголовка X-Forwarded-For
подсеть: /24 (маска 255.255.255.0)
лимит: 100 запросов в минуту
время ожидания после ограничения: 2 минуты
Пример: после 20 запросов с IP 123.45.67.89 и 80 запросов с IP 123.45.67.1 сервис возвращает 429 ошибку на любой запрос с подсети 123.45.67.0/24 в течение двух последующих минут.
Усложнения:
- покрытие тестами
- контейнеризация, возможность запустить с помощью docker-compose up
- размер префикса подсети, лимит и время ожидания можно задавать при старте сервиса
- отдельный handler для сброса лимита по префиксу
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача
Необходимо создать сервис для хранения и подачи объявлений. Объявления должны храниться в базе данных. Сервис должен предоставлять API, работающее поверх HTTP в формате JSON.
Требования
- Язык программирования Go
- Финальную версию нужно выложить на github.com (просьба не делать форк этого репозитория, дабы не плодить плагиат);
- Простая инструкция для запуска (в идеале — с возможностью запустить через docker-compose up, но это необязательно);
- 3 метода: получение списка объявлений, получение одного объявления, создание объявления;
- Валидация полей: не больше 3 ссылок на фото, описание не больше 1000 символов, название не больше 200 символов;
Если есть сомнения по деталям — решение принять самостоятельно, но в своём README.md рекомендуем выписать вопросы и принятые решения по ним.
Детали
Метод получения списка объявлений
- Пагинация: на одной странице должно присутствовать 10 объявлений;
- Cортировки: по цене (возрастание/убывание) и по дате создания (возрастание/убывание);
- Поля в ответе: название объявления, ссылка на главное фото (первое в списке), цена.
Метод получения конкретного объявления
- Обязательные поля в ответе: название объявления, цена, ссылка на главное фото;
- Опциональные поля (можно запросить, передав параметр fields): описание, ссылки на все фото.
Метод создания объявления:
- Принимает все вышеперечисленные поля: название, описание, несколько ссылок на фотографии (сами фото загружать никуда не требуется), цена;
- Возвращает ID созданного объявления и код результата (ошибка или успех).
Усложнения
Не обязательно, но задание может быть выполнено с любым числом усложнений:
- Юнит тесты: постарайтесь достичь покрытия в 70% и больше;
- Контейнеризация: есть возможность поднять проект с помощью команды docker-compose up;
- Архитектура сервиса описана в виде текста и/или диаграмм
- Документация: есть структурированное описание методов сервиса.
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Семафор можно легко получить из канала. Чтоб не аллоцировать лишние данные, будем складывать туда пустые структуры.
В нашем случае мы хотим сделать семафор, который будет ждать выполнения пяти горутин.
- Для этого просто добавим вместо обычного канала буфферизированный.
- И внутри каждой горутины положим в него значение.
- А в конце будем дожидаться, что все ок — мы вычитаем все значения из канала.
Ответ
package main
import (
"fmt"
)
type sema chan struct{}
func New(n int) sema {
return make(sema, n)
}
func (s sema) Inc(k int) {
for i := 0; i < k; i++ {
s <- struct{}{}
}
}
func (s sema) Dec(k int) {
for i := 0; i < k; i++ {
<-s
}
}
func main() {
numbers := []int{1, 2, 3, 4, 5}
n := len(numbers)
sem := New(n)
for _, num := range numbers {
go func(n int) {
fmt.Println(n)
sem.Inc(1)
}(num)
}
sem.Dec(n)
}
👇 Пишите свой вариант в комментариях
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Даны два канала. В первый пишутся числа. Нужно, чтобы числа читались из первого по мере поступления, что-то с ними происходило (допустим, возводились в квадрат) и результат записывался во второй канал.
Довольно частая задача, более подробно можно почитать тут.
Решается довольно прямолинейно — запускаем две горутины.
В одной пишем в первый канал.
Во второй читаем из первого канала и пишем во второй.
Главное — не забыть закрыть каналы, чтобы ничего нигде не заблокировалось.
Ответ
package main
import (
"fmt"
)
func main() {
naturals := make(chan int)
squares := make(chan int)
go func() {
for x := 0; x <= 10; x++ {
naturals <- x
}
close(naturals)
}()
go func() {
for x := range naturals {
squares <- x * x
}
close(squares)
}()
for x := range squares {
fmt.Println(x)
}
}
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Синхронизация – это узкое место параллельных программ. Распараллеливая алгоритмы, мы работаем с последовательными структурами данных, обеспечивая их работу примитивами синхронизации – критическими секциями, мьютексами, условными переменными (condvar); в результате мы выстраиваем все наши потоки в очередь на доступ к структуре данных, тем самым убивая параллельность.
В академической среде изучение способов реализации конкурентных структур данных, обеспечивающих одновременный доступ к разделяемым данным, привело к созданию нескольких основных направлений:
- Lock-free структуры данных;
- Fine-grained algorithms;
- Транзакционная память (transactional memory).
Lock-free структуры данных - не требующие внешней синхронизации доступа. Это неформальное, чисто техническое определение, отражающее внутреннее строение контейнера и операций над ним. Формальное определение lock-free объекта звучит так: разделяемый объект называется lock-free объектом (неблокируемым, non-blocking объектом), если он гарантирует, что некоторый поток закончит выполнение операции над объектом за конечное число шагов вне зависимости от результата работы других потоков (даже если эти другие потоки завершились крахом).
В Go есть sync.Map и пакет atomic. Но с точки зрения указанных определений, а также реализации данных пакетов - это не чистый lock-free, это просто абстрактная реализация этой модели.
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Для заданной строки найдите в ней первый неповторяющийся символ, выполнив только один ее обход.
Например,
Input:
string is ABCDBAGHC
Output:
первый неповторяющийся символ: D
Простым решением было бы сохранить количество каждого символа в map или массиве, пройдя его один раз.
Затем еще раз просмотреть строку, чтобы найти первый символ, имеющий значение 1. Временная сложность этого решения равна O(n), где n длина входной строки. Проблема с этим решением заключается в том, что строка проходится дважды, что нарушает ограничения программы.
Мы можем решить эту задачу за один обход строки. Идея состоит в том, чтобы использовать map для хранения количества каждого отдельного символа и индекса его первого или последнего вхождения в строку. Затем пройтись по map и найти символ с минимальным индексом строки.
👉 Пишите ваше решение в комментариях👇
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Описание задания
Необходимо разработать приложение, предоставляющее HTTP API для получения данных о парковках такси в г. Москва. Данные необходимо брать с этой страницы ("Актуальная версия").
Описание необходимого функционала
Приложение должно реализовывать:
▪Функционал загрузки данных из файла (локального и/или по ссылке) в хранилище данных (данные на источнике могут как удаляться, так и добавляться);
▪Обслуживание HTTP запросов к API-endpoints, которые реализуют поиск по хранимым данным;
Обслуживание HTTP запросов к роуту, возвращающему метрические данные (в формате prometheus) работы приложения.
▪Обновление данных в хранилище должно происходить без остановки обслуживания HTTP запросов к API с учетом того, что их объем может быть очень большим (и маппинг данных на источнике может изменяться).
Методы HTTP API должны возвращать ответ в формате json. Время обработки одного запроса к HTTP API (не загрузка данных в хранилище) - не более 2 мс. до первого байта HTTP ответа (TTFB). Проектирование самих методов API - на ваше усмотрение (минимально необходимый функционал - это поиск по global_id, id и mode).
Метрические данные должны включать в себя как минимум следующие метрики:
Общее количество обработанных запросов к API-endpoints;
Количество ошибок обработки HTTP запросов к API-endpoints (плюсом будет "разведение" по различным кодам ответов);
Данные по времени обработки HTTP запросов к API-endpoint;
Дополнительные метрики, на ваше усмотрение.
Требования к реализации
▪В качестве хранилища данных необходимо использовать Redis;
▪Все функции (экспортируемые и не экспортируемые) должны сопровождаться понятным комментарием (если возможно - на английском языке);
▪Не стоит излишне сокращать имена переменных и констант - код пишется для людей, и он должен быть максимально простым и понятным;
▪Можно использовать любые сторонние пакеты, но не использовать какой-либо фреймворк;
▪Весь ключевой функционал должен быть зафиксирован unit-тестами;
▪После завершения работы над заданием необходимо написать сопроводительную документацию по работе с приложением в файле README.md в корне репозитория;
▪Конфигурация параметров подключения к хранилищу данных должна иметь возможность управляться как флагами запуска, так и переменными окружения. Возможности конфигурирования должны быть описаны в файле README.md вашего репозитория.
Плюсами будут являться
▪Настройка CI (силами GitHub actions, TravisCI, etc) выполняющая запуск тестов и сборки на каждый коммит;
▪Автоматическая сборка Docker-образа с приложением;
▪Интуитивно-понятное разбитие коммитов - одной конкретной задаче - один коммит или PR (её правки - отдельный коммит или PR);
Написание всех текстов коммитов - на английском языке.
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Текст задания:
Процессу на stdin приходят строки, содержащие интересующие нас URL. Каждый такой URL нужно дернуть и посчитать кол-во вхождений строки "Go". В конце работы приложение выводит на экран общее кол-во найденных строк "Go" во всех переданных URL, например:
$ echo -e 'https://golang.org\nhttps://golang.org\nhttps://golang.org' | go run 1.go
Count for https://golang.org: 9
Count for https://golang.org: 9
Count for https://golang.org: 9
Total: 27
Введенный URL должен начать обрабатываться сразу после вычитывания и параллельно с вычитыванием следующего. URL должны обрабатываться параллельно, но не более k=5 одновременно.
Обработчики url-ов не должны порождать лишних горутин, т.е. если k=1000 а обрабатываемых URL-ов нет, не должно создаваться 1000 горутин.
Нужно обойтись без глобальных переменных и использовать только стандартные библиотеки.
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Большой вборник вопросов технического собеседования, решенных с помощью Go
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Общее описание
Сервис предназначен для борьбы с подбором паролей при авторизации в какой-либо системе.
Сервис вызывается перед авторизацией пользователя и может либо разрешить, либо заблокировать попытку.
Предполагается, что сервис используется только для
server-server,т.е
. скрыт от конечного пользователя.Алгоритм работы
Сервис ограничивает частоту попыток авторизации для различных комбинаций параметров, например:
▪не более N = 10 попыток в минуту для данного логина.
▪не более M = 100 попыток в минуту для данного пароля (защита от обратного brute-force).
▪не более K = 1000 попыток в минуту для данного IP (число большое, т.к. NAT).
Для подсчета и ограничения частоты запросов, можно использовать например алгоритм leaky bucket. Или иные аналогичные: https://en.wikipedia.org/wiki/Rate_limiting
Причем сервис будет поддерживать множество bucket-ов, по одному на каждый логин/пароль/ip.
Bucket-ы можно хранить:
▪в памяти (в таком случае нужно продумать удаление неактивных bucket-ов, чтобы избежать утечек памяти).
▪во внешнем хранилище (например redis или СУБД, в таком случае нужно продумать производительность).
White/black листы содержат списки адресов сетей, которые обрабатываются более простым способом:
▪Если входящий IP в whitelist, то сервис безусловно разрешает авторизацию (ok=true);
▪Если - в blacklist, то отклоняет (ok=false).
Архитектура
Микросервис состоит из API, базы данных для хранения настроек и black/white списков. Опционально - хранилище для bucket'ов. Сервис должен предоставлять GRPC или REST API.
Описание методов API
Попытка авторизации
Запрос:
▪login
▪password
▪ip
Ответ:
▪ok (true/false) - сервис должен возвращать ok=true, если считает что запрос нормальный и ok=false, если считает что происходит bruteforce.
Сброс bucket
Должен очистить bucket-ы соответствующие переданным login и ip.
▪login
▪ip
Добавление IP в blacklist
подсеть (IP + маска)
Удаление IP из blacklist
подсеть (IP + маска)
Добавление IP в whitelist
подсеть (IP + маска)
Удаление IP из whitelist
подсеть (IP + маска)
▪Достаточно IPv4
▪Пример подсети: 192.1.1.0/25 - представляет собой адрес 192.1.1.0 с маской 255.255.255.128
▪Во время работы сервиса при поступлении очередного IP мы проходимся по подсетям в черных и белых списках и вычисляем, принадлежит ли IP одной из них.
Конфигурация
Основные параметры конфигурации:
N, M, K
- лимиты по достижению которых, сервис считает попытку брутфорсом.Command-Line интерфейс
Необходимо так же разработать command-line интерфейс для ручного администрирования сервиса. Через CLI должна быть возможность вызвать сброс бакета и управлять whitelist/blacklist-ом. CLI может работать через GRPC/HTTP интерфейс.
Развертывание
Развертывание микросервиса должно осуществляться командой make run (внутри docker compose up) в директории с проектом.
Тестирование
Рекомендуется выделить модуль обработки одного bucket и протестировать его с помощью unit-тестов.
Так же необходимо написать интеграционные тесты, проверяющие все вызовы API.
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Список фичей:
▪Пользователь может добавлять, удалять, закрывать и заново открывать задачи
▪Названия задач должны быть уникальными для всех пользователей (удаленные не учитываются).
▪Пользователь может получить список всех задач любого другого пользователя, кроме удаленных.
▪Пользователь может закрывать, удалять и заново открывать только свои задачи
▪Задача проходит следующие состояния: CREATED <--> CLOSED -> DELETED. При этом задача в статусе CREATED не может сразу перейти в DELETED. Задача же в DELETED больше не может переходить ни в какое состояние.
В рамках задания DELETED можно трактовать как фактическое удаление элемента, а не выставление какого-либо статуса.
Веб-сервер принимает сообщения по придуманному нами протоколу - Simple Web Protocol.
Запросы и ответы состоят из одной строки.
Формат запроса: "USER COMMAND ARG"
Формат ответа: "RESULT ARG"
Описание формата:
1. USER — имя пользователя, который осуществляет действие.
2. COMMAND — команда. Варианты команд:
▪CREATE_TASK MyTask — создать задачу с названием MyTask
▪CLOSE_TASK MyTask — закрыть задачу MyTask
▪DELETE_TASK MyTask — удалить задачу MyTask
▪REOPEN_TASK MyTask — заново открыть задачу MyTask
▪LIST_TASK USER — Получить список задач пользователя (в статусе CREATED и CLOSED)
▪__DELETE_ALL — Удалить информацию о всех пользователях и их задачах. Используется в тестах, чтобы «чистить» данные между их выполнением. Формат ответа для этой команды не имеет значения, так как он нигде не валидируется.
3. ARG — аргумент запроса или ответа. Может отсутствовать. Например, в запросе на создание задачи VASYA CREATE_TASK CleanRoom — это CleanRoom. А в ответе TASKS [MyTask1, MyTask2] — [MyTask1, MyTask2].
4. RESULT — ответ сервера о совершении действия. Варианты ответов.
▪CREATED — задача успешно создана
▪DELETED — задача успешно удалена
▪CLOSED — задача успешно закрыта
▪REOPENED — задача успешно открыта заново
▪TASKS [MyTask1, MyTask2] — список задач пользователя. Если задач нет, список пустой ([]). Задачи перечислены в порядке их создания.
▪WRONG_FORMAT — Неверный формат запроса
▪ACCESS_DENIED — Нет прав на совершение операции
▪ERROR — Любая другая ошибка
5. Все команды, а также имена пользователей регистрозависимые. В названии задач и имен пользователей не может быть пробелов.
6. Запросы валидируются в следующем порядке: формат запроса, право на совершение операции, все остальные проверки. Если первая проверка не прошла, остальные не выполняются.
Примеры запросов и ответов:
1.VASYA CREATE_TASK CleanRoom
CREATED
2.PETYA DELETE_TASK CleanRoom
ACCESS_DENIED
3.PETYA CREATE_TASK Task1
CREATED
4.PETYA CREATE_TASK Task2
CREATED
5. VASYA LIST_TASK PETYA
TASKS [Task1, Task2]
6. VASYA CREATE_TASK CleanRoom
ERROR
В данном примере состояние сервиса сохраняется между запросами, поэтому PETYA DELETE_TASK CleanRoom возвращает ACCESS_DENIED.
Дополнительные баллы
Учитывается общее оформление кода, архитектурное разделение компонентов, а также наличие Unit-тестов на отдельные части проекта.
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM