Backend Ddevelopment
π Intro
- λκΈ μμ€ν
μμ κ° λκΈμ κ²½λ‘(path)λ₯Ό κ΄λ¦¬νλ λ°©μμ κ³μΈ΅μ ꡬ쑰λ₯Ό μ μ§νλ©΄μλ λΉ λ₯΄κ² κ²μν μ μλλ‘ μ€κ³λμ΄μΌ ν©λλ€.
- λ³Έ κΈμμλ
CommentPath
ν΄λμ€λ₯Ό λΆμνκ³ , νμ λκΈμ΄ μμ±λλ κ³Όμ κ³Ό κ΄λ ¨λ λ‘μ§μ μ€λͺ
ν©λλ€.
package kobe.board.comment.entity;
import jakarta.persistence.Embeddable;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;
@Getter
@ToString
@Embeddable
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class CommentPath {
private String path;
private static final String CHARSET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
private static final int DEPTH_CHUNK_SIZE = 5;
private static final int MAX_DEPTH = 5;
// MIN_CHUNK = "00000", MAX_CHUNK = "zzzzz"
private static final String MIN_CHUNK = String.valueOf(CHARSET.charAt(0)).repeat(DEPTH_CHUNK_SIZE);
private static final String MAX_CHUNK = String.valueOf(CHARSET.charAt(CHARSET.length() - 1)).repeat(DEPTH_CHUNK_SIZE);
public static CommentPath create(String path) {
if (isDepthOverflowed(path)) {
throw new IllegalStateException("depth overflowed");
}
CommentPath commentPath = new CommentPath();
commentPath.path = path;
return commentPath;
}
private static boolean isDepthOverflowed(String path) {
return calculateDepth(path) > MAX_DEPTH;
}
private static int calculateDepth(String path) {
// 25κ°μ λ¬Έμμ΄ / 5 = 5depth
return path.length() / DEPTH_CHUNK_SIZE;
}
// CommentPath ν΄λμ€μ pathμ depthλ₯Ό ꡬνλ 맀μλ
public int getDepth() {
return calculateDepth(path);
}
// rootμΈμ§ νμΈνλ 맀μλ
public boolean isRoot() {
// νμ¬μ depthκ° 1μΈμ§ νμΈν΄μ£Όλ©΄ λ¨
return calculateDepth(path) == 1;
}
// νμ¬ pathμ parentPathλ₯Ό λ°νν΄μ£Όλ 맀μλ
public String getParentPath() {
// λ 5μλ¦¬λ§ μλΌλ΄λ©΄ λ¨
return path.substring(0, path.length() - DEPTH_CHUNK_SIZE);
}
// νμ¬ pathμ νμ λκΈμ pathμ λ§λλ 맀μλ
public CommentPath createChildCommentPath(String descendantsTopPath) {
if (descendantsTopPath == null) {
return CommentPath.create(path + MIN_CHUNK);
}
String childrenTopPath = findChildrenTopPath(descendantsTopPath);
return CommentPath.create(increase(childrenTopPath));
}
// 00a0z0000200000 <- descendantsTopPath
private String findChildrenTopPath(String descendantsTopPath) {
return descendantsTopPath.substring(0, (getDepth() + 1) * DEPTH_CHUNK_SIZE);
}
private String increase(String path) {
// pathμμ κ°μ₯ λ§μ§λ§ 5μ리λ₯Ό μλ₯Έ κ²
String lastChunk = path.substring(path.length() - DEPTH_CHUNK_SIZE);
if (isChunkOverflowed(lastChunk)) {
throw new IllegalStateException("chunk overflowed");
}
// Character setμ κΈΈμ΄
int charsetLength = CHARSET.length();
// lastChunkλ₯Ό 10μ§μλ‘ λ¨Όμ λ³ννκΈ° μν κ°μ μ μ₯
int value = 0;
for (char character : lastChunk.toCharArray()) {
value = value * charsetLength + CHARSET.indexOf(character);
}
value = value + 1;
String result = "";
for (int i = 0; i < DEPTH_CHUNK_SIZE; i++) {
result = CHARSET.charAt(value % charsetLength) + result;
value /= charsetLength;
}
return path.substring(0, path.length() - DEPTH_CHUNK_SIZE) + result;
}
private boolean isChunkOverflowed(String lastChunk) {
return MAX_CHUNK.equals(lastChunk);
}
}
- CommentPath ν΄λμ€λ λκΈμ κ³ μ ν κ²½λ‘(path)λ₯Ό κ΄λ¦¬νλ μν μ ν©λλ€.
- κ²½λ‘λ λ¬Έμμ΄λ‘ ννλλ©°, κ° λκΈμ depthλ₯Ό μ μ§νλ©΄μ νμ λκΈμ μ½κ² μ°Ύμ μ μλλ‘ κ΅¬μ±λ©λλ€.
π1οΈβ£ μ£Όμ μμ λ° λ³μ.
-
CHARSET : 0-9, A-Z, a-zλ‘ κ΅¬μ±λ μ΄ 62κ°μ λ¬Έμ μ
-
DEPTH_CHUNK_SIZE = 5 : λκΈ κΉμ΄λ₯Ό λνλ΄λ λ¨μ ν¬κΈ°
-
MAX_DEPTH = 5 : λκΈμ μ΅λ κΉμ΄
-
MIN_CHUNK = β00000β : κ²½λ‘μμ μ¬μ©λ μ΅μ λ¨μ λ¬Έμμ΄
-
MAX_CHUNK = βzzzzzβ : κ²½λ‘μμ μ¬μ©λ μ΅λ λ¨μ λ¬Έμμ΄
- μ΄ λ©μλλ μλ‘μ΄ CommentPath κ°μ²΄λ₯Ό μμ±νλ μ μ ν©ν 리 λ©μλμ
λλ€.
π1οΈβ£ λμ κ³Όμ .
-
1. isDepthOverflowed(path)λ₯Ό νΈμΆνμ¬ pathμ κΉμ΄κ° MAX_DEPTH = 5λ₯Ό μ΄κ³Όνλμ§ νμΈν©λλ€.
-
calculateDepth(path) > MAX_DEPTHμ΄λ©΄ IllegalStateExceptionμ λμ§λλ€.
-
2. CommentPath κ°μ²΄λ₯Ό μμ±ν©λλ€.
-
3. κ°μ²΄μ path νλλ₯Ό pathλ‘ μ€μ ν©λλ€.
-
4. μλ‘ μμ±λ CommentPath κ°μ²΄λ₯Ό λ°νν©λλ€.
- μ΄ λ©μλλ μ£Όμ΄μ§ descendantsTopPathλ₯Ό κΈ°λ°μΌλ‘ μλ‘μ΄ νμ λκΈμ pathλ₯Ό μμ±νλ μν μ ν©λλ€.
π1οΈβ£ λμ κ³Όμ .
-
1. descedantsTopPathκ° nullμ΄λ©΄ path + MIN_CHUNK(β00000β)λ₯Ό μΆκ°νμ¬ CommentPathλ₯Ό μμ±νκ³ λ°νν©λλ€.
-
2. findChildrenTopPath(descendantsTopPath)λ₯Ό νΈμΆνμ¬ childrenTopPathλ₯Ό μ°Ύμ΅λλ€.
-
descendantsTopPathμμ depth + 1 κΈΈμ΄λ§νΌ λ¬Έμμ΄μ μλ¦
λλ€.
-
3. increase(childrenTopPath)λ₯Ό νΈμΆνμ¬ μ΄μ νμ λκΈ path κ°μμ 1μ μ¦κ°μν΅λλ€.
-
4. μ¦κ°λ childrenTopPathλ₯Ό κΈ°λ°μΌλ‘ μλ‘μ΄ CommentPath κ°μ²΄λ₯Ό μμ±νκ³ λ°νν©λλ€.
β
4οΈβ£ β00000βμ΄ μμ±λλ €λ©΄ μ΄λ€ κ³Όμ μ κ±°μ³μΌ ν κΉ?
-
1. createChildCommentPath(null)μ΄ νΈμΆλ©λλ€.
-
2. descendantsTopPathκ° nullμ΄λ―λ‘ path + MIN_CHUNKκ° CommentPath.creat()μ μ λ¬λ©λλ€.
-
3. CommentPath.create() λ΄λΆμμ isDepthOverflowed κ²μ¬λ₯Ό ν΅κ³Όνλ©΄ μλ‘μ΄ CommentPath κ°μ²΄κ° μμ± λ©λλ€.
-
4. path κ°μ λΆλͺ¨ path + β00000βμ΄ λ©λλ€.
β
5οΈβ£ β0000000000βμ΄ μμ±λλ €λ©΄ μ΄λ€ κ³Όμ μ κ±°μ³μΌ ν κΉ?
-
1. createdChildCommentPath(null)μ΄ λ λ² νΈμΆλμ΄μΌ ν©λλ€.
-
2. 첫 λ²μ§Έ νΈμΆ:
- descendantsTopPath = null
- path + β00000βμ CommentPath.create()λ‘ μ λ¬νμ¬ β00000βμ΄ μμ±λ¨.
-
3. λ λ²μ§Έ νΈμΆ:
- descendantsTopPath = β00000β
- β00000βμ νμ λκΈμ λ§λ€ λ path + β00000βμ μΆκ°νμ¬ β0000000000βμ μμ±.
- μ¦, 2λ¨κ³ νμ λκΈ μμ± κ³Όμ μ΄ νμν©λλ€.
β
6οΈβ£ νΉμ descendantsTopPathκ° μ£Όμ΄μ‘μ λ childrenTopPathκ° μ΄λ»κ² λ³ν κΉμ?
π μμ: descendantsTopPath = β00000β, childrenTopPath = β00001β
- 1. createChildCommentPath(β00000β)κ° νΈμΆλ¨.
-
2. findChildrenTopPath(β00000β) νΈμΆ:
- descendantsTopPath = β00000β
-
getDepth() + 1 = 2 β depth 2 κΉμ§μ 5μ리(00000)λ₯Ό κ°μ Έμ΄.
- childrenTopPath = β00000β
-
3. increase(β00000β) μ€ν:
- 62μ§μ μ°μ°μΌλ‘ β00000β β β00001βλ‘ λ³ν.
- 4. β00001βμ΄ pathλ‘ μ€μ λ CommentPath κ°μ²΄κ° μμ±λ¨.
- μ¦, increase(β00000β) μ°μ°μ ν΅ν΄ β00001βμ΄ μμ±λ©λλ€.
β
7οΈβ£ νΉμ μν©μμ μλ‘μ΄ λκΈμ pathλ₯Ό μμ±νλ κ³Όμ
π μμ: descendantsTopPath = β0000zβ, νμ λκΈμ΄ βabcdzβ > βzzzzzβ > βzzzzzβ μΌ λ, βabcdzβμ sibling λκΈ μμ±
-
1. νμ¬ descendantsTopPathλ β0000zβμ΄λ―λ‘ μ΄ λκΈμ΄ μν νμ λκΈλ€μ΄ μ‘΄μ¬ν¨.
-
2. createChildCommentPath(βzzzzzβ) μ€ν β κ°μ₯ ν° νμ pathλ₯Ό κΈ°μ€μΌλ‘ μλ‘μ΄ pathλ₯Ό μμ±ν΄μΌ ν¨.
-
3. findChildCommentTopPaht(βzzzzzβ) μ€ν:
- βzzzzzβμ depth + 1 κΈΈμ΄κΉμ§ μλ¦ β βzzzzzβ
-
4. increase(βzzzzzβ) μ€ν:
- βzzzzzβμμ μ¦κ°λ κ° βaaaaaβκ° λμ΄
- νμ§λ§ βabcdzβ μ κ°μ depthμ μλ‘μ΄ λκΈμ λ§λ€λ €λ©΄ βabcdzβμ sibling λκΈμ΄ λμ΄μΌ ν¨.
-
5. increase(βabcdzβ) μ€ν:
- βabcdzβμμ μ¦κ°λ κ° βabce0βκ° μμ±λ¨.
- π κ²°λ‘ : μ΅μ’
μ μΌλ‘ μμ±λ βabce0βμ βpathβλ λΆλͺ¨ βpathβ + βabce0β μ¦, path = β0000zabce0βμ΄ λ©λλ€.
β
8οΈβ£ κ²°λ‘
-
CommentPathλ₯Ό μ΄μ©νλ©΄ κ³μΈ΅μ λκΈ μμ€ν
μ ν¨κ³Όμ μΌλ‘ ꡬνν μ μμ΅λλ€.
- νμ λκΈμ pathλ₯Ό 62μ§μ λ¬Έμμ΄ μ¦κ° λ°©μμΌλ‘ κ΄λ¦¬νμ¬, λΉ λ₯Έ μ λ ¬ λ° κ²μμ΄ κ°λ₯ν©λλ€.
-
increase μ°μ°μ ν΅ν΄ νμ λκΈμ λμ μΌλ‘ μμ±νλ©°, κ²½λ‘ μ€λ²νλ‘μ°λ₯Ό λ°©μ§ν μ μμ΅λλ€.
- μ΄λ¬ν λ°©μμ νΈλ¦¬ ꡬ쑰λ₯Ό ν¨μ¨μ μΌλ‘ μ μ₯νκ³ μ‘°ννλ λ°©λ²μΌλ‘, λκ·λͺ¨ λκΈ μμ€ν
μμλ μ μ©νκ² μ μ©λ μ μμ΅λλ€.