3. ํ์ ๊ด๋ฆฌ ์์ - ๋ฐฑ์๋ ๊ฐ๋ฐ
๋ชฉ์ฐจ
- ๋น์ฆ๋์ค ์๊ตฌ์ฌํญ ์ ๋ฆฌ
- ํ์ ๋๋ฉ์ธ๊ณผ ๋ฆฌํฌ์งํ ๋ฆฌ ๋ง๋ค๊ธฐ
- ํ์ ๋ฆฌํฌ์งํ ๋ฆฌ ํ ์คํธ ์ผ์ด์ค ์์ฑ
- ํ์ ์๋น์ค ๊ฐ๋ฐ
- ํ์ ์๋น์ค ํ ์คํธ
์๊ฐ ์ฝ์ค๋ ์ธํ๋ฐ ์คํ๋ง ์ ๋ฌธ ๊ฐ์๋ฅผ ๋ฃ๊ณ ์์ต๋๋ค.
๋น์ฆ๋์ค ์๊ตฌ์ฌํญ ์ ๋ฆฌ
๋จ์ํ ๋น์ฆ๋์ค๋ก ์ค์ต ์งํ. ๋ํ, ์์ง ๋ฐ์ดํฐ๋ฒ ์ด์ค๊ฐ ์ ํด์ง์ง ์์์ง๋ง ๊ฐ๋ฐ์ ์งํํด์ผ ํ๋ ์ํฉ์ ๊ฐ์ .
- ๋ฐ์ดํฐ : ํ์ID, ์ด๋ฆ
- ๊ธฐ๋ฅ : ํ์ ๋ฑ๋ก, ์กฐํ
์ผ๋ฐ์ ์ธ ์น ์ ํ๋ฆฌ์ผ์ด์ ๊ตฌ์กฐ
์ผ๋ฐ์ ์ธ ์น ์ฑ ๊ตฌ์กฐ๋ฅผ ๋ฐ๋ผ๊ฐ ์์ .
- ์ปจํธ๋กค๋ฌ : ์น MVC์ ์ปจํธ๋กค๋ฌ์ ์ญํ
- ์๋น์ค : ํต์ฌ ๋น์ฆ๋์ค ๋ก์ง ๊ตฌํ(ex. ํ์ ์ค๋ณต๊ฐ์ ๋ถ๊ฐ ๋ฑ)
- ๋ฆฌํฌ์งํ ๋ฆฌ : ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ๊ทผ, ๋๋ฉ์ธ ๊ฐ์ฒด๋ฅผ DB์ ์ ์ฅํ๊ณ ๊ด๋ฆฌ
- ๋๋ฉ์ธ : ํ์, ์ฃผ๋ฌธ, ์ฟ ํฐ ๋ฑ๋ฑ ์ฃผ๋ก ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฅ๋๊ณ ๊ด๋ฆฌ๋๋ ๋น์ฆ๋์ค ๋๋ฉ์ธ ๊ฐ์ฒด
ํด๋์ค ์์กด๊ด๊ณ
- ํ์ ๋น์ฆ๋์ค ๋ก์ง์ผ๋ก๋ MemberService
- ํ์์ ์ ์ฅํ๋ MemberRepository๋ interface๋ก ๊ด๋ฆฌํ๋ค (-> ๋ฐ์ดํฐ๋ฒ ์ด์ค๊ฐ ์์ง ์ ์ ๋์ง ์์๊ธฐ ๋๋ฌธ์)
- Memory๋ก ๋จ์ํ๊ฒ ์ ์ฅํ๋ Memory MemberRepository๋ก ์ฌ์ฉํ๋ค. ์ถํ ๋ฐ์ดํฐ๋ฒ ์ด์ค๊ฐ ์ ์ ๋๋ฉด ๋ฐ๊ฟ๋ผ์ธ ์ ์๋๋ก ๋ฆฌํฌ์งํ ๋ฆฌ๋ฅผ interface๋ก ๊ตฌํ.
ํ์ ๋๋ฉ์ธ๊ณผ ๋ฆฌํฌ์งํ ๋ฆฌ ๋ง๋ค๊ธฐ
๋๋ฉ์ธ (ํ์ ๊ฐ์ฒด)
- hello.hellospring์์ domain์ด๋ผ๋ ํจํค์ง๋ฅผ ์์ฑํ๊ณ , Member๋ผ๋ ํด๋์ค๋ฅผ ์์ฑํ๋ค.
ํ์ ๋ฆฌํฌ์งํ ๋ฆฌ ์ธํฐํ์ด์ค
ํ์ ๋ฆฌํฌ์งํ ๋ฆฌ ๋ฉ๋ชจ๋ฆฌ ๊ตฌํ์ฒด
- implements MemberRepository ํด์ค ํ
Alt
+Insert
ํ์ฌ implements Methods ํด์ฃผ Generateํ ์ ์๋ค. - Map<Long, Member>๋ฅผ ์ฐ๋ฉด Map์ inport ํด์ฃผ์ด์ผ ํ๋๋ฐ,
Alt
+Insert
ํ๊ฑฐ๋Ctrl
+Space
ํ๋ฉด importํ ์ ์๋ค. - ํด๋น ์ฝ๋์์ HashMap์ ์ฌ์ฉํ๋๋ฐ, ๋์์ฑ ๋ฌธ์ ๊ฐ ๊ณ ๋ ค๋์ด ์์ง ์์ผ๋ฏ๋ก ์ค๋ฌด์์๋ ConcurrentHashMap, AtomicLong ์ฌ์ฉ์ ๊ณ ๋ คํด์ผ ํ๋ค.
ConcurrentHashMap
: HashMap์ thread-safe ํ๋๋ก ๋ง๋ ํด๋์ค์ด๋ค. HashMap๊ณผ ๋ฌ๋ฆฌ key, value์ null์ ํ์ฉํ์ง ์๋๋ค. ๋ํ ํค๊ฐ์ด ์กด์ฌํ๋ฉด ๊ธฐ์กด์ ๊ฐ์ ๋ฐํํ๊ณ , ์๋ค๋ฉด ์ ๋ ฅํ ๊ฐ์ ์ ์ฅํ ๋ค ๋ฐํํ๋putIfAbsent
๋ฉ์๋๊ฐ ์กด์ฌํ๋ค.AtomicLong
: Long ์๋ฃํ์ ๊ฐ๊ณ ์๋ Wrapping ํด๋์ค๋ก, thread-safe๋ก ๊ตฌํ๋์ด ์๋ค.
- long sequence๋ 1, 2, 3 ๋ฑ์ ์์๋๋ก ๋ฐ์์ค๋ ๊ฑฐ๋ผ๊ณ ํ๋ค.
- 0L : ๋ช ์์ ์ผ๋ก long type value๋ผ๋ ์๋ฏธ์ด๋ค.
- member.setId(++sequence)๋ก id๋ฅผ ์ธํ ํ๊ณ , store ๋ฉ๋ชจ๋ฆฌ์ ์ ์ฅํ๋ค.
- findById์์ return Optional.ofNullable(store.get(id));๋ store.get(id)๊ฐ null๋ก ๋ฐํ๋ ๊ฒ์ ๋๋นํ์ฌ Optional๋ก ๊ฐ์ธ๋๋ฉด, null์ด ๋ฐํ๋์ด๋ ๋๋ค.
- Java Stream filter (Java8๋ถํฐ ๋ค์ด์ด)
- for, foreach ๋์ ๋๋คํจ์ํ์์ผ๋ก ๊ฐ๊ฒฐํ๊ณ ๊น๋ํ๊ฒ ์์๋ฅผ ๊ณจ๋ผ๋ด์ด ๊ฐ๊ณต
- map : ์์๋ค์ ํน์ ์กฐ๊ฑด์ ํด๋นํ๋ ๊ฐ์ผ๋ก ๋ณํํด์ค๋ค. ๋,์๋ฌธ์ ๋ณํ ๋ฑ์ ์์ ์ ํ๊ณ ์ถ์ ๋ ์ฌ์ฉ๊ฐ๋ฅ
- filter : ์์๋ค์ ์กฐ๊ฑด์ ๋ฐ๋ผ ๊ฑธ๋ฌ๋ด๋ ์์ . ๊ธธ์ด์ ์ ํ, ํน์ ๋ฌธ์ํฌํจ ๋ฑ์ ์์ ์ ํ๊ณ ์ถ์ ๋ ์ฌ์ฉ๊ฐ๋ฅ
- sorted : ์์ ์ ๋ ฌ
- ์์๋ค์ ๊ฐ๊ณต์ด ๋๋ฌ๋ค๋ฉด ๋ฆฌํดํ ๊ฒฐ๊ณผ๋ฅผ collect๋ฅผ ํตํด ๋ง๋ค์ด์ค๋๋ค.
- for, foreach ๋์ ๋๋คํจ์ํ์์ผ๋ก ๊ฐ๊ฒฐํ๊ณ ๊น๋ํ๊ฒ ์์๋ฅผ ๊ณจ๋ผ๋ด์ด ๊ฐ๊ณต
- ๊ตฌํํ ์ฝ๋์ ๋์ ์ฌ๋ถ๋ฅผ ํ์ธํ๋ ๊ฐ๋จํ ๋ฐฉ๋ฒ์ด ํ ์คํธ์ผ์ด์ค ์์ฑ์ด๋ค.
ํ์ ๋ฆฌํฌ์งํ ๋ฆฌ ํ ์คํธ ์ผ์ด์ค ์์ฑ
- java main method๋ฅผ ํตํด ์คํํ๊ฑฐ๋, ์น์ฑ ์ปจํธ๋กค๋ฌ๋ฅผ ํตํด ํด๋น ๊ธฐ๋ฅ์ ์คํํด๋ณผ ์๋ ์๋ค. ํ์ง๋ง ๋ฐ๋ณต์คํํ๊ธฐ ์ด๋ ต๊ณ , ์ฌ๋ฌ ํ ์คํธ๋ฅผ ํ๋ฒ์ ์คํํ๊ธฐ ์ด๋ ต๋ค. => Java๋ JUnit์ ์ฌ์ฉํด ํ๋ ์์ํฌ ํ ์คํธ ์ง์
- junit.jupiter.api๊ฐ ์ง์ํ๋ Assertions.assertEquals(member, result);์ ์ฌ์ฉํ์ฌ result์ member๊ฐ ๊ฐ์์ง ํ์ธํ๋ค. (์์ ํ๋ผ๋ฏธํฐ๊ฐ expected, ๋ค๊ฐ ๊ฒฐ๊ณผ. ์ ์ฅํ๋ ๋ฉค๋ฒ๊ฐ findํ์ ๋ ํ์ด๋์์ผํ๋ค.)
- assertj.core.api๊ฐ ์ง์ํ๋ Assertions๋ ์ข ๋ ํธํ๊ฒ ๋์ด์๋ค. Assertions.assertThat(member).isEqualTo(result);๋ก ์์ฑ๋๋ค๋ณด๋ ์์ด ๊ฐ๋ ์ฑ์ด ์ข๋ค.
- ๊ฐ๊ฐ์ ๊ด์ฐฎ๋ค๊ฐ Class๋ก test๋ฅผ ๋๋ฆฌ๋ฉด ๋ฌธ์ ๊ฐ ์๊ธด๋ค. findAll()์ด ๋จผ์ ์ฌ๋ผ๊ฐ๋๋ฐ, findAll()์์ ์ด๋ฏธ spring1, spring2๋ฅผ ์ ์ฅํด์ ๋ฌธ์ ๊ฐ ์๊ธด๋ค. ๊ทธ๋ฌ๋ฏ๋ก ๋ฐ์ดํฐ๋ฅผ ํ ๋ฒ clearํด์ผ ํ๋ค.
- ๊ฒ์ฆํ ์ ์๋ ํ์ ๋จผ์ ๋ง๋ค๊ณ , ์ํ์ด ์์ฑ๋๋ฉด ํ์ ๊ฝํ๋์ง ์๊ฝํ๋์ง๋ฅผ ํ ์คํธ ์ฃผ๋ ๊ฐ๋ฐ(TDD)๋ผ๊ณ ํ๋ค. ํ ์คํธ๋ ์์ฃผ ์ค์ํ๋ฏ๋ก ํ ์คํธ๋ฅผ ๊น์ด ์๊ฒ ๊ณต๋ถํ๊ธธ ๋ฐ๋๋ค๋ ๊ฐ์ฌ๋์ ์กฐ์ธ.
ํ์ ์๋น์ค ๊ฐ๋ฐ
- ๊ฐ์ด ์์ผ๋ฉด result.ifPresent๊ฐ ๋์ํ๋ค. Optional๋ก ํ ๋ฒ ๊ฐ์ธ๋ฉด, ์ต์ ๋ ์์ ์ฌ๋ฌ ๋ฉ์๋๊ฐ ์๊ณ ์ด๋ฅผ ์ฌ์ฉํ ์๊ฐ ์๋ค. ๊ณผ๊ฑฐ์๋ if null ์ด๋ฐ ์์ผ๋ก ์ฝ๋ฉํ์ง๋ง, null์ผ ๊ฐ๋ฅ์ฑ์ด ์์ผ๋ฉด ์ต์ ๋๋ก ๊ฐ์ธ์ค๋ค.
- result.orElseGet(โฆ) ์ ์ฌ์ฉํด์ ์์ฃผ ๊บผ๋ธ๋ค. (์์ผ๋ฉด ๊บผ๋ด๊ณ , ์์ผ๋ฉด ๋ํดํธ๊ฐ์ ๊บผ๋ธ๋ค)
- ์ด์ฐจํผ Optional๋ก ๋ฆฌํด์ด ๋๊ธฐ ๋๋ฌธ์ ๋ฐ๋ก ifPresent๋ก ๋ฐ์์ค๋ค.
- Extract Method๋ฅผ ํตํด ๋ฐ๋ก๋ฐ๋ก ๋ฉ์๋๋ฅผ ๋ง๋ค์ด์ค ์ ์๋ค.
public class MemberService {
private final MemberRepository memberRepository = new MemoryMemberRepository();
/* ํ์ ๊ฐ์
*/
public Long join(Member member) {
// ๊ฐ์ ์ด๋ฆ์ด ์๋ ์ค๋ณต ํ์ ๊ธ์ง
validateDuplicateMember(member);
memberRepository.save(member);
return member.getId();
}
private void validateDuplicateMember(Member member) {
memberRepository.findByName(member.getName())
.ifPresent(m -> {
throw new IllegalStateException("์ด๋ฏธ ์กด์ฌํ๋ ํ์์
๋๋ค.");
});
}
/* ์ ์ฒด ํ์ ์กฐํ */
public List<Member> findMembers() {
return memberRepository.findAll();
}
public Optional<Member> findOne(Long memberId) {
return memberRepository.findById(memberId);
}
}
ํ์ ์๋น์ค ํ ์คํธ
- ์ด์ ์ ๋นํด ๋น ๋ฅด๊ฒ ํ๋ ๋ฐฉ๋ฒ
Ctrl
+Shift
+T
: Go to Test - Test๋ ์ฌ์ค ๋ฉ์๋ ์ด๋ฆ์ ํ๊ธ๋ก ํด๋ ํฐ ์๊ด์ด ์๋ค.
- given, when, then ๋ฌธ๋ฒ
- given : ์ด๋ฐ ์ํฉ์ด ์ฃผ์ด์ก๋๋ฐ
- when : ์ด๊ฑธ ์คํํ์ ๋
- then : ๊ฒฐ๊ณผ๋ก ์ด๊ฒ ๋์์ผํ๋ค
- ์ง๊ธ test ๊น์ง ๋๋ ธ๋๋ฐ ์๋์๊ฐ์ ์๋ฌ ํด๊ฒฐ์ค => spring์ผ๋ก name์ ๋ ๊ฐ ์คฌ์ด์ผ ํ๋๋ฐ, ํ๊ฐ๋ฅผ Spring์ผ๋ก ์ค์ ์๋ฌ๊ฐ ๋ฌ์๋ค.
- ์๋ก ๋ค๋ฅธ ๋ฆฌํ์งํ ๋ฆฌ๋ก ํ ์คํธํ๊ณ ์๊ธฐ ๋๋ฌธ์, ๊ฐ์ ์ธ์คํด์ค๋ฅผ ์ธ ์ ์๋๋ก ๋ฉค๋ฒ์๋น์ค์์ Alt enter ๋๋ฌ์ ์ธ๋ถ์์ ๋ฃ์ด์ฃผ๋๋ก this.member โฆ ๋ก ๋ฐ๊พผ๋ค. ๋ฉค๋ฒ์๋น์ค ์ ์ฅ์์๋ ๋ฉค๋ฒ๋ฆฌํ์งํ ๋ฆฌ๋ฅผ ์ธ๋ถ์์ ๋ฃ์ด์ฃผ๋ฏ๋ก, ์ด๋ฅผ Dependency Induction(DI)๋ผ๊ณ ํ๋ค. ์ด๋ ๋ค์ ์๊ฐ์ ๋ ์์ธํ ์์๋ณผ ์์ .
[๋จ์ถํค]
Alt
+Insert
: GenerateCtrl
+Space
: importAlt
+Shift
+Enter
: import class (ex. HashMap)Shift
+F6
: Rename (๋น ๋ฅด๊ฒ ๋ณ์๋ฅผ ๋ณต๋ถํ๊ณ ์ด๋ฆ๋ง ๋ฐ๊พธ๊ธฐ)Ctrl
+B
: Go to Declaration or UsagesCtrl
+W
: Extend Selection (ํฌ์ปค์ค ๋ฒ์ ํ ๋จ๊ณ์ฉ ๋๋ฆฌ๊ธฐ)Ctrl
+Shift
+Del
: Navigate -> BackCtrl
+D
: ํฌ์ปค์ฑํ ๋ด์ฉ์ ๊ทธ๋๋ก duplicateํ๋คCtrl
+Alt
+V
: return์ ์๋์ผ๋ก ํด์ค๋ค.Ctrl
+Alt
+Shift
+T
: Extract MethodCtrl
+Shift
+T
: Go to Test
[๋ ํผ๋ฐ์ค]
- ์๋ฐ ์คํธ๋ฆผ ํฌ์คํธ