Post

๐Ÿฐ 332-blokey-land-service

๐Ÿฐ 332-blokey-land-service

๊ฐœ์š”

  • ํ”„๋กœ์ ํŠธ, ํƒœ์Šคํฌ, ๋งˆ์ผ์Šคํ†ค์„ ํ†ตํ•ฉ์ ์œผ๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ์„œ๋น„์Šค
  • ๋ฐ์ดํ„ฐ๋ฅผ ์‹œ๊ฐํ™”ํ•˜์—ฌ ํ”„๋กœ์ ํŠธ ํ˜„ํ™ฉ์„ ์‰ฝ๊ฒŒ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ๋‹ค.

ย ๊ฐœ๋ฐœ ๊ธฐ๊ฐ„

  • v1.0.0ย (2025-06-06 ~ 2025-06-15): ๋ฐฑ์—”๋“œ๋“œ ์„ค๊ณ„ ๋ฐ ์ดˆ๊ธฐ ๊ธฐ๋Šฅ ๊ตฌํ˜„
  • v1.0.1ย (2025-06-24 ~ 2025-07-07): ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ ๋ฐ ๋„๋ฉ”์ธ ๋กœ์ง ์ •๋น„
  • v1.0.2ย (2025-07-08): ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ ์›น ์ ‘์† ์‹œ ๋ฌดํ•œ ์ƒˆ๋กœ๊ณ ์นจ ๋ฒ„๊ทธ ํ•ซํ”ฝ์Šค
  • v1.1.0ย (2025-07-09 ~ 2025-07-15): ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ ๊ตฌ์ถ• ๋ฐ ๊ธฐ์กด ๊ธฐ๋Šฅ ๊ฐœ์„  ์ž‘์—…

ํ”„๋กœ์ ํŠธ ํ™˜๊ฒฝ

  • Language:ย Java 21,ย Typescript
  • Framework:ย Spring boot 3.5.0
  • Database:ย PostgreSQL
  • IDE:ย IntelliJ IDEA
  • CSR:ย React
  • Build-Tool:ย Gradle
  • ORM:ย JPA
  • Query Library:ย QueryDSL
  • DevOps:ย Docker,ย Docker-compose
  • Test:ย JUnit,ย JaCoCo,ย SonarQube,ย Cypress
  • CI:ย GitHub Actions

์š”์ฒญ ยท ์‘๋‹ต ํ๋ฆ„

  1. ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์‚ฌ์ดํŠธ์— ์ ‘์†ํ•˜๋ฉด Nginx๊ฐ€ React ์ •์  ๋นŒ๋“œ ํŒŒ์ผ์„ ์‘๋‹ตํ•œ๋‹ค.
  2. ๋ชจ๋“  ์š”์ฒญ์€ Sentinel-Server API Gateway๋ฅผ ํ†ตํ•œ๋‹ค.
  3. ์ธ์ฆ ยท ์ธ๊ฐ€ ์š”์ฒญ์€ Sentinel-Server์—์„œ ์ง์ ‘ ์‘๋‹ตํ•œ๋‹ค.
  4. Blokey-Land-Service์— ๋Œ€ํ•œ API ์š”์ฒญ์€ Reverse Proxy๋ฅผ ํ†ตํ•ด Blokey-Land-Service๊ฐ€ ์‘๋‹ตํ•œ๋‹ค.

์ธํ”„๋ผ ๊ตฌ์กฐ (์˜ˆ์ •)

  • ์•„์ง ๋ฐฐํฌ๋Š” ์ง„ํ–‰ํ•˜์ง€ ์•Š์•˜์œผ๋ฉฐ, ์ถ”ํ›„ ์ธ์Šคํ„ด์Šค๋ฅผ ๋‚˜๋ˆ„๊ธฐ ์œ„ํ•ด Docker-compose ๋‹จ์œ„๋กœ ๋ถ„๋ฆฌํ•˜์˜€๋‹ค.
  • Blokey-Land ์„œ๋ฒ„์—๋Š” ์•„์ง ElasticSearch๋ฅผ ๋„์ž…ํ•˜์ง€ ์•Š์•˜๋‹ค.
  • ์ถ”ํ›„ ๊ด€๋ จ ๊ธฐ๋Šฅ๊ณผ ํ•จ๊ป˜ ์ถ”๊ฐ€๋  ์˜ˆ์ •์ด๋‹ค.

