๋ชฉ๋ก์ ์ฒด ๊ธ (124)
DevLog ๐ถ
๐ฑ ๋ฌธ์ ์ํฉ ํ๋ก์ ํธ๋ฅผ ์งํํ๋ฉด์ ๋์ ์ฟผ๋ฆฌ๋ฅผ ์์ฑํ ์ผ์ด ๋ง์ QueryDSL์ ๋์ ํ๊ฒ ๋์๋๋ฐ, ์ด๋ฒ์ ์๋ค๋ฅธ ์ค๋ฅ๋ฅผ ๋ฐ๊ฒฌํ๊ฒ ๋์๋ค. java.lang.NullPointerException: Cannot read field "id" because "co.kirikiri.domain.goalroom.QGoalRoomMember.goalRoomMember.goalRoom.roadmapContent.roadmap" is null NPE๋ฅผ ๋ณธ ๊ฑด ์ค๋๋ง์ด์ด์ ์กฐ๊ธ ์ฝ์ง์ ์งํํ๋ค. ๐ฑ ๋๋ฉ์ธ ๊ตฌ์กฐ ์ง๋ ํฌ์คํ ๊ณผ ๊ฐ์ ํ๋ก์ ํธ์ด๊ธฐ ๋๋ฌธ์ ๋๋ฉ์ธ ๊ตฌ์กฐ๋ ๊ฑฐ์ ๋์ผํ๋ฐ, ์ ๋ฌธ์ ์ํฉ์ ์ดํดํ๊ธฐ ์ํ ์ถ๊ฐ์ ์ธ ๋๋ฉ์ธ ์ ๋ณด๊ฐ ํ์ํ๋ค. ํ๋์ ๋ก๋๋งต ๋ณธ๋ฌธ(RoadmapContent) ์ ๋ณด์ ๋ํด์ ์ฌ๋ฌ ๊ฐ์ ..
์ฌ์ค ๋ฐํ๊ฐ ๋ ์ง๋ ๊ฝค ๋์ง๋ง ๋ธ๋ก๊ทธ์ ๊ธฐ๋ก์ผ๋ก ๋จ๊ฒจ๋๋ฉด ์ข์ ๊ฒ ๊ฐ์์ ์ฐ๋ ๊ธ ๐ ์ถํ 2024 NEXT๊ฐ ์งํ๋์์ ๋ ๋์์ด ๋ ๋ถ๋ค์ด ์์์ผ๋ฉด ์ข๊ฒ ๋ค! ๐ฑ ์ค๋น ์ฌ์ ์ฌํด 6์ ๋ง ์ ๋, ํ ์ค์์ 2023 NEXT ๊ฐ๋ฐ์ ์ฑ๋ฆฐ์ง๋ฅผ ํตํด์ 3๋ ์ดํ์ ๊ฐ๋ฐ์๋ฅผ ์ฑ์ฉํ๋ค๋ ๊ณต๊ณ ๋ฅผ ๋๋ค. ์ฌ์ค ์ฐํ ์ฝ๋ฅผ ์งํํ๋ฉด์ ์ฌํด ์์๋ ๋ณธ๊ฒฉ์ ์ธ ์ทจ์ ์ค๋น๋ฅผ ํ ์๊ฐ์ด ์์์ด์, ๊ทธ๋ฅ ๊ฒฝํ ํ ๋ฒ ํด๋ณด์๋ ์๊ฐ์ผ๋ก ๋น๋นํ๊ฒ ์ง์ํ๋ค. Core Banking์ด๋ Server ์ค์ ์ด๋ค ๊ฑธ ํ ์ง ๊ณ ๋ฏผํ๋๋ฐ, ๊ธ์ต ๊ด๋ จ ๋๋ฉ์ธ์ ๋ํ ์ดํด๋๊ฐ ํ์ ํ ๋ฎ์์ง๋ผ Server ์ชฝ ์ง๋ฌด๋ก ์ง์ํ๊ฒ ๋์๋ค. ๋ถ์ผ๋ณ ์ด๋ ํํธ๋ฅผ ํ๊ณ ์ถ์์ง๋ ์ฒ์์ ๋ฃ์ ์ ์๋๋ฐ, ๊ทธ๋๋ ํ ์ค๋ ํ ์ค๋ฑ ํฌ๋ฅผ ๋ฃ์๋ค. ์ฝ๋ฉ ํ ์คํธ > ์ง๋ฌด ์ธํฐ..
๐ฑ ๋ค์ด๊ฐ๊ธฐ ์ ์ฐ๋ฆฌ ํ์ ๊ฒฝ์ฐ E2E ํ ์คํธ ํ๊ฒฝ์ ๊ตฌ์ถํ๊ธฐ ์ํด์ @SpringBootTest๋ฅผ ํตํด ํ ์คํธ ์ฝ๋๋ฅผ ์์ฑํ๊ณ ์๋๋ฐ, ์ฐ๋ฆฌ ํ์ ํ์๋ถ์ด ์๋์ ๊ฐ์ ์ค๋ฅ๋ฅผ ๋ง๋๊ฒ ๋์๋ค. failed to lazily initialize a collection of role: co.kirikiri.domain.roadmap.RoadmapContent.nodes.values: could not initialize proxy - no Session ์ํฉ์ ์๋์ ๊ฐ๋ค. (์ถํ ์ฝ๋๋ก ๋ ์ ์ดํด๋ณผ ์์ ์ด๋ค.) A๋ผ๋ ์์ฑ API์ B๋ผ๋ ์กฐํ API๊ฐ ์์ ๋, ํ ๋ด์์ ๊ธฐ๋ฅ์ ์ธ๋ถํํ ๋ค์ ๊ฐ์ ๊ฐ๋ฐ์ ์งํํ๋ค ๋ณด๋ B๋ฅผ ๊ฐ๋ฐํ๋ ์์ ์ A๋ผ๋ API๊ฐ ์์ด, ํตํฉ ํ ์คํธ ๋ repository๋ฅผ ..
๐ฑ ๋ค์ด๊ฐ๊ธฐ ์ ์ฐ๋ฆฌ ํ์ CI ํ๋ก์ฐ ๊ณผ์ ์ค์์ Jacoco๋ฅผ ํ์ฉํ์ฌ ํ ์คํธ ๋ฆฌํฌํธ๋ฅผ ๋ฐํํ๊ณ , ์ปค๋ฒ๋ฆฌ์ง๋ฅผ ์ฒดํฌํ๊ณ ์๋ค. (ํ ์คํธ๋ฅผ ์ ๋ง ์ฒ ์ ํ๊ฒ ํ์๋ ์ทจ์ง์ธ๋ฐ, ํ์ ๋ชจ๋๊ฐ ํ ์คํธ๋ฅผ ์ ๋ง ๊ผผ๊ผผํ๊ฒ ์์ฑํด ์ฃผ์ ์ ์ข๋ค ๐) CI์ ๋ํ ๊ธ์ ๋ค์์ ์์ ํ๊ฒ ๊ตฌ์ถ๋ ์ดํ์ ์์ฑํ๋ ๊ฒ ์ข์ ๊ฒ ๊ฐ์์, ์ค๋์ Jacoco์ ๋ํด์๋ง ๊ฐ๋ณ๊ฒ ์ง๊ณ ๋์ด๊ฐ๊ณ ์ ํ๋ค. ๐ฑ Jacoco ์ค์ ํ๊ธฐ Jacoco๋, ํ ์คํธ ์ฝ๋ ์ปค๋ฒ๋ฆฌ์ง๋ฅผ ๋ถ์ํด์ฃผ๋ ์๋ฐ์ ๋ฌด๋ฃ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ด๋ค. Jacoco ํ๋ฌ๊ทธ์ธ์๋ JacocoTestReport์ JacocoTestCoverageVerification Task ๋ฑ์ด ์กด์ฌํ๋ค. (์ฌ๊ธฐ์๋ ์ด 2๊ฐ์ง๋ฅผ ์์ฃผ๋ก ์์๋ณด๋๋ก ํ์.) - JacocoTestReport: ์ปค๋ฒ๋ฆฌ์ง ๊ฒฐ๊ณผ..
๐ฑ ๋ค์ด๊ฐ๊ธฐ ์ JPA์์ @OneToMany ๋จ๋ฐฉํฅ ๋งคํ๋ณด๋ค๋ ๋ค๋์ผ ์๋ฐฉํฅ ๋งคํ์ ๊ถ์ฅํ๋ค๋ ๋ง์ ๋ณด์์ ๊ฒ์ด๋ค. ํ์ง๋ง, ๊ฐ์ฒด์งํฅ์ผ๋ก ์ฝ๋๋ฅผ ์ค๊ณํ๋ค ๋ณด๋ฉด ๋ค๋์ผ์ ์ํฉ๋ณด๋ค๋ 1์ธ ์ํฐํฐ๋ฅผ ๊ธฐ์ค์ผ๋ก N์ธ ์ํฐํฐ๋ฅผ ์กฐํํ๋ ๊ฒฝ์ฐ๊ฐ ๋ ๋ง๊ณ , (์ ์ด๋ ๋ด ๊ฒฝํ์์๋ ๊ทธ๋ฌ๋ค) N์ธ ์ํฐํฐ๊ฐ ๊ตณ์ด 1์ธ ์ํฐํฐ์ ๋ํ ์ ๋ณด๋ฅผ ๋ชฐ๋ผ๋ ๋๋ ์ ์ด ๋ง์๋ค. ๊ทธ๋ฌ๋ค ๋ณด๋ ์์ฐ์ค๋ฝ๊ฒ ์ผ๋๋ค ๋จ๋ฐฉํฅ ๋งคํ์ ๋ง์ด ์ฌ์ฉํ์๋๋ฐ, ์ ๊ทธ๋ฌ๋ ๊ฒ์ธ์ง ๊ถ๊ธํด์ ๋๋ฆ๋๋ก ์คํ์ ํด๋ณด๊ณ ์ ํ๋ค. (ex. ๊ฒ์๊ธ๊ณผ ๊ฒ์๊ธ ์ด๋ฏธ์ง์ ๊ด๊ณ์์, ๊ฒ์๊ธ ์ด๋ฏธ์ง๋ฅผ ๊ธฐ์ค์ผ๋ก ๊ฒ์๊ธ ์ ๋ณด๋ฅผ ์ฐพ์์ค๋ ๊ฒ๋ณด๋ค๋ ๊ฒ์๊ธ์ ๊ธฐ์ค์ผ๋ก ๊ฒ์๊ธ ์ด๋ฏธ์ง ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค๋ ๊ฒ ๋ ๋ง์์) ๐ฑ ๊ธฐ๋ณธ ์ํฐํฐ ์ค๊ณํ๊ธฐ @Entity class Board( @Id @..
๐ฑ ๋์คํฌ ์ฝ๊ธฐ ๋ฐฉ์ ๐ฌ HDD (ํ๋ ๋์คํฌ ๋๋ผ์ด๋ธ) / SSD (์๋ฆฌ๋ ์ค๋ ์ดํธ ๋๋ผ์ด๋ธ) ๋ฉ๋ชจ๋ฆฌ์ ๋นํด ์ค์ ํ๋์จ์ด ์ฅ์น์ ๋ฐ์ ์ ๋น๊ต์ ๋๋ฆฌ๊ฒ ๋ฐ์ ํ๋ค๋ ์๋ฆฌ๋ฅผ ๋ค์ ์ ์ด ์์ ๊ฒ์ด๋ค. ํนํ HHD๋ ํ๋ํฐ(์ํ)์ ๋๋ ค์ ์ฝ๊ณ ๋ ์ฐ๋ค ๋ณด๋ ์ฑ๋ฅ์ด ๋งค์ฐ ๋๋ฆด ์๋ฐ์ ์๋ค. ์ด๋ฅผ ๋ณด์ํ๊ธฐ ์ํด ๋ฑ์ฅํ SSD์ ๊ฒฝ์ฐ ๊ธฐ์กด ํ์คํฌ ๋๋ผ์ด๋ธ์์ ๋ฐ์ดํฐ ์ ์ฅ์ฉ ํ๋ํฐ(์ํ)์ ์ ๊ฑฐํ๊ณ ๊ทธ ๋์ ํ๋์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ฅ์ฐฉํด์ ๋น ๋ฅด๊ฒ ๋ฐ์ดํฐ๋ฅผ ์ฝ๊ณ ์ธ ์ ์๋ค. ํ๋์ ๋ฉ๋ชจ๋ฆฌ๋ ์ ์์ด ์์ด๋ ๋ฐ์ดํฐ๊ฐ ์ญ์ ๋์ง ์์ผ๋ฉฐ, ๋ฉ๋ชจ๋ฆฌ๋ณด๋ค๋ ๋๋ฆฌ์ง๋ง ๊ทธ๋๋ ํ๋ ๋์คํฌ ๋๋ผ์ด๋ธ๋ณด๋ค๋ ํจ์ฌ ๋น ๋ฅด๋ค. ๐ฌ ๋๋ค I/O์ ์์ฐจ I/O ๋์คํฌ ์ฝ๊ธฐ ์ฐ์ฐ์์ '๋๋ค I/O'์ '์์ฐจ I/O'๋ผ๋ ๋ง์ ๋ค์ ์ ์ด ์์ ๊ฒ์ด๋ค. ๋๋ค ..
๐ฑ ์ฝ๋ผ๋ฆฌ๋ผ๋ฆฌํ ๊ฒฐ์ฑ! ๋๋์ด ๋ ๋ฒจ 3์ด ์์ํ๋ฉด์ ๋ณธ๊ฒฉ์ ์ธ ํ ํ๋ก์ ํธ๊ฐ ์งํ๋์๋ค. ์์ ๋ ๋ฒจ 2 ํ๊ณ ๋ ์ธ๊ธํ๋ ๊ฒ์ฒ๋ผ, ์ด์ด ์ข๊ฒ๋ ๋ด๊ฐ ์์ด๋์ด๋ฅผ ๋๋ ์ฃผ์ ๋ก ํ๋ก์ ํธ๋ฅผ ์งํํ ์ ์๊ฒ ๋์๋ค. ๋ ๋ฌ ๋์ ํจ๊ป ํ ํฌ๋ฃจ๋ ๋๋ , ์ฌ์ท, ๋ฐ๋ฆฌ, ์ฐ๋, ๋ค์ด๋ธ, ๋ถ์์ด์๋ค. ์ฝ ์ผ์ฃผ์ผ ์ ๋ ํจ๊ป ์งํํ๋ฉด์, ์ฐ๋ฆฌ ํ์ ๋ฐธ๋ฐ์ค๊ฐ ์๋นํ ์ข๋ค๋ ์๊ฐ์ด ์์ฃผ ๋ค์๋ค. ๊ธฐ๋ณธ์ ์ผ๋ก ๋ค๋ค ๋ํํ ๋ ๋์ ๋ง์ฃผ์น๊ณ ๊ฒฝ์ฒญ์ ์ํด์ฃผ์๊ธฐ๋ ํ๊ณ , ๊ทธ๋ ๋ค๊ณ ๋ง์ด ์๋ ๊ฒ๋ ์๋๊ณ ํ์๋ ๊ฝค ์ฌ๋ฐ๊ฒ ์งํ๋๋ ๋ถ๋ถ์ด ์์ด์ ์ข๋ค. ์ ๋นํ ๋ดํฅ์ ์ด๋ฉด์ ์ธํฅ์ ์ธ ์ฌ๋๋ค์ด ์ ๋ง๋ ๊ธ์ ์ ์ธ ์ผ์ด์ค๋ฅผ ๋ณด๋ ๋๋....? ํนํ ํ ๋ก ํ ๋งํ ์ฃผ์ ์ ๋ํด์ 20๋ถ, 30๋ถ๋ ์ฌ๋์๊ฒ ํ ๋ก ํ๋ ์๊ฐ๋ค์ด ๊ต์ฅํ ์ข์๋ค. ์์ผ๋ก๋ ๊ณ์ ..
๐ฑ JPA ๊ธฐ๋ณธ ํค ์์ฑ ์ ๋ต JPA์์ ์ ๊ณตํ๋ ๊ธฐ๋ณธ ํค ์์ฑ ์ ๋ต์ ํฌ๊ฒ 5๊ฐ์ง๋ก ๋๋์ด์ง๋ค. - TABLE, SEQUENCE, IDENTITY, UUID, AUTO ๊ฐ ์ ๋ต์ ๋ํด์ ํ๋์ฉ ์์๋ณด๋๋ก ํ์. ๐ฑ TABLE ๐ก Indicates that the persistence provider must assign primary keys for the entity using an underlying database table to ensure uniqueness. - ๋ฐ์ดํฐ๋ฒ ์ด์ค ํ ์ด๋ธ์ ์ฌ์ฉํ์ฌ ์ํฐํฐ์ ๊ธฐ๋ณธ ํค๋ฅผ ํ ๋นํด์ผ ํ๋ค. ๐ฌ ์ํฐํฐ ์ค์ @Entity class User( @Id @GeneratedValue(strategy = GenerationType.TABLE) val id: Lon..
๐ฑ ๋ค์ด๊ฐ๊ธฐ ์ ์ง๋ ํฌ์คํ ์์๋ CascadeType.REMOVE์ ๋ํด์ ์ค์ ์ ์ผ๋ก ์์๋ดค์๋๋ฐ, ์ด๋ฒ์๋ orphanRemoval=true ์ต์ ์ ๋ํด์ ํ ๋ฒ ์์๋ณด์. ์ํฐํฐ ์ธํ ์ ์ง๋ ๋ฒ๊ณผ ๊ฑฐ์ ๋์ผํ๊ธฐ ๋๋ฌธ์ ๋ณํ๊ฐ ์๊ธด ๋ถ๋ถ์ ๋ํด์๋ง ๋ฐ๋ก ์ง๋๋ก ํ๊ฒ ๋ค. ๐ฑ ์ํฐํฐ ์์ ํ๊ธฐ ์ด๋ฒ์๋ CascadeType.REMOVE ๋์ ์ orphanRemoval=true๋ฅผ ์ ์ฉํ์. @Entity class Concert( @Id @GeneratedValue(strategy = GenerationType.IDENTITY) val id: Long = 0L, @Column(nullable = false) val name: String, @Column(nullable = false) val ticketLi..
๐ฑ ๋ค์ด๊ฐ๊ธฐ ์ JPA๋ฅผ ๊ณต๋ถํ๋ฉด์ CascadeType.REMOVE์ orphanRemoval = true ์ต์ ์ ๋ํด์ ์ด๋ค ์ฐจ์ด๊ฐ ์๋์ง ์ ๋๋ก ์ธ์งํ ์ ์ด ์๋ ๊ฒ ๊ฐ์์, ์ด๋ฒ์ ๊ณต๋ถํ ๊ฒธ ์ฌ๋ฌ ๊ฐ์ง ํ ์คํธ๋ฅผ ์งํํด๋ณด๋ฉฐ ๋ ์ต์ ์ ์ฐจ์ด๋ฅผ ๊ณต๋ถํด๋ณด์๋ค. ๊ฒฐ๊ณผ์ ์ผ๋ก ๋งํ์๋ฉด Cascade ์ต์ ์ ๋ถ๋ชจ ์ํฐํฐ์ ์์ ์ํฐํฐ์ ์์ ์ํ๋ฅผ ๊ด๋ฆฌํ๋ ๊ฒ์ด๊ณ , orphanRemoval์ ์กฐ๊ธ ๋ ์ธ๋ถ์ ์ผ๋ก ๊ณ ์ ๊ฐ์ฒด์ ๋ํ ๊ด๋ฆฌ๋ผ๋ ์๊ฐ์ด ๋ค์๋ค. ์ง๊ธ๋ถํฐ ์ฌ๋ฌ ์ผ์คํธ๋ฅผ ํ ์คํธํ๋ฉฐ ํ๋์ฉ ์์๋ณด์. ๐ฑ ์ํฐํฐ ์ธํ ํ๊ธฐ 1:N ๊ด๊ณ๋ฅผ ๋ด๋นํด์ค '์ฝ์ํธ' ์ํฐํฐ์ '์ฝ์ํธ ํฐ์ผ' ์ํฐํฐ๋ฅผ ์์ฑํ์๋ค. ๋ ์ฌ์ด์ ๊ด๊ณ๋ ์๋ฐฉํฅ์ผ๋ก ์ค์ ํ์์ผ๋ฉฐ, ํ๋์ ์ฝ์ํธ๋ ์ฌ๋ฌ ๊ฐ์ ์ฝ์ํธ ํฐ์ผ์ ๋ณด์ ํ ์ ์๋๋ก ์ค๊ณํ์..