[삭제된 게시물입니다]
알림
|
페이지 정보
본문
[이 게시물은 작성자가 삭제했습니다.]
댓글 21
원츠마인드님의 댓글의 댓글
@개발용님에게 답글
저도 둘다 쓰고 있는데, 쓰다가 뭐가 더 좋을까 고민하게 되네요.
특히 확장성, 유지보수용이성으로 보자면,
예를들어,
Mode가 나중에 10개가 추가되었다고 한다면,
좀 달라질까요?
아니 100개가 추가된다면
어떨까요?
1번의경우,
장점:
enum 항목만 추가하면 된다.
단점:
enum을 변경하게 되면, 기존 GameState 클래스가 변경되어서 Open-Closed 원리에 위배됩니다.
그럼 enum 정의를 GameState 클래스 밖에다 선언하게되면,
GameState 클래스는 외부선언값인 enum 에 의존성을 갖게 됩니다.
2번의 경우,
장점:
확장에 용이하다.의존성이 없다.
단점:
클래스를 그만큼 생성해야한다.
전 2가 그나마 좋다고 생각해서 2를 만들다가
클래스가 많아지다보니,
compare 할 경우 조건문을 많아지고
추가적인 작업들이 있는데
이게 맞는것인가? 의문이 듭니다.
특히 확장성, 유지보수용이성으로 보자면,
예를들어,
Mode가 나중에 10개가 추가되었다고 한다면,
좀 달라질까요?
아니 100개가 추가된다면
어떨까요?
1번의경우,
장점:
enum 항목만 추가하면 된다.
단점:
enum을 변경하게 되면, 기존 GameState 클래스가 변경되어서 Open-Closed 원리에 위배됩니다.
그럼 enum 정의를 GameState 클래스 밖에다 선언하게되면,
GameState 클래스는 외부선언값인 enum 에 의존성을 갖게 됩니다.
2번의 경우,
장점:
확장에 용이하다.의존성이 없다.
단점:
클래스를 그만큼 생성해야한다.
전 2가 그나마 좋다고 생각해서 2를 만들다가
클래스가 많아지다보니,
compare 할 경우 조건문을 많아지고
추가적인 작업들이 있는데
이게 맞는것인가? 의문이 듭니다.
개발용님의 댓글의 댓글
@원츠마인드님에게 답글
개인적으로 1번의 경우 enum 이 추가된다는 가정을 안해서요..
만약 불가피하게 추가된다면 OCP 에따라서 기존 클레스의 enum 을 수정할게 아니라
GameStateExtended extends GameState {
public enum ExtendedMode {
Arena(GameState.Mode.Arena),
PvP(GameState.Mode.PvP),
PvE;
private final GameState.Mode originalMode;
ExtendedMode(GameState.Mode originalMode) {
this.originalMode = originalMode;
}
public GameState.Mode getOriginalMode() {
return originalMode;
}
}
}
식으로 확장을 하던가
Wrapper 로 계속 감싸야 하지 않을까요?
만약 불가피하게 추가된다면 OCP 에따라서 기존 클레스의 enum 을 수정할게 아니라
GameStateExtended extends GameState {
public enum ExtendedMode {
Arena(GameState.Mode.Arena),
PvP(GameState.Mode.PvP),
PvE;
private final GameState.Mode originalMode;
ExtendedMode(GameState.Mode originalMode) {
this.originalMode = originalMode;
}
public GameState.Mode getOriginalMode() {
return originalMode;
}
}
}
식으로 확장을 하던가
Wrapper 로 계속 감싸야 하지 않을까요?
원츠마인드님의 댓글의 댓글
@개발용님에게 답글
자바는 enum 이 object 인가 보군요. ;;;
하긴 swift 도 enum 이 object 였던것 같네요.
하긴 swift 도 enum 이 object 였던것 같네요.
에놀미타님의 댓글
enum class BattleMode { PvE, PvP, Arena };
이건 거의 바뀔 일이 없어서 굳이 복잡하게 할 필요가 없을 것 같아요
이건 거의 바뀔 일이 없어서 굳이 복잡하게 할 필요가 없을 것 같아요
원츠마인드님의 댓글의 댓글
@에놀미타님에게 답글
예시를 게임으로 든것이지만,
다른분야의 클래스일경우 Mode 가 천차만별일수 있습니다.
그럴 경우에 대한 고민이네요.
다른분야의 클래스일경우 Mode 가 천차만별일수 있습니다.
그럴 경우에 대한 고민이네요.
프로그피쉬님의 댓글
일단 완성하고 최적으로 리팩토링하는게 답이 아닌가 싶습니다. 물론 자기가 만든 코드지옥을 헤쳐나올 수 있다며 말이죠.
원츠마인드님의 댓글의 댓글
@프로그피쉬님에게 답글
저도 항상 옛날 코드 보고 리팩토링을 하는데
왜 처음부터 이렇게 설계안했을까 하는 후회를 종종합니다.
그런 불평, 고민에서 나온 의문이었습니다.
왜 처음부터 이렇게 설계안했을까 하는 후회를 종종합니다.
그런 불평, 고민에서 나온 의문이었습니다.
에헤라디야님의 댓글
저는 개인적으로 2번으로 해야 한다고 생각합니다. 단일 클래스의 구현은 단일 컨택스트로 최소한의 정보만 가지고 있어야 한다고 생각하거든요. 앞서 댓글에 언급하신 추가적 작업이 있다고 하더라도요.
1번처럼 설계를 하게 되면 해당 클래스는 모든 기능을 다 가지고 있는 초대형 클래스가 되어 버립니다. 그러면 나중에 당연히 리팩토링 1호 대상이 되고 얘를 리팩토링 하게 되면 1번 클래서는 enum을 가진 switch case만 남게 되고 내부 구현은 결국 2번 클래스들로 호출을 하게 되는 형태가 되어버리게 됩니다. 그렇기 때문에 아예 처음부터 2번처럼 작업해야 하는 것이 옳습니다.
1번처럼 설계를 하게 되면 해당 클래스는 모든 기능을 다 가지고 있는 초대형 클래스가 되어 버립니다. 그러면 나중에 당연히 리팩토링 1호 대상이 되고 얘를 리팩토링 하게 되면 1번 클래서는 enum을 가진 switch case만 남게 되고 내부 구현은 결국 2번 클래스들로 호출을 하게 되는 형태가 되어버리게 됩니다. 그렇기 때문에 아예 처음부터 2번처럼 작업해야 하는 것이 옳습니다.
원츠마인드님의 댓글의 댓글
@에헤라디야님에게 답글
확장성과 유연성을 고려안한다면
1,2 번 큰차이는 없고 오히려 1번이 더 편할수가 있습니다.
하지만,
우리는 언제 어떻게 요구사항이 변경될지 모르기에..
1번의 경우는 Single Responsilbity 원칙과 Open-Closed 원리에 위배됩니다.
예를 들어서,
GameState 클래스 내부에 DoSometing 함수를 만들어야 하고,
그 안에 Mode 별로 다르게 처리 해야 한다면,
1번의 경우
void DoSomthing (){
if(mode == Arena){
// do something in arena
}
else if ( mode == PvP ){
// do somthing in PvP
}
}
나중에 Mode가 더 추가가 될경우,
저 함수내부에 또 추가해야 합니다.
이건 Single 책임에 위배됩니다.
2번의 경우는
public abstract class GameState(){
public int id;
public string name;
public abstract void DoSomething();
}
public class Arena:GameState(){
public void DoSomething(){
// do something in Arena
}
}
public class PvP :GameState(){
public void DoSomething(){
// do something in PvP
}
}
이렇게 해버리면,
클래스와 코드는 딱 정해진 한가지 모드에 대해서만 관리가 됩니다.
1,2 번 큰차이는 없고 오히려 1번이 더 편할수가 있습니다.
하지만,
우리는 언제 어떻게 요구사항이 변경될지 모르기에..
1번의 경우는 Single Responsilbity 원칙과 Open-Closed 원리에 위배됩니다.
예를 들어서,
GameState 클래스 내부에 DoSometing 함수를 만들어야 하고,
그 안에 Mode 별로 다르게 처리 해야 한다면,
1번의 경우
void DoSomthing (){
if(mode == Arena){
// do something in arena
}
else if ( mode == PvP ){
// do somthing in PvP
}
}
나중에 Mode가 더 추가가 될경우,
저 함수내부에 또 추가해야 합니다.
이건 Single 책임에 위배됩니다.
2번의 경우는
public abstract class GameState(){
public int id;
public string name;
public abstract void DoSomething();
}
public class Arena:GameState(){
public void DoSomething(){
// do something in Arena
}
}
public class PvP :GameState(){
public void DoSomething(){
// do something in PvP
}
}
이렇게 해버리면,
클래스와 코드는 딱 정해진 한가지 모드에 대해서만 관리가 됩니다.
ccsw님의 댓글
mode 가 단순하게 enum 으로 구분만 하고 다른 동작 차이가 없다고 하면 1번이고, mode에 따라 다양한 다른 동작이 있거나 미래에 있을 것 같으면 2번이 좋을 것 같습니다.
원츠마인드님의 댓글의 댓글
@ccsw님에게 답글
기획자들이 언제 어떻게 요구사항을 내놓을지 모르는 상황이라면, 2번을 해야겠네요
AmD5950x님의 댓글
디스어셈블로 돌려서 가장나은 코드를 만들어주는걸 선택하는것이... ㅎㅎ
개인적으로는 단순하게 작성하는것을 매우 선호해서 객체지향형에 최대한 부합하게 코드를 작성한다고 복잡하게 짜는걸 별로 좋아하지 않아서요.
특히 함수콜이 딥하게 들어가는 코드는 정말 싫어합니다. 함수콜도 다 비용인데...
어짜피 enum값으로 분기타서 처리하는 코드라면 그냥 똑같은 기능으로 단순하게 c type으로 작성 하는게 컴파일된 코드는 제일 좋게 나옵니다.
유지보수도 쉽고요
개인적으로는 단순하게 작성하는것을 매우 선호해서 객체지향형에 최대한 부합하게 코드를 작성한다고 복잡하게 짜는걸 별로 좋아하지 않아서요.
특히 함수콜이 딥하게 들어가는 코드는 정말 싫어합니다. 함수콜도 다 비용인데...
어짜피 enum값으로 분기타서 처리하는 코드라면 그냥 똑같은 기능으로 단순하게 c type으로 작성 하는게 컴파일된 코드는 제일 좋게 나옵니다.
유지보수도 쉽고요
AmD5950x님의 댓글
state가 5개 미만이면
enum class : unsigned {}
struct game_state_t {}
void update_state(game_state_t* state)
이방식이 덤프떠서 디버깅할때 가장 좋고 메모리도 적게먹을꺼에요. 처리속도야 뭐 내부 구현에 달린거긴하니 논외로 하고요.
만약 state 내부구현이 전부 다르다면 두번째 방식으로 결국 상속받아 처리 해야겠지요.
enum class : unsigned {}
struct game_state_t {}
void update_state(game_state_t* state)
이방식이 덤프떠서 디버깅할때 가장 좋고 메모리도 적게먹을꺼에요. 처리속도야 뭐 내부 구현에 달린거긴하니 논외로 하고요.
만약 state 내부구현이 전부 다르다면 두번째 방식으로 결국 상속받아 처리 해야겠지요.
원츠마인드님의 댓글의 댓글
@AmD5950x님에게 답글
게임업계가 아니고서는 요즘 메모리 차지는 그다지 신경을 안쓸거에요.
순전히 현대언어 관점에서
디자인패턴을 고민해보자라고 말씀드리고 싶네요.
디버깅할때 덤프를 뜰정도면,
로레벨 프로그래밍인것 같네요.
순전히 현대언어 관점에서
디자인패턴을 고민해보자라고 말씀드리고 싶네요.
디버깅할때 덤프를 뜰정도면,
로레벨 프로그래밍인것 같네요.
AmD5950x님의 댓글의 댓글
@원츠마인드님에게 답글
게임업계 문제가 아니라 그냥 스크립터나 코더 수준의 코딩할거 아니면 모든 분야에서 메모리 하나하나 다 신경쓰고요..
적어도 프로그래머라면.. 자기가 쓰고있는 언어에 대해서 잘못되었을 경우 메모리 덤프해서 어떤 상황에서 메모리가 깨졌는지.. 어떤 힙커럽션인지 스택 오버플로인지.. 어떤 쓰레드 로컬 힙이 깨졌는지.. 정도는 파악해야죠. 덤프는 c가 아니어도 자바나 c#도 다 남아요. 하다못해 스크립트 언어도 남습니다.
메모리 신경안쓰고 디자인패턴을 프로그래머 마음껏 적용하는건 비지니스 로직에서나 그렇치..
실제로 백엔드 또는 프레임워크 정도의 로우레벨은 아니지만 적당히 OS와 시스템 그리고 비지니스 로직의 중간 정도를 개발하는 프로그래머가 메모리 신경안쓰고 디자인패턴을 주된 고민으로 개발한다면.. 개인적으로는 좀 놀라운 상황입니다.
자기가 짠코드가 대충이라도 메모리와 프로세서에서 어떻게 작동하고있는지는 알아야죠.
파이썬으로 죽도록 실시간 힙할당 하는 코드 짜놓고 캐시미스를 논하는 개발자도 봤는데요.
프로그래머에게 컴퓨터 구조를 공부하라고 하는건 다른 이유가 있는게 아닙니다
------------
글을 쓰고보니 마치 가르치듯 덧글 쓴거 같네요. 제코가 석자인데..
덤프나 이런건 뭐 딱히 어려운 기술은 아니고 잘 모르는 프로그래머 분들이라면
그냥 잠깐 보시면 금방 익힐 수 있는 잡 기술들이라.. 이걸로 안다고 잘난척하고 이런 뜻은 아니었습니다.
기분 나뻐 하실까봐요. 윈츠마인드 님을 깔보거나 그런건 절대 아닙니다.
클래스 설계는 그냥 자기 편한대로 하면된다고 생각합니다. 저는 90년대 중반 부터 프로그래밍을
해와서 그때의 버릇으로 효율성을 매우 중시해서 짜는 스타일이라 그런거고..
클래스를 쪼게던 구조체로 하던 인터페이스로 빼던 어짜피 프로세서에서는 대부분 jmp로 메모리 점프해서 가는 것들이라.. 저에겐 별 차이는 없고 그냥 코드 관리의 영역정도로 보입니다
참고로 게임업계도 요즘엔 슬프게도 메모리 팍팍 쓰는 경우가 많아요. 게임 쪽이라고 뭐 별반 다를 바는 없는 경우가 많더군요. 물론 모바일게임도 그래서 요즘 많이 무겁죠 ..
적어도 프로그래머라면.. 자기가 쓰고있는 언어에 대해서 잘못되었을 경우 메모리 덤프해서 어떤 상황에서 메모리가 깨졌는지.. 어떤 힙커럽션인지 스택 오버플로인지.. 어떤 쓰레드 로컬 힙이 깨졌는지.. 정도는 파악해야죠. 덤프는 c가 아니어도 자바나 c#도 다 남아요. 하다못해 스크립트 언어도 남습니다.
메모리 신경안쓰고 디자인패턴을 프로그래머 마음껏 적용하는건 비지니스 로직에서나 그렇치..
실제로 백엔드 또는 프레임워크 정도의 로우레벨은 아니지만 적당히 OS와 시스템 그리고 비지니스 로직의 중간 정도를 개발하는 프로그래머가 메모리 신경안쓰고 디자인패턴을 주된 고민으로 개발한다면.. 개인적으로는 좀 놀라운 상황입니다.
자기가 짠코드가 대충이라도 메모리와 프로세서에서 어떻게 작동하고있는지는 알아야죠.
파이썬으로 죽도록 실시간 힙할당 하는 코드 짜놓고 캐시미스를 논하는 개발자도 봤는데요.
프로그래머에게 컴퓨터 구조를 공부하라고 하는건 다른 이유가 있는게 아닙니다
------------
글을 쓰고보니 마치 가르치듯 덧글 쓴거 같네요. 제코가 석자인데..
덤프나 이런건 뭐 딱히 어려운 기술은 아니고 잘 모르는 프로그래머 분들이라면
그냥 잠깐 보시면 금방 익힐 수 있는 잡 기술들이라.. 이걸로 안다고 잘난척하고 이런 뜻은 아니었습니다.
기분 나뻐 하실까봐요. 윈츠마인드 님을 깔보거나 그런건 절대 아닙니다.
클래스 설계는 그냥 자기 편한대로 하면된다고 생각합니다. 저는 90년대 중반 부터 프로그래밍을
해와서 그때의 버릇으로 효율성을 매우 중시해서 짜는 스타일이라 그런거고..
클래스를 쪼게던 구조체로 하던 인터페이스로 빼던 어짜피 프로세서에서는 대부분 jmp로 메모리 점프해서 가는 것들이라.. 저에겐 별 차이는 없고 그냥 코드 관리의 영역정도로 보입니다
참고로 게임업계도 요즘엔 슬프게도 메모리 팍팍 쓰는 경우가 많아요. 게임 쪽이라고 뭐 별반 다를 바는 없는 경우가 많더군요. 물론 모바일게임도 그래서 요즘 많이 무겁죠 ..
원츠마인드님의 댓글의 댓글
@AmD5950x님에게 답글
쓰고나서 걱정을 했는데 ^^;
좀 더 길게 쓸것을 그랬네요.
일단 C언어를 사용하셔서 low-level 프로그램하시는 걸로 판단했고요.
그래서 님의 조언에 부정하는것이 아니라
로레벨단, 펌웨어단 프로그래밍과는
일반 응용프로그밍과는 다르다고 생각하거든요.
전자는 메모리 신경써야 하고, (한정적 메모리기때문에, )
cpu 역시 빵방한 pc가 아닐테고 하니.
설계자체가 다르고, 사용법도 다르다고 생각합니다.
일단 상속자체도 몇단계 밑으로 하면 안되잖아요
이렇듯, 로레벨단 프로그램과 응용프로그램은 다르게 접근해야 한다
차원에서 제가 댓글을 위에 처럼 단것입니다.
물론 후자도 신경써야 하지만,
그렇게 크리티컬하게 생각을 안합니다.
그래서 다른 디자인패턴에서도 요즘 같은 pc환경에서는
메모리사용과 iteration 돌리는것에 큰 성능이슈는 없으니,
가독성있고 유지보수가 더 좋은 프로그래밍으로 권장을 합니다.
그런식으로 디자인패턴이 발전하고 있고요.
물론 개발자라면
말씀하신데로 메모리 얼마나 사용하는지 확인하면서해야겠죠.
struct 구조 짤때
padding 생각해서 변수 타입 지정하듯이요.
님의견이 틀렸다고 얘기한것이 아닙니다.
그리고 게임쪽도 메모리 신경씁니다.
특히나 모바일은 더더욱이나 .
그래서 항상 개발중에 성능테스트와 최적화를 병행해서 진행합니다.
좀 더 길게 쓸것을 그랬네요.
일단 C언어를 사용하셔서 low-level 프로그램하시는 걸로 판단했고요.
그래서 님의 조언에 부정하는것이 아니라
로레벨단, 펌웨어단 프로그래밍과는
일반 응용프로그밍과는 다르다고 생각하거든요.
전자는 메모리 신경써야 하고, (한정적 메모리기때문에, )
cpu 역시 빵방한 pc가 아닐테고 하니.
설계자체가 다르고, 사용법도 다르다고 생각합니다.
일단 상속자체도 몇단계 밑으로 하면 안되잖아요
이렇듯, 로레벨단 프로그램과 응용프로그램은 다르게 접근해야 한다
차원에서 제가 댓글을 위에 처럼 단것입니다.
물론 후자도 신경써야 하지만,
그렇게 크리티컬하게 생각을 안합니다.
그래서 다른 디자인패턴에서도 요즘 같은 pc환경에서는
메모리사용과 iteration 돌리는것에 큰 성능이슈는 없으니,
가독성있고 유지보수가 더 좋은 프로그래밍으로 권장을 합니다.
그런식으로 디자인패턴이 발전하고 있고요.
물론 개발자라면
말씀하신데로 메모리 얼마나 사용하는지 확인하면서해야겠죠.
struct 구조 짤때
padding 생각해서 변수 타입 지정하듯이요.
님의견이 틀렸다고 얘기한것이 아닙니다.
그리고 게임쪽도 메모리 신경씁니다.
특히나 모바일은 더더욱이나 .
그래서 항상 개발중에 성능테스트와 최적화를 병행해서 진행합니다.
AmD5950x님의 댓글의 댓글
@원츠마인드님에게 답글
일단 제 경력만 말씀드리자면
전 로우 레벨만 하지 않아요.
언어적으론 x86어셈, C/C++ , OBJ-C, Swift, 자바, Go, C#, Rust 정도 다루고..
작업 분야는 요즘 소위 말하는 백엔드 일부, 게임 서버, 게임 렌더링엔진, 게임 클라이언트, 공장에서 돌리는 잡다 어플리케이션.. 등등을 했어요.
최근은 Unreal4 커스트 마이즈 했고.. 크로미움 오픈소스 내부 힙 할당 부분 뜯어내고 벌칸쪽 렌더러 코드가 문제있어서 수정후에 좀더 가벼운 웹 브라우저를 만들기도 했습니다.
나이가 많아서 그런지 하기는 많이 했어요. 그렇다고 제가 실력이 좋다는 건 아닙니다.
많이 안다고 잘하는 사람이라고 볼 수는 없으니까요. 모르는 분야가 더 많아요.
지금은 회사 다니면서 집에서 틈틈히 개인 게임 엔진(서버 포함) 만들고 있습니다.
(은퇴 후에 제 엔진으로 1인 게임 개발 하려구요)
SQL DB쪽은 할 줄은 알지만.. 실제 DB만 전문적으로 하시는 분들 보다는 못합니다.
AI쪽은 전혀 모르고요.
-------------------------------------
디자인 패턴이라는 말은 사실 1990년대 후반부터 많이 이슈화 되었었죠.
2000~2010년도에는 거의 종교의 영역까지 가서 프로그래머들 간에 많은 논쟁이 있었고
그것 말고도 리팩토링, 페어 프로그래밍을 포함한 애자일 개발 방법론등 그당시 정말
논쟁이 끝도 없이 이어졌던 기억이 납니다. 지금 생각하면 그때가 제일 재미있었네요.
지금 와서 보면 의미가 있을 수도 또는 별 의미가 없을 수도 있다고 생각합니다.
디자인 패턴이라는건 그냥 그동안 개발에 많이 쓰여온 테크닉들을 정리해서
소프트웨어 공학적으로 교육하기 쉽게 만든 것이지 그게 문제를 해결해주는 무언가라고
생각하지 않습니다.
당장 윈도우 NT 커널 소스만 봐도 그 옛날 짜놓은 C코드에 디자인 패턴에 포함되는
대부분의 테크닉들이 다 들어있어요. 커틀러가 짜놓은 프로그래밍에서도 볼수있고..
COM구조도 분리 하면 4~5가지의 소위 말하는 디자인 패턴이라는 구조들이 합쳐져 있습니다.
게임쪽 메모리는 예전과는 페러다임이 많이 바뀌어서 슬프게도 지금은 예전같이 메모리를
줄이지는 않습니다. 현재 언리얼4,5를 커스트 마이즈 하고있는 입장에서 참 많이 느끼고 있습니다.
유니티도 마찬가지 입니다. 일단 기본적으로 힙 할당에 굉장히 관대해서..
동남아나 남미에서 주로 사용되어지는 저 사양 폰에서는 뭘 하기가 참으로 난감 할 경우가 많습니다.
C# 언어는 그냥 짤수도 있지만 IL컴파일 할때 만들어지는 IL코드들을 원하는데로 만들어지게
최적화가 가능합니다.
유니티에서는 해당 IL코드들을 CPP로 바꿔주는 역할을 IL2CPP가 해주는데요.
C#에서 가능한 기능들을 CPP로 바꾸면서 정말 많은 메모리를 내부적으로 사용합니다.
C#으로 작성한 코드들과의 호환성을 위해서 정말 정말 많은 메모리가 사용됩니다.
개인적으로는 IL2CPP 구현 자체에 좀 실망을 했습니다.
언리얼도 마찬가지 입니다. 언리얼 코드는 2시절 부터 봤는데요. 언리얼 엔진의 방향이..
점점 생산성, 범용성 그리고 하이 퀄리티를 바라보다 보니.. 많은 부분들이 최적화를 해줘야
원하는 플랫폼에서 원하는 성능이 나와요. 하지만 그것도 결국 만든놈은 제가 아니다보니..
그 방향을 완전히 비껴가서 만들 수는 없더군요. 또 제가 실력이 부족해서 일수도 있고요..
또 언리얼 엔진을 너무 깊게 수정하다 보면 엔진 업데이트 할 때 피를 토합니다.
말이 길어졌는데..지금은 그냥 클래스 디자인도 짜고 싶은 대로 짜도 된다고 봅니다.
그게 디자인 패턴에 맞게 짜놓은 클래스던.. 아니면 그냥 C++ 클래스 장점만 가져온 C코드나 다름없는
형식이든.. 상관없다고 봅니다.
어짜피 개발의 절반 이상은 런타임 디버깅이고.. 디버깅 할때 덤프떠서 뭐가 깨졌는지
뭐가 잘못 된건지 정확히 볼 수 있다면 대부분 99%의 문제 해결은 다 가능해요.
MVC형식을 지나 요즘 말 많은 ECS든 .. OOP던 DOD던..
어짜피 비지니스 로직 딴에서는 별로 중요하지 않아요.
디자인패턴 적용한다고 희얀한 구조 적용해서 디버깅만 어렵게 만들고
심지어 디자인 패턴 자체가 코드를 유지하는 비용을 상승 시키는 경우도 많이 봤습니다.
물론 저런 경우는 초짜 프로그래머들이 작성한 코드에서 많이 보입니다.
클라이언트(or 비지니스) 로직은 빠르고 간결하게 작성하고 그 로직을 작성을 도와주는
미들 웨어는 외부적으로는 MVC던 ECS던 뭐든 간에 일관성 있게 로직을 붙있을 수 있게
인터페이스가 빠져있으면 그게 개인적으로는 제일 좋은 방법이라고 봅니다.
미들 웨어 위에서 로직 가지고 온갖 자신만의 월드를 구성하는 그런 코드를 작성하면 좀 무섭더군요.
얘가 정말 뭘 알고 이렇게 짜는건가.. 혼자 다 책임 질 수 있는건가..
얘가 퇴사하면 다음 인수 받은 프로그래머는 이 구조를 다 파악할 수 있는건가..
그래서 직원들에게는 단순하게 짜라고 계속 주지 시켜요.
남에게 화려하게 보여지는 코드 작성 하지 말아라..
당신이 작성한 코드가 과연 정말 필요한 코드들인가?
혹시 A+B하려고 그전에 유지보수를 위한 코드들로 CPU클럭을 쓸떼없이 소모하는건 아닌가?
A+B하겠다고 Class_CallFunc() => Class_CallFunc => Call_Func => Call_Func
이런 짓을 한 건 아닌가..
비동기 구조로 작성한 것이 과연 객체가 파괴 되었을 때도 지연 실행되는 콜백에 대해서
안전한 처리가 되어있는건가?... 등등
뭐 그냥 잡소리 끄적였습니다.
생각해보니 "그냥 니가 짜고 싶은대로 짜라" 말해놓고 주저리 주저리 말이 길었네요..
전 로우 레벨만 하지 않아요.
언어적으론 x86어셈, C/C++ , OBJ-C, Swift, 자바, Go, C#, Rust 정도 다루고..
작업 분야는 요즘 소위 말하는 백엔드 일부, 게임 서버, 게임 렌더링엔진, 게임 클라이언트, 공장에서 돌리는 잡다 어플리케이션.. 등등을 했어요.
최근은 Unreal4 커스트 마이즈 했고.. 크로미움 오픈소스 내부 힙 할당 부분 뜯어내고 벌칸쪽 렌더러 코드가 문제있어서 수정후에 좀더 가벼운 웹 브라우저를 만들기도 했습니다.
나이가 많아서 그런지 하기는 많이 했어요. 그렇다고 제가 실력이 좋다는 건 아닙니다.
많이 안다고 잘하는 사람이라고 볼 수는 없으니까요. 모르는 분야가 더 많아요.
지금은 회사 다니면서 집에서 틈틈히 개인 게임 엔진(서버 포함) 만들고 있습니다.
(은퇴 후에 제 엔진으로 1인 게임 개발 하려구요)
SQL DB쪽은 할 줄은 알지만.. 실제 DB만 전문적으로 하시는 분들 보다는 못합니다.
AI쪽은 전혀 모르고요.
-------------------------------------
디자인 패턴이라는 말은 사실 1990년대 후반부터 많이 이슈화 되었었죠.
2000~2010년도에는 거의 종교의 영역까지 가서 프로그래머들 간에 많은 논쟁이 있었고
그것 말고도 리팩토링, 페어 프로그래밍을 포함한 애자일 개발 방법론등 그당시 정말
논쟁이 끝도 없이 이어졌던 기억이 납니다. 지금 생각하면 그때가 제일 재미있었네요.
지금 와서 보면 의미가 있을 수도 또는 별 의미가 없을 수도 있다고 생각합니다.
디자인 패턴이라는건 그냥 그동안 개발에 많이 쓰여온 테크닉들을 정리해서
소프트웨어 공학적으로 교육하기 쉽게 만든 것이지 그게 문제를 해결해주는 무언가라고
생각하지 않습니다.
당장 윈도우 NT 커널 소스만 봐도 그 옛날 짜놓은 C코드에 디자인 패턴에 포함되는
대부분의 테크닉들이 다 들어있어요. 커틀러가 짜놓은 프로그래밍에서도 볼수있고..
COM구조도 분리 하면 4~5가지의 소위 말하는 디자인 패턴이라는 구조들이 합쳐져 있습니다.
게임쪽 메모리는 예전과는 페러다임이 많이 바뀌어서 슬프게도 지금은 예전같이 메모리를
줄이지는 않습니다. 현재 언리얼4,5를 커스트 마이즈 하고있는 입장에서 참 많이 느끼고 있습니다.
유니티도 마찬가지 입니다. 일단 기본적으로 힙 할당에 굉장히 관대해서..
동남아나 남미에서 주로 사용되어지는 저 사양 폰에서는 뭘 하기가 참으로 난감 할 경우가 많습니다.
C# 언어는 그냥 짤수도 있지만 IL컴파일 할때 만들어지는 IL코드들을 원하는데로 만들어지게
최적화가 가능합니다.
유니티에서는 해당 IL코드들을 CPP로 바꿔주는 역할을 IL2CPP가 해주는데요.
C#에서 가능한 기능들을 CPP로 바꾸면서 정말 많은 메모리를 내부적으로 사용합니다.
C#으로 작성한 코드들과의 호환성을 위해서 정말 정말 많은 메모리가 사용됩니다.
개인적으로는 IL2CPP 구현 자체에 좀 실망을 했습니다.
언리얼도 마찬가지 입니다. 언리얼 코드는 2시절 부터 봤는데요. 언리얼 엔진의 방향이..
점점 생산성, 범용성 그리고 하이 퀄리티를 바라보다 보니.. 많은 부분들이 최적화를 해줘야
원하는 플랫폼에서 원하는 성능이 나와요. 하지만 그것도 결국 만든놈은 제가 아니다보니..
그 방향을 완전히 비껴가서 만들 수는 없더군요. 또 제가 실력이 부족해서 일수도 있고요..
또 언리얼 엔진을 너무 깊게 수정하다 보면 엔진 업데이트 할 때 피를 토합니다.
말이 길어졌는데..지금은 그냥 클래스 디자인도 짜고 싶은 대로 짜도 된다고 봅니다.
그게 디자인 패턴에 맞게 짜놓은 클래스던.. 아니면 그냥 C++ 클래스 장점만 가져온 C코드나 다름없는
형식이든.. 상관없다고 봅니다.
어짜피 개발의 절반 이상은 런타임 디버깅이고.. 디버깅 할때 덤프떠서 뭐가 깨졌는지
뭐가 잘못 된건지 정확히 볼 수 있다면 대부분 99%의 문제 해결은 다 가능해요.
MVC형식을 지나 요즘 말 많은 ECS든 .. OOP던 DOD던..
어짜피 비지니스 로직 딴에서는 별로 중요하지 않아요.
디자인패턴 적용한다고 희얀한 구조 적용해서 디버깅만 어렵게 만들고
심지어 디자인 패턴 자체가 코드를 유지하는 비용을 상승 시키는 경우도 많이 봤습니다.
물론 저런 경우는 초짜 프로그래머들이 작성한 코드에서 많이 보입니다.
클라이언트(or 비지니스) 로직은 빠르고 간결하게 작성하고 그 로직을 작성을 도와주는
미들 웨어는 외부적으로는 MVC던 ECS던 뭐든 간에 일관성 있게 로직을 붙있을 수 있게
인터페이스가 빠져있으면 그게 개인적으로는 제일 좋은 방법이라고 봅니다.
미들 웨어 위에서 로직 가지고 온갖 자신만의 월드를 구성하는 그런 코드를 작성하면 좀 무섭더군요.
얘가 정말 뭘 알고 이렇게 짜는건가.. 혼자 다 책임 질 수 있는건가..
얘가 퇴사하면 다음 인수 받은 프로그래머는 이 구조를 다 파악할 수 있는건가..
그래서 직원들에게는 단순하게 짜라고 계속 주지 시켜요.
남에게 화려하게 보여지는 코드 작성 하지 말아라..
당신이 작성한 코드가 과연 정말 필요한 코드들인가?
혹시 A+B하려고 그전에 유지보수를 위한 코드들로 CPU클럭을 쓸떼없이 소모하는건 아닌가?
A+B하겠다고 Class_CallFunc() => Class_CallFunc => Call_Func => Call_Func
이런 짓을 한 건 아닌가..
비동기 구조로 작성한 것이 과연 객체가 파괴 되었을 때도 지연 실행되는 콜백에 대해서
안전한 처리가 되어있는건가?... 등등
뭐 그냥 잡소리 끄적였습니다.
생각해보니 "그냥 니가 짜고 싶은대로 짜라" 말해놓고 주저리 주저리 말이 길었네요..
원츠마인드님의 댓글의 댓글
@AmD5950x님에게 답글
경험이 많으신것 같네여
앞으로 관련 글 부탁드릴게요
나이가 들면 열정이 식는데
글에서 열정이 느껴집니다
ㅎㅎ
앞으로 관련 글 부탁드릴게요
나이가 들면 열정이 식는데
글에서 열정이 느껴집니다
ㅎㅎ
수퍼야옹님의 댓글
public class GameState {
public int id;
public string name;
}
public interface SomethingProcessor {
public void DoSomething();
}
public class Arena: SomethingProcessor {
GameState gameState = new GameState();
public void DoSomething() {
// do something in Arena
}
}
public class PvP: SomethingProcessor {
GameState gameState = new GameState();
public void DoSomething() {
// do something in PvP
}
}
바뀌는 걸 감안한다면 이렇게 하는 것도 좋을 것 같네요. GameState 외에 별도로 각각 다른 필드가 들어갈 수도 있으니까요.
public int id;
public string name;
}
public interface SomethingProcessor {
public void DoSomething();
}
public class Arena: SomethingProcessor {
GameState gameState = new GameState();
public void DoSomething() {
// do something in Arena
}
}
public class PvP: SomethingProcessor {
GameState gameState = new GameState();
public void DoSomething() {
// do something in PvP
}
}
바뀌는 걸 감안한다면 이렇게 하는 것도 좋을 것 같네요. GameState 외에 별도로 각각 다른 필드가 들어갈 수도 있으니까요.
원츠마인드님의 댓글의 댓글
@수퍼야옹님에게 답글
네 interface활용도 있죠.
interface는 GameState에 의존적이지 않아서
활용범위가 좀 더 넓죠.
이 점이 장점이라 볼수 있겠네요
interface는 GameState에 의존적이지 않아서
활용범위가 좀 더 넓죠.
이 점이 장점이라 볼수 있겠네요
개발용님의 댓글
자체 기능은 없고 외부에서 구분해서 구현해야하는 단순 구분만 한다면 1번이요
1번은 데이터 CRUD 에서 사용하고
2번은 Controller, Command, Service 등 처리 부분에서 쓰죠
근데, 뭘 선호 한다기 보다는 해당 클래스가 데이터를 담아서 여기저기 주고받으며 사용 할 것인가
아니면 받은 데이터를 처리 할 것인가에 따라서 선택하는거라 둘 다 씁니다.