ํ’ˆ์งˆ ๊ด€๋ฆฌ ํ”„๋กœ์„ธ์Šค

โœ… ๋‹จ์œ„ ํ…Œ์ŠคํŠธ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
@DisplayName("์กด์žฌํ•˜๋Š” ID๋กœ ํ”„๋กœ์ ํŠธ๋ฅผ ์กฐํšŒํ•˜๋ฉด ํ•ด๋‹น ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•œ๋‹ค.")  
@Test  
void givenValidId_whenReadProjectByProjectId_thenReturnProject() {  
	// given  
	Long id = 1L;  
	Project project = Project.builder()  
		.id(id)  
		.title("์ œ๋ชฉ")  
		.description("์„ค๋ช…")  
		.status(ProjectStatusType.ACTIVE)  
		.isPrivate(true)  
		.estimatedStartDate(LocalDate.now())  
		.estimatedEndDate(LocalDate.now())  
		.actualStartDate(LocalDate.now())  
		.actualEndDate(LocalDate.now())  
		.build();  
		
	when(repository.findById(id)).thenReturn(Optional.of(project));  
	
	// when  
	Project found = service.findProjectByProjectId(id);  
	
	// then  
	assertEquals(project.getId(), found.getId());  
	assertEquals(project.getTitle(), found.getTitle());  
	assertEquals(project.getDescription(), found.getDescription());  
	assertEquals(project.getImageUrl(), found.getImageUrl());  
	assertEquals(project.getStatus(), found.getStatus());  
	assertEquals(project.isPrivate(), found.isPrivate());  
	assertEquals(project.getEstimatedStartDate(), found.getEstimatedStartDate());  
	assertEquals(project.getEstimatedEndDate(), found.getEstimatedEndDate());  
	assertEquals(project.getActualStartDate(), found.getActualStartDate());  
	assertEquals(project.getActualEndDate(), found.getActualEndDate());  
	
	verify(repository).findById(id);  
}
  • JUnit์„ ํ†ตํ•ด TDD ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•œ๋‹ค.
  • Mockito ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ ˆํฌ์ง€ํ† ๋ฆฌ์˜ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ ์‹œ ํŠน์ • ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ํ•˜์—ฌ DB ์—ฐ๊ฒฐ ์—†์ด ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋ฉด ์ข‹์ง€๋งŒ, ๊ฐœ๋ฐœ ๋ฐ ๋นŒ๋“œ ๊ณผ์ •์—์„œ ์‹œ๊ฐ„ ๋น„์šฉ์ด ํฌ๋ฏ€๋กœ ์„œ๋น„์Šค ๊ณ„์ธต์€ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋กœ ์ถฉ์กฑํ•˜์˜€๋‹ค.

โœ… ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
@Testcontainers  
public abstract class ContainerBaseTest {  
	private static final PostgreSQLContainer<?> POSTGRES_CONTAINER;  
	
	static {  
		Dotenv dotenv = Dotenv.configure()  
			.ignoreIfMissing()  
			.load();  
			
		dotenv.entries().forEach(entry ->  
			System.setProperty(entry.getKey(), entry.getValue())  
		);  
		
		POSTGRES_CONTAINER = new PostgreSQLContainer<>("postgres:15-alpine");  
		POSTGRES_CONTAINER.start();  
	}  
	
	@DynamicPropertySource  
	static void overrideProps(DynamicPropertyRegistry registry) {  
		String originalJdbcUrl = POSTGRES_CONTAINER.getJdbcUrl();  
		String p6spyJdbcUrl = originalJdbcUrl.replace("jdbc:postgresql:", "jdbc:p6spy:postgresql:");  
		registry.add("spring.datasource.url", () -> p6spyJdbcUrl);  
		registry.add("spring.datasource.username", POSTGRES_CONTAINER::getUsername);  
		registry.add("spring.datasource.password", POSTGRES_CONTAINER::getPassword);  
		registry.add("spring.datasource.driver-class-name", () -> "com.p6spy.engine.spy.P6SpyDriver");  
		registry.add("file.upload-dir", () -> "DEFAULT");  
		registry.add("server.port", () -> "8081");  
		registry.add("server.address", () -> "0.0.0.0");  
	}  
}
  • ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ๋Š” Testcontainers๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ€์ƒ์˜ DB๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ์ถ”์ƒ ํด๋ž˜์Šค๋ฅผ ์ž‘์„ฑํ–ˆ๋‹ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@Test  
