Skip to content

Commit

Permalink
Structure and autoconfigurations (#143)
Browse files Browse the repository at this point in the history
  • Loading branch information
pavetok authored Sep 30, 2023
1 parent 3425358 commit fde4141
Show file tree
Hide file tree
Showing 74 changed files with 473 additions and 429 deletions.
3 changes: 1 addition & 2 deletions .dx/group_vars/all.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ prefs: turing
lib_cid: "{{ lookup('ansible.builtin.pipe', 'git write-tree --prefix=libs')[:7] }}"
lib_cids:
signatures: "{{ lookup('ansible.builtin.pipe', 'git write-tree --prefix=libs/signatures')[:7] }}"
construction: "{{ lookup('ansible.builtin.pipe', 'git write-tree --prefix=libs/construction')[:7] }}"
storage: "{{ lookup('ansible.builtin.pipe', 'git write-tree --prefix=libs/storage')[:7] }}"
essentials: "{{ lookup('ansible.builtin.pipe', 'git write-tree --prefix=libs/essentials')[:7] }}"
messaging: "{{ lookup('ansible.builtin.pipe', 'git write-tree --prefix=libs/messaging')[:7] }}"
Expand Down Expand Up @@ -52,4 +51,4 @@ stack_images:
docker_entity: "{{ 'image' if image_repo == 'local' else 'manifest' }}"

app_deps:
foo: [essentials, construction, signatures, messaging, storage]
foo: [essentials, signatures, messaging, storage]
18 changes: 1 addition & 17 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,30 +6,14 @@ updates:
schedule:
interval: "weekly"
- package-ecosystem: "maven"
directory: "/libs"
directory: "/"
open-pull-requests-limit: 10
schedule:
interval: "daily"
groups:
spring-framework:
patterns:
- "org.springframework*"
- package-ecosystem: "maven"
directory: "/apps"
schedule:
interval: "weekly"
ignore:
- dependency-name: "smecalculus.bezmen:*"
- package-ecosystem: "maven"
directory: "/tests"
schedule:
interval: "weekly"
ignore:
- dependency-name: "smecalculus.bezmen:*"
- package-ecosystem: "maven"
directory: "/tools"
schedule:
interval: "weekly"
- package-ecosystem: "docker"
directory: "/schemas/postgres"
schedule:
Expand Down
81 changes: 0 additions & 81 deletions README.adoc
Original file line number Diff line number Diff line change
@@ -1,84 +1,3 @@
= bezmen

Шаблон репозитория backend-проекта на Java.

== Ключевые принципы

Решение и конвейер как сущности первого класса::
Решение (solution) - система, реализуемая для клиентов. Конвейер (pipeline) - система, реализуемая для разработчиков.

Единый интерфейс для локальной разработки и непрерывной интеграции::
Семантика интерфейса подразумевает набор предопределенных абстракций, артефакты которых последовательно конструируются в ходе сборки. Перед началом конструирования выполняются обязательные проверки. Примеры абстракций: исходники (sources), бинарники (binaries), образы (images), стеки (stacks) и другие.

Контентная адресация (aka идентификация по содержимому)::
Контентная адресация (content addressability) делает конструирование *идемпотентным*. Для директорий с исходным кодом вычисляются их контентные идентификаторы (CID's). Затем вычисляются корневые идентификаторы решения и конвейера. Таким образом формируется 2 небольших дерева Меркла, хеши которых подставляются в качестве тегов/классификаторов артефактов соответствующих абстракций. Артефакт конструируется, только когда его контентный идентификатор меняется.

Множественность окружений, назначений и настроек::
Решение/конвейер используется клиентами/разработчиками в разных окружениях (environs) для разных назначений (usages) и с разными настройками (prefs). Ключевые окружения/назначения/настройки именуются и проверяются в рамках непрерывной интеграции. Устаревшие окружения/назначения/настройки снимаются с поддержки.

Тесты! Тесты! Тесты!::
Тестирование - один из самых важных (или даже самый важный) аспектов разработки! При тестировании проверяется поведение целевого объекта в различных ситуациях. В зависимости от подхода к подготовке зависимостей целевого объекта тесты можно разделить на 3 категории.
Модульные тесты (unit tests):::
Все зависимости целевого объекта глушатся (stub) или мокируются (mock).
Интеграционные тесты (integration tests):::
Все зависимости глушатся/мокируются кроме одной (иногда нескольких), которая честно конструируется.
Сквозные тесты (end-to-end tests):::
Все зависимости честно конструируются.

Роботизированная асинхронная заливка (merge)::
Позволяет избежать ошибок/конкуренции и, как следствие, неоправданных потерь на загруженных ветках (например, таких как main).

== Непрерывная интеграция (CI)

Планы делим на 2 категории:

. Проверяющие решение (solution)
. Проверяющие конвейер (pipeline)

=== Проверка решения

Решение проверяем во всех окружениях, в которых его могут эксплуатировать клиенты.

==== В пределах разумного (sanity)

Запускаем анализ зависимостей, линтинг, статический анализ, компиляцию, модульные тесты и собираем/публикуем бинарники.

==== Убедительная (convincing)

Все перечисленное ранее. Плюс запускаем интеграционные тесты, анализируем покрытие и собираем/публикуем образы.

==== За пределами сомнений (beyond doubt)

Все перечисленное ранее. Плюс запускаем сквозные тесты, собираем/публикуем решения.

=== Проверка конвейера

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

==== В пределах разумного (sanity)

Запускаем линтинг исходного кода конвейера.

==== За пределами сомнений (beyond doubt)

Запускаем весь конвейер на минимальном наборе тестов.

== Частые вопросы (FAQ)

[qanda]
Почему обязательными статусными проверками назначены тестовые отчеты, а не тестовые джобы?::
Это дает свободу выбора структуры джобов, т.к. в различных планах сборки она может быть разной.

== Консольный интерфейс (CLI)

ansible-playbook <abstraction>.yml [-l <selector>]

== Todo

. Релизная сборка
. Параллелизация модульных тестов
. Построение дерева хешей (взглянуть критически)
. Версионирование библиотек и приложений (взглянуть критически)
. Локальные проверки в удаленном репозитории
. Чистка артефактов в удаленном репозитории
. Поддержка нескольких версий Java
4 changes: 0 additions & 4 deletions apps/foo/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,6 @@
<groupId>${project.groupId}</groupId>
<artifactId>essentials</artifactId>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>construction</artifactId>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>messaging</artifactId>
Expand Down
69 changes: 26 additions & 43 deletions apps/foo/src/main/java/smecalculus/bezmen/construction/App.java
Original file line number Diff line number Diff line change
@@ -1,26 +1,18 @@
package smecalculus.bezmen.construction;

import static smecalculus.bezmen.configuration.OrmMode.MY_BATIS;
import static smecalculus.bezmen.configuration.OrmMode.SPRING_DATA;
import static smecalculus.bezmen.configuration.WebMode.SPRING_MVC;
import static smecalculus.bezmen.configuration.MessageMappingMode.SPRING_WEB_MVC;
import static smecalculus.bezmen.configuration.StateMappingMode.MY_BATIS;
import static smecalculus.bezmen.configuration.StateMappingMode.SPRING_DATA;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.actuate.autoconfigure.health.HealthContributorAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.jdbc.DataSourceHealthContributorAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.system.DiskSpaceHealthContributorAutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.aop.AopAutoConfiguration;
import org.springframework.boot.autoconfigure.context.LifecycleAutoConfiguration;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration;
import org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration;
import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration;
import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration;
import org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration;
import org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration;
import org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration;
import org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.health.HealthEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.observation.web.servlet.WebMvcObservationAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.servlet.ServletManagementContextAutoConfiguration;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
Expand All @@ -32,7 +24,7 @@
import smecalculus.bezmen.messaging.SepulkaMsgMapper;
import smecalculus.bezmen.messaging.SepulkaMsgMapperImpl;
import smecalculus.bezmen.messaging.client.SepulkaClient;
import smecalculus.bezmen.messaging.springmvc.SepulkaController;
import smecalculus.bezmen.messaging.springwebmvc.SepulkaController;
import smecalculus.bezmen.storage.SepulkaDao;
import smecalculus.bezmen.storage.SepulkaDaoMyBatis;
import smecalculus.bezmen.storage.SepulkaDaoSpringData;
Expand All @@ -42,35 +34,26 @@
import smecalculus.bezmen.storage.springdata.SepulkaRepository;
import smecalculus.bezmen.validation.EdgeValidator;

@Import({ConfigBeans.class, ValidationBeans.class, MessagingBeans.class, StorageBeans.class})
@EnableAutoConfiguration(
exclude = {
LiquibaseAutoConfiguration.class,
AopAutoConfiguration.class,
DataSourceHealthContributorAutoConfiguration.class,
DiskSpaceHealthContributorAutoConfiguration.class,
EmbeddedWebServerFactoryCustomizerAutoConfiguration.class,
PersistenceExceptionTranslationAutoConfiguration.class,
SpringDataWebAutoConfiguration.class,
HealthContributorAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class,
LifecycleAutoConfiguration.class,
MultipartAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class,
RestTemplateAutoConfiguration.class,
TaskExecutionAutoConfiguration.class,
TaskSchedulingAutoConfiguration.class
})
@Configuration(proxyBeanMethods = false)
@Import({ConfigBeans.class, ValidationBeans.class, MessagingBeans.class, StorageBeans.class})
@ImportAutoConfiguration({
ManagementContextAutoConfiguration.class,
ServletManagementContextAutoConfiguration.class,
EndpointAutoConfiguration.class,
WebEndpointAutoConfiguration.class,
HealthEndpointAutoConfiguration.class,
ObservationAutoConfiguration.class,
WebMvcObservationAutoConfiguration.class
})
public class App {

public static void main(String[] args) {
SpringApplication.run(App.class, args);
}

@Bean
@ConditionalOnWebMode(SPRING_MVC)
SepulkaController sepulkaController(SepulkaClient client, SepulkaMsgMapper mapper) {
@ConditionalOnMessageMappingMode(SPRING_WEB_MVC)
SepulkaController sepulkaControllerSpringWeb(SepulkaClient client, SepulkaMsgMapper mapper) {
return new SepulkaController(client, mapper);
}

Expand All @@ -95,13 +78,13 @@ SepulkaConverter sepulkaConverter() {
}

@Bean
@ConditionalOnOrmMode(SPRING_DATA)
@ConditionalOnStateMappingMode(SPRING_DATA)
SepulkaDaoSpringData sepulkaDaoSpringData(SepulkaRecMapper mapper, SepulkaRepository repository) {
return new SepulkaDaoSpringData(mapper, repository);
}

@Bean
@ConditionalOnOrmMode(MY_BATIS)
@ConditionalOnStateMappingMode(MY_BATIS)
SepulkaDaoMyBatis sepulkaDaoMyBatis(SepulkaRecMapper recMapper, SepulkaSqlMapper sqlMapper) {
return new SepulkaDaoMyBatis(recMapper, sqlMapper);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package smecalculus.bezmen.messaging.springmvc;
package smecalculus.bezmen.messaging.springwebmvc;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import smecalculus.bezmen.messaging.SepulkaMsgMapper;
import smecalculus.bezmen.messaging.SepulkaMsgMapperImpl;
import smecalculus.bezmen.messaging.client.SepulkaClient;
import smecalculus.bezmen.messaging.springmvc.SepulkaController;
import smecalculus.bezmen.messaging.springwebmvc.SepulkaController;
import smecalculus.bezmen.validation.EdgeValidator;

@Import(ValidationBeans.class)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package smecalculus.bezmen.construction;

import static java.util.stream.Collectors.joining;
import static smecalculus.bezmen.configuration.OrmMode.MY_BATIS;
import static smecalculus.bezmen.configuration.OrmMode.SPRING_DATA;
import static smecalculus.bezmen.configuration.VendorMode.POSTGRES;
import static smecalculus.bezmen.configuration.StateMappingMode.MY_BATIS;
import static smecalculus.bezmen.configuration.StateMappingMode.SPRING_DATA;
import static smecalculus.bezmen.configuration.StorageProtocolMode.POSTGRES;

import java.util.Collection;
import java.util.List;
Expand All @@ -13,9 +13,9 @@
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import smecalculus.bezmen.configuration.OrmProps;
import smecalculus.bezmen.configuration.StateMappingProps;
import smecalculus.bezmen.configuration.StorageProps;
import smecalculus.bezmen.configuration.VendorProps;
import smecalculus.bezmen.configuration.StorageProtocolProps;
import smecalculus.bezmen.storage.SepulkaDao;
import smecalculus.bezmen.storage.SepulkaDaoMyBatis;
import smecalculus.bezmen.storage.SepulkaDaoSpringData;
Expand All @@ -33,7 +33,7 @@ public class SepulkaDaoBeans {
public DataSource dataSource(StorageProps storageProps) {
List<String> common = List.of("DB_CLOSE_DELAY=-1");
List<String> specific =
switch (storageProps.vendorProps().mode()) {
switch (storageProps.protocolProps().protocolMode()) {
case H2 -> List.of("MODE=STRICT");
case POSTGRES -> List.of("MODE=PostgreSQL", "DATABASE_TO_LOWER=TRUE", "DEFAULT_NULL_ORDERING=HIGH");
};
Expand Down Expand Up @@ -64,8 +64,11 @@ public SepulkaDao underTest(SepulkaRecMapper recMapper, SepulkaRepository reposi
@Bean
public StorageProps storageProps() {
return StorageProps.builder()
.ormProps(OrmProps.builder().mode(SPRING_DATA).build())
.vendorProps(VendorProps.builder().mode(POSTGRES).build())
.mappingProps(
StateMappingProps.builder().mappingMode(SPRING_DATA).build())
.protocolProps(StorageProtocolProps.builder()
.protocolMode(POSTGRES)
.build())
.build();
}
}
Expand All @@ -81,8 +84,11 @@ public SepulkaDao underTest(SepulkaRecMapper recMapper, SepulkaSqlMapper sqlMapp
@Bean
public StorageProps storageProps() {
return StorageProps.builder()
.ormProps(OrmProps.builder().mode(MY_BATIS).build())
.vendorProps(VendorProps.builder().mode(POSTGRES).build())
.mappingProps(
StateMappingProps.builder().mappingMode(MY_BATIS).build())
.protocolProps(StorageProtocolProps.builder()
.protocolMode(POSTGRES)
.build())
.build();
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package smecalculus.bezmen.storage;

import org.springframework.test.context.ContextConfiguration;
import smecalculus.bezmen.construction.OrmMyBatisBeans;
import smecalculus.bezmen.construction.MappingMyBatisBeans;
import smecalculus.bezmen.construction.SepulkaDaoBeans;

@ContextConfiguration(classes = {SepulkaDaoBeans.MyBatisPostgres.class, OrmMyBatisBeans.class})
@ContextConfiguration(classes = {SepulkaDaoBeans.MyBatisPostgres.class, MappingMyBatisBeans.class})
public class SepulkaDaoMyBatisPostgresIT extends SepulkaDaoIT {}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package smecalculus.bezmen.storage;

import org.springframework.test.context.ContextConfiguration;
import smecalculus.bezmen.construction.OrmSpringDataBeans;
import smecalculus.bezmen.construction.MappingSpringDataBeans;
import smecalculus.bezmen.construction.SepulkaDaoBeans;

@ContextConfiguration(classes = {SepulkaDaoBeans.SpringDataPostgres.class, OrmSpringDataBeans.class})
@ContextConfiguration(classes = {SepulkaDaoBeans.SpringDataPostgres.class, MappingSpringDataBeans.class})
public class SepulkaDaoSpringDataPostgresIT extends SepulkaDaoIT {}
Loading

0 comments on commit fde4141

Please sign in to comment.