Технологии программирования
Оценка сложности алгоритма, ssh-ключи, git, тестирование.
Оценка сложности алгоритма
Виды оценок
Можно выделить по сути 2 основных “вида” оценок алгоритма:
- Оценка по памяти (емкостная сложность)
- Оценка по времени (временная сложность)
Временная сложность алгоритма
- Оценивается в асимптотике O большого
- Учитываются “шаги алгоритма”, чье время выполнение константно
- Оценка в O-big означает что функция времени выполнения нашего алгоритма растет не быстрее, чем некоторая функция fn умноженная на константу
- пример: O(f(n)) - время выполнение нашего алгоритма растет не быстрее чем f(n) * const
Примеры
public class Test {
// Если количество шагов не зависит от входных данных -> скорее всего это O(1)
public int foo1(int a, int b) { // f(n) = 1 --> O(const * 1) -> O(1)
int c = a + b; // 1 шаг, его время const == 1
return c;
}
public int foo2(int a, int b) { // O(2 * 1) ? O(const * 1) -> O(1)
int c = a + b; // 1 шаг, его время const == 1
int result = c * c; // 1 шаг
return c;
}
// Если у нас есть цикл по входным (но без вложенного цикла) -> скорее всего это O(n) // линейная сложность
public int foo3(int n) { // O(n), f(n) = n
int sum = 0;
for (int i = 0; i < n; i++) {
sum += 1; // 1 шаг * n раз
}
return sum;
}
// Если у нас есть вложенный цикл по входным данным, скорее всего это O(n^2) // квадратичная сложность
public int foo4(int n) { // f(n) = n * n -> O(n^2)
int sum = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
sum += 1; // 1 шаг * n * n раз
}
}
}
// Еще бывает логарифмическая сложность O(logn); Сортировка слиянием ?
// O(nlogn)
}
Полезные ссылки
Сложность алгоритмов. Big O. Основы.
Оценка сложности алгоритмов, или Что такое О(log n)
Для знатоков математического анализа:
SSH ключи для подключения к серверу
Что такое ssh-ключ?
SSH-ключ — безопасный способ соединения с сервером.
Для аутентификации используются два ключа: приватный и публичный.
Публичный ключ хранится на сервере в корневом каталоге, а приватный ключ остаётся на локальном компьютере в зашифрованном виде.
Каждый раз, когда вы обращаетесь к серверу, происходит сопоставление ключей. Поэтому для аутентификации не нужен пароль.
Windows
- git bash -> инструкция по генерации похожа на macos (linux)
- через приложение putty
Полезные ссылки
Reg Ru. Инструкция как создать ssh-ключ
Git
Что такое гит?
Система контроля версий.
Используется для работы в команде, для разрешения конфликтов (в коде), для версионирования кода (позволяет на какое-то время фиксировать версии программного кода)
Ветка мастер <- 10 разработчиков добавляют свои фичи 1 раз в неделю дежурный инженер хочет взять все новые фичи и выкатить их на пользователей (добавляет обновление в Google Play). Чтобы это сделать с точки зрения кода, мы должны зафиксировать его на какой-то “версии” (набор коммитов) -> отводим специальную ветку кода и называем version 2.20.3
Часто, когда работают много программистов вместе, могут возникать конфликты в коде
Программист John на своем компьютере:
public class A {
public static void main(String[] args) {
System.out.println("hello world!");
}
}
Программист Петя на своем компьютере:
public class A {
public static void main(String[] args) {
System.out.println("привет мир!");
}
}
John сохранил файлик с кодом одновременно с Петей (с разницей в 3 секунды) Когда возникают такие ситуации, нам помогает git.
Основные вещи которые надо знать:
Создать репозиторий: git init
Изменения в коде в репозитории “находятся” в commit-ах (фиксация). Коммит хранит следующее:
- commit message
- состояние файлов с кодом (или не только с кодом), которые попали в коммит
Чтобы создать коммит:
- нужно добавить файл в репозиторий (если он еще не добавлен) - git add (file)
- git commit + написать сообщение (commit message)
Ветви
- Позволяют делать разные версии кода.
- Чтобы сделать новую ветвь - существует команда checkout -b
- Чтобы переключаться между ветвями - команда checkout
Существует возможность переносить изменения из одной ветки в другую. Merge - объединение (есть еще rebase) git merge –into-name имя ветки
Возможность работать с удаленным репозиториями (которые на сервере). manage remotes (в идее).
git push (ctrl shift k) - мы отправляем в удаленный репозиторий наши локальные коммиты
Тестирование
- Тестирование – вероятностный процесс нахождения ошибок
Виды тестирования
- Ручное / автоматическое
- Функциональное / smoke / регрессионное
- Unit / интеграционное / E2E
- UI тесты / скриншотные тесты
Что проверять в тестах
- Основные сценарии
- Граничные случаи
- Сценарии с ошибками
- Специфику функциональности (параллельное выполнение, транзакционность, …)
Что НЕ проверять в тестах
- Примитивные функции (getters, setters, …)
- Внешние библиотеки
Другие виды тестирования
- Статический анализ кода (checkstyle, error prone, PMD, …)
- Нагрузочное тестирование (JMeter, Yandex Tank)
- Тестирование производительности (JMH)
- Тестирование надёжности (Chaos Monkey)
Unit тестирование
- Unit тест (модульный тест) – сфокусирован на тестировании отдельного метода или класса, может быть группы классов. Как правило такие тесты не зависят от фреймворков (например, Spring), баз данных и любых внешних сервисов
- Разные команды могут по-разному интерпретировать unit и интеграционные тесты. Кто-то считает тест, использующий настоящую базу, unit тестом. Это ОК
- Unit тесты необходимо применять для тестирования нетривиальной логики в отдельном методе, классе или наборе классов
Что такое unit тест в прикладном смысле?
Программа или функция, которая тестирует какой-то один тест-кейс
Как устроены наши тесты?
Они написаны на groovy. Используется фреймворк spock
Пример теста на groovy
import spock.lang.Specification
class TestSpec extends Specification {
def "test sum should return false"() {
/*
// 1 шаг заводим какие-то данные которые нам нужны
// 2 шаг делаем действие, которое хотим проверить
// 3 шаг проверяем результат
**/
given:
def a = 1 // 1 шаг, здесь может быть создание нужных классов
when:
def sum = a + a // мы вызовем здесь какой-нибудь метод у созданного класса
then:
// сделать проверку
// Assert.areEqual() - обычно что-то такое
// в груви все чуть приятнее - мы можем просто написать boolean выражение
// и спок будет ждать, что оно должно быть true
sum == 2
}
def "test with where"() {
when:
def sum = a + b
then:
sum == sum1
where:
a || b || sum1
1 || 1 || 2
2 || 3 || 5
10 || 1 || 11
}
}