@DisplayName("์‚ฌ์šฉ์ž ID๋กœ ํ”„๋กœ์ ํŠธ ๋ฐ ํƒœ์Šคํฌ ๋ชฉ๋ก ์กฐํšŒ ์‹œ ํ”„๋กœ์ ํŠธ ๋ชฉ๋ก๊ณผ ํ•ด๋‹น ํ”„๋กœ์ ํŠธ์˜ ํƒœ์Šคํฌ ๋ชฉ๋ก์ด ํ•จ๊ป˜ ๋ฐ˜ํ™˜๋œ๋‹ค.")  
void givenBlokeyId_whenFindProjectsWithTasksByBlokeyId_thenReturnsProjectsWithTasks() { 
    // given  
    taskRepository.save(Task.builder()  
        .title("์ œ๋ชฉ 1")  
        .description("์„ค๋ช… 1")  
        .project(project1)  
        .milestone(null)  
        .assignee(blokeyId)  
        .estimatedStartDate(LocalDate.now())  
        .estimatedEndDate(LocalDate.now())  
        .actualStartDate(LocalDate.now())  
        .actualEndDate(LocalDate.now())  
        .build()  
    );  
    
    // when  
    List<Project> result = repository.findProjectsWithTasksByBlokeyId(blokeyId);  
    
    // then  
    assertThat(result).hasSize(2);  
    assertThat(result.getFirst().getTitle()).isEqualTo("์ œ๋ชฉ 1");  
    assertThat(result.getFirst().getTasks()).isNotNull();  
}
  • ๋ ˆํฌ์ง€ํ† ๋ฆฌ ๋ฉ”์„œ๋“œ๋กœ ๋งคํ•‘๋˜๋Š” ์ฟผ๋ฆฌ๋ฅผ ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์œ„ํ•ด ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ–ˆ๋‹ค.

โœ… ํ…Œ์ŠคํŠธ ์ปค๋ฒ„๋ฆฌ์ง€ ๋ชจ๋‹ˆํ„ฐ๋ง

  • JaCoCo๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ…Œ์ŠคํŠธ ์ปค๋ฒ„๋ฆฌ์ง€๋ฅผ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ ๋ชจ๋‹ˆํ„ฐ๋ง ํ–ˆ๋‹ค.
  • ํ…Œ์ŠคํŠธ ๋ถˆํ•„์š” ์ฝ”๋“œ๊นŒ์ง€ ์ปค๋ฒ„๋ฆฌ์ง€ ๋ฒ”์œ„์— ํฌํ•จ๋˜๋ฉด ์˜คํžˆ๋ ค ๊ฐœ๋ฐœ ์ง„ํ–‰์— ๋ฐฉํ•ด๊ฐ€ ๋˜๊ธฐ ๋•Œ๋ฌธ์—, ๋Œ€์ƒ ์ฝ”๋“œ๋Š” Service, Repository ํด๋ž˜์Šค๋กœ ํ•œ์ •ํ•˜์˜€๋‹ค.

โœ… E2E ํ…Œ์ŠคํŠธ

  • ํ”„๋ก ํŠธ์—”๋“œ์˜ ํ•ต์‹ฌ ํ”„๋กœ์„ธ์Šค๋ฅผ ts ํŒŒ์ผ๋กœ ์ž‘์„ฑํ•˜์—ฌ ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ–ˆ๋‹ค.
  • ๊ฐ€๋ น Blokey-Land์˜ ํ•ต์‹ฌ์€ ๊ฐ„ํŠธ์ฐจํŠธ ํ™•์ธ์ด๋ฏ€๋กœ ์ดˆ๊ธฐ์— ์ฃผ์š” ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๋Š” ํ”„๋กœ์„ธ์Šค๋ฅผ ์ž‘์„ฑํ•ด๋ณด์•˜๋‹ค.

โœ… CI ํ†ตํ•ฉ์„ ํ†ตํ•œ ํ’ˆ์งˆ ๊ด€๋ฆฌ

1
2
3
4
5
- name: Build and analyze with SonarCloud
  working-directory: spring-boot-app
  env:
    SONAR_TOKEN: $
  run: ./gradlew clean build jacocoTestReport sonarqube --info
  • GitHub Actions ์›Œํฌํ”Œ๋กœ์šฐ์— ์œ„์™€ ๊ฐ™์ด SonarQube ๋ถ„์„ Step์„ ์ถ”๊ฐ€ํ•˜์˜€๋‹ค.

  • ํ’ˆ์งˆ ๊ฒŒ์ดํŠธ๋ฅผ ์„ค์ •ํ•˜์—ฌ CI๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์ง„ํ–‰๋˜๋ฉด, SonarQube ํด๋ผ์šฐ๋“œ ์„œ๋น„์Šค๋Š” PR์— ์ฝ”๋“œ๋ฅผ Pushํ•  ๊ฒฝ์šฐ ์ƒˆ๋กœ์šด ์ฝ”๋“œ์— ๋Œ€ํ•œ ์ด์Šˆ, ์ฝ”๋“œ ์ปค๋ฒ„๋ฆฌ์ง€๋ฅผ ๋ถ„์„ํ•˜์—ฌ ์ฝ”๋ฉ˜ํŠธ๋ฅผ ๋‚จ๊ธด๋‹ค.

์–ด๋ ค์› ๋˜ ์ 

โœ… ๋ฒก์—”๋“œ ํ…Œ์ด๋ธ” ์„ค๊ณ„ ๋ฐ ๊ตฌํ˜„

  • ํ…Œ์ด๋ธ”์„ ์„ค๊ณ„ํ•  ๋•Œ N+1 ๋“ฑ ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ๋ฌธ์ œ๋ฅผ ์˜ˆ๋ฐฉํ•˜๊ธฐ ์œ„ํ•ด ๊ฐ€๊ธ‰์  ์—ฐ๊ด€ ๊ด€๊ณ„๋ฅผ ๊ฐ–์ง€ ์•Š๋„๋ก ํ•˜์˜€๋‹ค.
  • ๊ทธ๋Ÿฌ๋‚˜ ๊ฐ„ํŠธ์ฐจํŠธ๋ฅผ ๋ Œ๋”๋ง ํ•  ๋•Œ๋Š” ํ”„๋ก ํŠธ์—”๋“œ์—์„œ ํ”„๋กœ์ ํŠธ๋ฅผ ์กฐํšŒํ•˜๊ณ , ํ•ด๋‹น ๋ชฉ๋ก์„ ์ˆœํšŒํ•˜๋ฉฐ ํƒœ์Šคํฌ๋ฅผ ์กฐํšŒํ•˜๋‹ค๋ณด๋‹ˆ ๋„คํŠธ์›Œํฌ ์š”์ฒญ์„ N+1๋ฒˆ์ด๋‚˜ ํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค.
  • ํ•ด๋‹น ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ํ”„๋กœ์ ํŠธ์™€ ํƒœ์Šคํฌ๋Š” ์–‘๋ฐฉํ–ฅ ์—ฐ๊ด€๊ด€๊ณ„๋ฅผ ๊ฐ–๋„๋ก ์ˆ˜์ •ํ•˜์˜€๋‹ค.
  • ์„œ๋ฒ„๋‹จ์—์„œ DB์— N+1๋ฒˆ ์š”์ฒญ์„ ํ•˜์ง€ ์•Š๋„๋ก ํŒจ์น˜ ์กฐ์ธ์„ ์‚ฌ์šฉํ•˜์—ฌ ์กฐํšŒํ•˜์˜€๋‹ค.

โœ… ํ”„๋ก ํŠธ์—”๋“œ ์ƒํƒœ ๊ด€๋ฆฌ

  • ๊ฐ€๋ น A โ†’ B โ†’ C ๋ฐฉํ–ฅ์œผ๋กœ ์ปดํฌ๋„ŒํŠธ๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  A์˜ ์ƒํƒœ๋ฅผ C์—์„œ ์กฐ์ž‘ํ•ด์•ผ ํ•  ๊ฒฝ์šฐ B์—์„œ ๊ทธ ํ๋ฆ„์ด ๋Š๊ธฐ๋ฉด ์ปดํŒŒ์ผ์„ ํ†ตํ•ด ๋ฌธ์ œ๋ฅผ ๋””๋ฒ„๊น… ํ•  ์ˆ˜ ์—†์–ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š”๋ฐ ์˜ค๋žœ ์‹œ๊ฐ„์ด ๊ฑธ๋ ธ๋‹ค.
  • ์ƒํƒœ๋ฅผ props๋กœ๋งŒ ์ „๋‹ฌํ•˜๋Š” ๊ตฌ์กฐ๋Š” ๊นŠ์–ด์ง€๋ฉด ๊ด€๋ฆฌ๊ฐ€ ์–ด๋ ค์›Œ ์ง„๋‹ค๋Š” ์ ์„ ์•Œ๊ฒŒ ๋˜์—ˆ๋‹ค.
  • ์ถ”ํ›„ Context, Redux ๊ฐ™์€ ํŒจํ„ด์„ ์ ๊ทน์ ์œผ๋กœ ๋„์ž…ํ•  ์˜ˆ์ •์ด๋‹ค.

โœ… Testcontainers ์ปจํ…Œ์ด๋„ˆ๋ฅผ ๊ณต์œ ํ•˜์ง€ ๋ชปํ•˜๊ณ  ์žฌ์ƒ์„ฑํ•˜๋Š” ๋ฌธ์ œ

1
2
3
4
5
6
7
8
9
10
11
12
13
@Testcontainers 
public abstract class ContainerBaseTest { 
	@Container 
	static PostgreSQLContainer<?> postgresContainer = new PostgreSQLContainer<>("postgres:15-alpine"); 
	
	@DynamicPropertySource 
	static void overrideProps(DynamicPropertyRegistry registry) { 
		registry.add("spring.datasource.url", postgresContainer::getJdbcUrl);
		registry.add("spring.datasource.username", postgresContainer::getUsername);
		registry.add("spring.datasource.password", postgresContainer::getPassword);
		registry.add("file.upload-dir", () -> "/test-uploads"); 
	} 
}
  • ์ฒ˜์Œ์—๋Š” @Container Annotation์„ ์‚ฌ์šฉํ•˜์—ฌ ์œ„์™€ ๊ฐ™์€ ํด๋ž˜์Šค๋ฅผ ์ƒ์†๋ฐ›์•„ ํ•ด๋‹น ์ปจํ…Œ์ด๋„ˆ์˜ ๋ผ์ดํ”„ ์‚ฌ์ดํด์„ ๊ด€๋ฆฌํ–ˆ๋‹ค.
  • ๊ทธ๋Ÿฐ๋ฐ @Testcontainers ์ปจํ…Œ์ด๋„ˆ๋ฅผ ๊ณต์œ ํ•˜์ง€ ๋ชปํ•˜๊ณ  ํ•ด๋‹น ํด๋ž˜์Šค๋ฅผ ์ƒ์† ๋ฐ›๋Š” ์ž์‹ ํด๋ž˜์Šค ๊ฐœ์ˆ˜ ๋งŒํผ ์ปจํ…Œ์ด๋„ˆ ์žฌ์ƒ์„ฑ์„ ์‹œ๋„ํ•˜๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค.
  • ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์ž์‹ ํด๋ž˜์Šค ๊ฐœ์ˆ˜ ๋งŒํผ ์žฌ์ƒ์„ฑํ•˜๋ฉด, ๋ฆฌ์†Œ์Šค๋„ ์ปค์ง€๊ณ  ์‹ค์ œ๋กœ ์ปจํ…Œ์ด๋„ˆ ์ƒ์„ฑ ์‹œ๊ฐ„ ๋•Œ๋ฌธ์— DB ์—ฐ๊ฒฐ ๋ฌธ์ œ๋กœ ํ…Œ์ŠคํŠธ๋„ ์‹คํŒจํ–ˆ๋‹ค.
  • @Container Annotation์„ ์—†์• ๊ณ , ์‹ฑ๊ธ€ํ†ค ๋ฐฉ์‹์œผ๋กœ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ๊ด€๋ฆฌํ•˜๋ฉฐ ์ˆ˜๋™์œผ๋กœ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜์˜€๋‹ค.

ํ–ฅํ›„ ๊ณ„ํš

โœ… ํ”„๋กœ์ ํŠธ์™€ ๋ฉค๋ฒ„ ๋งค์นญ ๊ธฐ๋Šฅ ์ถ”๊ฐ€

  • ํ”„๋กœ์ ํŠธ์™€ ๋ฉค๋ฒ„ ๋งค์นญ ๊ธฐ๋Šฅ์€ Blokey-Land ์„œ๋น„์Šค์˜ ํ•ต์‹ฌ ๊ฐ€์น˜ ์ค‘ ํ•˜๋‚˜๋กœ, ์‚ฌ์šฉ์ž ์นœํ™”์ ์ธ ๊ฒฝํ—˜์„ ์ œ๊ณตํ•˜๊ธฐ ์œ„ํ•ด ๊ธฐํš ๋‹จ๊ณ„๋ถ€ํ„ฐ ์ค‘์š”ํ•œ ์š”์†Œ๋กœ ๊ณ ๋ ค๋˜์—ˆ๋‹ค.
  • ์ด๋ฅผ ์œ„ํ•ด ํ”„๋กœ์ ํŠธ ๋ฐ ์‚ฌ์šฉ์ž ๋„๋ฉ”์ธ์— ์Šคํ‚ฌ(skill), ํฌ์ง€์…˜(discipline) ํ•„๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ , ElasticSearch๋ฅผ ๋„์ž…ํ•˜์—ฌ ํ”„๋กœ์ ํŠธ์™€ ๋ฉค๋ฒ„ ๊ฐ„ ์ถ”์ฒœ ๋ฐ ๋งค์นญ ๊ธฐ๋Šฅ์„ ๊ฐœ๋ฐœํ•˜๊ณ ์ž ํ•œ๋‹ค.

โœ… ๊ธฐ์กด ๊ธฐ๋Šฅ ์ตœ์ ํ™”

  • ์•„์ง ์–‘๋ฐฉํ–ฅ์œผ๋กœ ์—ฐ๊ด€ ๊ด€๊ณ„๋ฅผ ์ „ํ™˜ํ•ด์•ผ ํ•  ๋„๋ฉ”์ธ ๊ด€๊ณ„๊ฐ€ ๋‚จ์•„์žˆ๋‹ค.
  • ์•„์šธ๋Ÿฌ ๋„๋ฉ”์ธ ์—ฐ๊ด€ ๊ด€๊ณ„ ์ „ํ™˜์— ๋”ฐ๋ฅธ ํ”„๋ก ํŠธ์—”๋“œ์˜ ํ™”๋ฉด ๊ตฌ์„ฑ๊ณผ ๋ฒก์—”๋“œ์˜ ์ฟผ๋ฆฌ๋ฅผ ์ตœ์ ํ™”ํ•  ์˜ˆ์ •์ด๋‹ค.

โœ… ๋””์ž์ธ

  • ์ดˆ๊ธฐ์—๋Š” ์‚ฌ์šฉ์ž์—๊ฒŒ ์นœ๊ทผํ•œ ์ธ์ƒ์„ ์ฃผ๊ธฐ ์œ„ํ•ด Blokey-Land๋ผ๋Š” ๋„ค์ด๋ฐ๊ณผ ๊ฒŒ์ด๋ฏธํ”ผ์ผ€์ด์…˜ ๋””์ž์ธ์„ ์ ์šฉํ–ˆ์œผ๋‚˜, ์‚ฌ์ดํŠธ์— ์ฒ˜์Œ ๋ฐฉ๋ฌธํ•˜๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์„œ๋น„์Šค ๋ชฉ์ ์„ ์ง๊ด€์ ์œผ๋กœ ์ดํ•ดํ•˜๊ธฐ ์–ด๋ ค์šธ ๊ฒƒ ๊ฐ™๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ๋‹ค.
  • ๋ณด๋‹ค ์ „๋ฌธ์ ์ด๊ณ  ๋ชจ๋˜ํ•œ ๋А๋‚Œ์˜ ๋””์ž์ธ์œผ๋กœ ๋ฆฌ๋””์ž์ธ์„ ์ง„ํ–‰ํ•˜์—ฌ ์„œ๋น„์Šค์˜ ๋ชฉ์ ๊ณผ ๊ธฐ๋Šฅ์„ ๋ช…ํ™•ํžˆ ์ „๋‹ฌํ•˜๊ณ ์ž ํ•œ๋‹ค.
  • https://github.com/brobro332/332-blokey-land-service
This post is licensed under CC BY 4.0 by the author.