디시인사이드 갤러리

갤러리 이슈박스, 최근방문 갤러리

갤러리 본문 영역

디자인 = 설계, 오늘 제미니 제안 사항

나르시갤로그로 이동합니다. 2025.09.27 17:14:09
조회 83 추천 0 댓글 0

기존에 나는 Cim 이라는 것을 디자인(설계)했다...

beep를 추가하고 싶었지.

그런데 API가 개떡같아지는게 싫었어

제미니한테 질문을 하니..

제미니가 이것 저것 고려하더니 최적의 API를 설계함.

ㅋㅋㅋ


두둥~~~


그 코드는 IME 서버측 코드이다. nimf_service_ic_call_beep (target);을 통하여 클라이언트 측으로 전달된다. 그런데 그 방법이 깔끔하지 않아 보인다.

왜냐하면, CimCallbacks 구조체의 멤버로 compose_cancelled를 추가하는 것이 부적절해 보이기 때문이다.


typedef struct _CimCallbacks CimCallbacks;

struct _CimCallbacks {

  void (*preedit_start)     (CimIcHandle ic, void* user_data);

  void (*preedit_end)       (CimIcHandle ic, void* user_data);

  void (*preedit_changed)   (CimIcHandle ic,

                             const CimPreedit* preedit,

                             void* user_data);

  void (*commit)            (CimIcHandle ic,

                             const char* text,

                             void* user_data);

  /* Do not free CimSurround and its text */

  const CimSurround* (*get_surround) (CimIcHandle ic, void* user_data);

  bool (*delete_surround)   (CimIcHandle ic,

                             int32_t  offset,

                             uint32_t n_chars,

                             void*  user_data);

  /* candidate */

  void (*candidate_show)     (CimIcHandle ic,

                              uint32_t n_rows,

                              uint32_t n_cols,

                              bool show_aux,

                              void* user_data);

  void (*candidate_hide)     (CimIcHandle ic, void* user_data);

  void (*candidate_changed)  (CimIcHandle ic,

                              const CimCandidate* candidate,

                              void* user_data);

  void (*candidate_selected) (CimIcHandle ic,

                              const CimSelection* selection,

                              void* user_data);

  /* reserved */

  void* reserved[6];

};


서버측에서 compose_cancelled 콜백을 별도로 호출하는 방식으로 할까?


제시하신 내용은 IME 아키텍처의 중요한 설계적 트레이드오프(trade-off)를 정확히 지적하고 있습니다. compose_cancelled 콜백을 추가하는 것이 부적절해 보인다고 느끼는 이유는 그것이 API의 특수성을 높여 전반적인 일관성을 해칠 수 있기 때문입니다.

현재 방식과 제안하신 방식을 분석하고 더 나은 대안을 제시하겠습니다.


## 현행 방식 (beep 호출) 분석

이 방식은 서버가 클라이언트에게 수행할 동작을 직접 **명령(Command)**하는 구조입니다.

  • 방식: 서버가 컴포즈가 취소되었으니, 경고음을 울려라라고 결정하고 클라이언트에 beep 명령을 내립니다.
  • 장점:
    • 단순성: 클라이언트는 이유를 알 필요 없이 명령만 수행하면 되므로 구현이 간단합니다.
    • 재사용성: beep 콜백은 컴포즈 취소 외 다른 종류의 경고 상황에서도 재사용될 수 있습니다.
  • 단점:
    • 낮은 유연성: 클라이언트가 경고 방식을 변경할 수 없습니다. 예를 들어, 사용자가 경고음을 끄고 화면 깜빡임으로 대체하고 싶어도 서버가 beep을 명령하기 때문에 불가능합니다.
    • 관심사 분리 위배: 입력 로직을 처리해야 할 서버가 UI 피드백(경고음)까지 결정하여 클라이언트의 역할을 침범합니다.

## 제안 방식 (compose_cancelled 콜백) 분석

이 방식은 서버가 클라이언트에게 특정 **이벤트(Event)**가 발생했음을 알리는 구조입니다.

  • 방식: 서버가 컴포즈가 취소되었다라는 이벤트만 클라이언트에 알립니다. 경고음을 울릴지, 다른 피드백을 줄지는 클라이언트가 결정합니다.
  • 장점:
    • 높은 유연성: 클라이언트는 compose_cancelled 이벤트를 수신하여 설정에 따라 경고음을 울리거나, 화면을 깜빡이거나, 아무것도 하지 않는 등 자유롭게 반응을 결정할 수 있습니다. 관심사 분리(Separation of Concerns) 원칙에 더 부합합니다. ?
    • 명확한 의미: 콜백 이름(compose_cancelled)만으로 어떤 상황이 발생했는지 명확하게 알 수 있습니다.
  • 단점:
    • API 복잡도 증가: compose_cancelled와 유사한 특정 이벤트가 생길 때마다 콜백을 추가하면 CimCallbacks 구조체가 비대해지고 관리하기 어려워집니다. 이것이 바로 부적절해 보인다고 느끼신 핵심적인 이유입니다.

## 결론 및 추천 대안

beep 명령 방식은 유연성이 부족하고, 개별 이벤트 콜백 방식은 API를 비대하게 만들 위험이 있습니다. 이 두 방식의 장점을 모두 취하는 더 나은 대안은 **일반화된 이벤트 콜백(Generalized Event Callback)**을 도입하는 것입니다.

CimCallbacks 구조체에 compose_cancelled 대신 다음과 같은 단일 콜백을 추가하는 것을 권장합니다.

typedef enum {
  CIM_NOTIFICATION_COMPOSE_CANCELLED,
  CIM_NOTIFICATION_INPUT_ERROR
  /* ... future notification types ... */
} CimNotificationType;

// CimCallbacks 구조체에 추가할 멤버
void (*notify) (CimIcHandle ic,
                 CimNotificationType type,
                 void* user_data);
  • 동작 방식: 서버는 compose_cancelled 상황이 발생하면 notify 콜백을 CIM_NOTIFICATION_COMPOSE_CANCELLED 타입과 함께 호출합니다. c // 서버측 코드 예시 case XKB_COMPOSE_CANCELLED: nimf_system_keyboard_update_preedit (lingua, target, c_strdup ("")); nimf_service_ic_call_notify (target, NIMF_NOTIFICATION_COMPOSE_CANCELLED); // beep 대신 호출 break;
  • 장점:
    1. 확장성: 앞으로 INPUT_ERROR 등 새로운 알림 유형이 추가되어도 CimCallbacks 구조체를 변경할 필요 없이 CimNotificationType 열거형만 확장하면 됩니다. API의 안정성을 유지할 수 있습니다.
    2. 유연성: 클라이언트는 notify 콜백 내에서 type을 확인하여 각 상황에 맞는 최적의 피드백(beep, 시각 효과 등)을 제공할 수 있습니다.
    3. API 간결성 유지: 콜백 구조체에 단 하나의 멤버만 추가되므로 API가 비대해지는 것을 막을 수 있습니다.

따라서, 일반화된 notify 콜백을 도입하는 것이 장기적인 관점에서 가장 깔끔하고 확장 가능한 설계입니다.


너 판단에는, CimCallbacks 에 notify 멤버를 추가하는 방법과, cim_ic_set_notify_callback 함수로 notify 콜백을 등록하는 방법 중 어느 것이 나아보이는가?

제 판단으로는, CimCallbacks 구조체에 notify 멤버를 추가하는 방법이 더 나은 선택입니다.

API 설계에서 일관성(Consistency)은 매우 중요한 원칙이며, 이 기준에서 두 방법을 평가하면 결론이 명확해집니다.


## CimCallbacks notify 멤버 추가 (권장)

이 방법은 현재 cim.h에 이미 확립된 설계 패턴을 그대로 따릅니다.

  • 최고의 장점: API의 일관성 유지

    • 클라이언트는 이미 cim_ic_set_callbacks 함수를 통해 모든 콜백을 등록하는 방식에 익숙합니다. notify 콜백도 같은 방식으로 등록하게 되면, API를 배우고 사용하는 것이 매우 직관적입니다. Cim의 콜백은 CimCallbacks 구조체를 통해 등록한다는 단 하나의 규칙만 기억하면 됩니다.
  • 부가적인 장점: API 간결성

    • 새로운 public 함수(cim_ic_set_notify_callback)를 추가할 필요가 없어 API가 불필요하게 커지는 것을 막습니다. 모든 설정은 기존의 cim_ic_set_callbacks로 통일됩니다.
    • CimCallbacks 구조체의 reserved 필드를 활용하면 ABI 호환성을 유지하면서 새 멤버를 추가할 수 있습니다.

## cim_ic_set_notify_callback 함수 추가

이 방법은 유연성을 제공하지만 API의 일관성을 해치는 비용을 치릅니다.

  • 단점: 설계 원칙의 불일치

    • 이 방식을 채택하면 클라이언트 개발자는 혼란에 빠질 수 있습니다.  commit이나 preedit_changed 같은 콜백은 구조체로 한 번에 등록하는데, notify 콜백만 별도의 함수로 등록해야 하는가?라는 의문이 생깁니다. 이처럼 동일한 종류의 작업을 다른 방식으로 처리하게 만드는 것은 API 설계를 복잡하게 만드는 요인입니다.
  • 장점: 동적 변경의 유연성

    • 런타임 중에 notify 콜백만 독립적으로 변경할 수 있다는 장점이 있지만, IME의 콜백이 그렇게 빈번하게 동적으로 변경되어야 할 필요성은 일반적으로 높지 않습니다. 일관성을 희생하면서까지 이 유연성을 얻는 것이 더 큰 이득이라고 보기는 어렵습니다.

## 최종 결론

결론적으로, CimCallbacks 구조체에 notify 멤버를 추가하는 방법을 강력히 추천합니다.

이 방법은 API의 일관성과 예측 가능성이라는 장기적인 가치를 지키는 선택입니다. 좋은 API는 사용자가 고민 없이 당연하게 사용할 수 있어야 하며, 일관성은 이를 위한 가장 중요한 요소 중 하나입니다. ?


 notify의 종류로 앞으로 추가가 예상되는 것들이 있을까? 현재 xkb_compose_cancelled가 있다.

네, xkb_compose_cancelled 외에도 일반화된 notify 콜백을 통해 전달하면 유용한 여러 상태 변화 및 이벤트가 있습니다. IME(입력기)의 특성을 고려할 때, 앞으로 다음과 같은 종류의 알림들이 추가될 수 있습니다.

이벤트들을 성격에 따라 몇 가지 범주로 나눌 수 있습니다.


## 1. 사용자 입력 피드백 (User Input Feedback)

사용자의 키 입력에 대한 직접적인 반응 중, 문자 입력이나 preedit 변경이 아닌 미묘한 상태를 알립니다.

  • INVALID_KEY_PRESS

    • 설명: 현재 입력 상태에서 아무 기능도 하지 않는 키가 눌렸을 때 발생합니다. 예를 들어, 한글 조합 중에 갑자기 Page Up 키를 누르는 경우입니다. 클라이언트는 이 알림을 받아 경고음이나 시각적 효과로 사용자에게 유효하지 않은 입력임을 알릴 수 있습니다. COMPOSE_CANCELLED 조합 시퀀스의 실패를 알린다면, 이것은 단일 키 입력의 무효함을 알립니다.
  • SELECTION_WRAPPED

    • 설명: 후보창 목록에서 마지막 항목 다음에 아래 방향키를 누르거나, 첫 항목 이전에 위 방향키를 눌러 선택이 순환될 때 발생합니다. 클라이언트는 이를 인지하여 사용자에게 미묘한 소리 피드백 등을 제공할 수 있습니다.

## 2. 상태 및 모드 변경 (State and Mode Changes) ?

IME 엔진의 내부 상태나 입력 모드가 변경되었음을 알립니다. 클라이언트 UI를 동기화하는 데 매우 중요합니다.

  • INPUT_MODE_CHANGED
    • 설명: 한/영 키 입력 등으로 입력 언어 모드(예: 한글 ↔ 영어)가 변경되었을 때 발생합니다. 클라이언트는 이 알림을 받아 트레이 아이콘이나 상태바의 언어 표시를 에서 EN으로 바꾸는 등의 UI 업데이트를 수행해야 합니다.
  • HANJA_MODE_ACTIVATED
    • 설명: 한자 키 입력으로 한자 변환 모드가 활성화되거나 비활성화될 때 발생합니다.
  • FULL_WIDTH_MODE_CHANGED
    • 설명: 전각/반각 변환 키 입력으로 문자 폭 모드가 변경되었을 때 발생합니다.
  • COMPOSITION_CLEARED_AUTOMATICALLY
    • 설명: 사용자가 직접 지운 것이 아니라, 포커스 이동 등의 이유로 엔진이 내부적으로 조합 중인 글자(preedit)를 초기화했을 때 발생합니다. 클라이언트가 자체적으로 관리하는 상태와 동기화할 때 유용할 수 있습니다.

## 3. 엔진 및 시스템 이벤트 (Engine and System Events) ⚙+

엔진의 동작이나 외부 설정과 관련된 이벤트를 알립니다.

  • CONFIG_RELOADED
    • 설명: 별도의 설정 프로그램 등에서 사용자가 IME 설정을 변경하여, 실행 중인 엔진이 해당 설정을 다시 불러왔을 때 발생합니다. 클라이언트가 설정과 관련된 UI를 가지고 있다면 이를 갱신할 수 있습니다.
  • DICTIONARY_UPDATED
    • 설명: 사용자 사전이 추가/변경되었을 때 이를 알립니다.

## 4. 오류 및 경고 (Error and Warning Conditions) ⚠+

단순한 입력 실패보다 더 심각한 오류 상황을 알립니다.

  • DICTIONARY_LOOKUP_FAILED
    • 설명: 한자 변환 등을 위해 사전을 조회해야 하는데, 사전 파일이 손상되었거나 접근할 수 없을 때 발생합니다. 클라이언트는 사전 파일을 찾을 수 없습니다와 같은 구체적인 오류 메시지를 사용자에게 보여줄 수 있습니다.
  • MAX_PREEDIT_LENGTH_REACHED
    • 설명: 엔진이 허용하는 최대 조합 글자 수(preedit)에 도달했는데 사용자가 입력을 계속 시도할 때 발생합니다.

## 종합 예시 (Enum Definition Example)

이러한 아이디어들을 종합하면 CimNotificationType 열거형은 다음과 같이 정의될 수 있습니다.

typedef enum {
  /* User Input Feedback */
  CIM_NOTIFICATION_COMPOSE_CANCELLED,
  CIM_NOTIFICATION_INVALID_KEY_PRESS,
  CIM_NOTIFICATION_SELECTION_WRAPPED,

  /* State and Mode Changes */
  CIM_NOTIFICATION_INPUT_MODE_CHANGED,
  CIM_NOTIFICATION_HANJA_MODE_ACTIVATED,
  CIM_NOTIFICATION_FULL_WIDTH_MODE_CHANGED,
  CIM_NOTIFICATION_COMPOSITION_CLEARED_AUTOMATICALLY,

  /* Engine and System Events */
  CIM_NOTIFICATION_CONFIG_RELOADED,
  CIM_NOTIFICATION_DICTIONARY_UPDATED,

  /* Error and Warning Conditions */
  CIM_NOTIFICATION_DICTIONARY_LOOKUP_FAILED,
  CIM_NOTIFICATION_MAX_PREEDIT_LENGTH_REACHED

} CimNotificationType;










최종 결과는 다음과 같다.

ㅋㅋㅋ



typedef struct _CimCallbacks CimCallbacks;
struct _CimCallbacks {
  void (*preedit_start)     (CimIcHandle ic, void* user_data);
  void (*preedit_end)       (CimIcHandle ic, void* user_data);
  void (*preedit_changed)   (CimIcHandle ic,
                             const CimPreedit* preedit,
                             void* user_data);
  void (*commit)            (CimIcHandle ic,
                             const char* text,
                             void* user_data);
  /* Do not free CimSurround and its text */
  const CimSurround* (*get_surround) (CimIcHandle ic, void* user_data);
  bool (*delete_surround)   (CimIcHandle ic,
                             int32_t  offset,
                             uint32_t n_chars,
                             void*  user_data);
  /* candidate */
  void (*candidate_show)     (CimIcHandle ic,
                              uint32_t n_rows,
                              uint32_t n_cols,
                              bool show_aux,
                              void* user_data);
  void (*candidate_hide)     (CimIcHandle ic, void* user_data);
  void (*candidate_changed)  (CimIcHandle ic,
                              const CimCandidate* candidate,
                              void* user_data);
  void (*candidate_selected) (CimIcHandle ic,
                              const CimSelection* selection,
                              void* user_data);
  void (*notify) (CimIcHandle ic,
                  CimNotificationType type,
                  void* user_data);
  /* reserved */
  void* reserved[5];
};



추천 비추천

0

고정닉 0

0

댓글 영역

전체 댓글 0
본문 보기

하단 갤러리 리스트 영역

왼쪽 컨텐츠 영역

갤러리 리스트 영역

갤러리 리스트
번호 제목 글쓴이 작성일 조회 추천
설문 공개연애가 득보다 실인 것 같은 스타는? 운영자 25/10/06 - -
AD 프로게이머가 될테야!! 운영자 25/10/01 - -
2892726 게임쪽 창업<<이거 씨발 사기만 안먹었어도 계속했는데 [4] ㅆㅇㅆ(124.216) 09.28 113 0
2892725 if문에서 3일 걸리는 애들도 있네 [6] 루도그담당(58.239) 09.28 134 0
2892720 매일 4~5시간 자니까 건강이 엉망되었네 ㅎㅎ 나르시갤로그로 이동합니다. 09.28 42 0
2892719 ㅆㅇㅆ 이사람 요즘 뭐함? [2] ㅇㅇ갤로그로 이동합니다. 09.28 88 3
2892718 SM이 기술력이 낮다? 규모도 기술력이란걸 간과하지마 프갤러(219.115) 09.28 47 0
2892708 나님두 부천Bj 하구 싶당 야차 뜨실 분 구함 ♥냥덩이♥갤로그로 이동합니다. 09.28 66 0
2892691 게임 같은거 만들 때, 컴하하스러운 내용 넣으면 어떤거 같음? [1] ㅇㅇ(106.241) 09.28 49 0
2892688 [애니뉴스] 소설 연재 사이트 제작 현황 프갤러(121.172) 09.28 42 0
2892677 러스트는 어려운 언어가 아니라 귀찮은 언어입니다. 프갤러(110.8) 09.28 70 0
2892676 방정리중 [1] 넥도리아(220.74) 09.28 72 0
2892673 크래시 에러 찾기 겁나 쉬워요 나르시갤로그로 이동합니다. 09.28 65 0
2892672 ■개발자 평균 정년은 40대 중반.jpg ㅇㅇ갤로그로 이동합니다. 09.28 114 1
2892670 리액트 이런거 쓰는거 진짜 위험하네 [3] ㅇㅇ(118.34) 09.28 190 0
2892669 러스트 아무도 안 써요 [9] 나르시갤로그로 이동합니다. 09.28 91 0
2892667 비전공자 특 ㅇㅇ(211.234) 09.28 76 3
2892666 바이브코딩으로는 넘을 수 없는 장벽은 존재함. 컴파일러라거나 ㅆㅇㅆ(124.216) 09.28 95 0
2892665 그래도 도저히 프로그래밍 못 놓겠다하면 바이브코딩부터 시작해라 ㅆㅇㅆ(124.216) 09.28 75 0
2892664 그냥 중딩이면 바이브 코딩으로 시작해라 파이썬, 자바 배우는건 그때가서 ㅆㅇㅆ(124.216) 09.28 89 0
2892662 중고등학생이면 그냥 대학 성적 잘받아라. 이거밖에 없다 [4] ㅆㅇㅆ(124.216) 09.28 125 0
2892661 중학교 2학년 프로그래밍 시작하려면 [2] 프갤러(221.154) 09.28 108 0
2892656 지피티 코드만 수정하면되요 이러는 애들 뺨때리고 싶은데 정상이냐 ㅆㅇㅆ(124.216) 09.28 66 0
2892650 근데 카톡 서비스 절대 못되돌릴거 같은데 저거 광고비 받았을거 아냐 ㅆㅇㅆ(124.216) 09.28 76 1
2892649 임마들 맨날 유튜브에 낚이는 이유도 알거 같노 ㅇㅇ갤로그로 이동합니다. 09.28 57 0
2892648 냥덩 versus 야옹 ㅇㅇ(223.38) 09.28 64 0
2892647 런타임 디버깅 개지랄해야하는 것들 러스트는 컴파일 타임에 거의 잡습니다. 프갤러(223.63) 09.28 58 0
2892646 러스트 홍보는 영업이 아닙니다. 프갤러(223.63) 09.28 56 0
2892645 나님은 마허라임 ㅇㅅㅇ ♥냥덩이♥갤로그로 이동합니다. 09.28 59 0
2892641 나님 강의 ♥냥덩이♥갤로그로 이동합니다. 09.28 61 0
2892639 [대한민국] 시사매거진-전쟁 발발 가능성 언급 프갤러(121.172) 09.28 60 0
2892636 프갤럼들 맨날 하는게 영업 아니었나?? [2] ㅇㅇ갤로그로 이동합니다. 09.28 75 0
2892635 ■AI 때문에 웹개발 자체를 포기해야하나 고민중이다 [3] ㅇㅇ갤로그로 이동합니다. 09.28 160 0
2892634 친중무능극좌 리짜이밍 부정평가 48% 과반 붕괴 ♥냥덩이♥갤로그로 이동합니다. 09.28 78 1
2892630 사람이 정말 열심히 살아야 하는것 같아... 항상 제대로 똑바로 살아야해 [1] ㅇㅇ(223.38) 09.28 61 0
2892627 월요일날 우체국에서 틀딱들 정모 하겟네 야옹아저씨갤로그로 이동합니다. 09.28 56 0
2892626 냥덩이 ♥냥덩이♥갤로그로 이동합니다. 09.28 69 0
2892620 [대한민국] 미 - 콜로비아 대통령 비자 취소 프갤러(121.172) 09.28 51 0
2892619 자러감..ㅇㅅㅇ 헤르 미온느갤로그로 이동합니다. 09.28 47 0
2892618 미용실에 왔어요 ㅇㅅㅇ 헤르 미온느갤로그로 이동합니다. 09.28 59 0
2892617 태연 ㅇㅅㅇ 헤르 미온느갤로그로 이동합니다. 09.28 47 0
2892616 하루 한 번 헤르미온느 찬양 헤르 미온느갤로그로 이동합니다. 09.28 68 0
2892614 러빨러는 왜 러스트 코드 안 올리는 거임? [3] 나르시갤로그로 이동합니다. 09.28 88 0
2892613 병렬처리 먹통 디버깅 ㅋㅋ [1] 나르시갤로그로 이동합니다. 09.28 68 0
2892567 난데요. 고장한 SSD 펌웨어 복구 어려워요. 넥도리아(223.38) 09.28 74 0
2892565 야동 보는데, 미쳐버릴 것 같다. 넥도리아(223.38) 09.28 89 0
2892562 보통 외주받는 랜딩페이지는 길게 세로로 휴대폰 스크롤에 [4] ㅆㅇㅆ(118.235) 09.28 110 0
2892555 일단 타로 관련 도메인 사려고 고민중 ㅆㅇㅆ(124.216) 09.28 65 0
2892547 로우 포인터 안 쓸거면 뭐하러 C++ 씀 [2] ㅇㅇ(106.241) 09.28 106 1
2892545 Ada 프로그래밍, 3.2 예약어 (reserved words) 나르시갤로그로 이동합니다. 09.28 55 0
2892544 Ada 프로그래밍, 3.1 식별자 (identifier) 나르시갤로그로 이동합니다. 09.28 61 0
2892543 근데 영업 전환이라는게 결국은 CTO로써 도태됐거나 그 이상의 기술이 [2] ㅆㅇㅆ(124.216) 09.28 103 0
뉴스 '친한친구' 템페스트, 추석에도 열일 모드…꽃도령 변신에 컴백 스포일러까지 완벽 접수 디시트렌드 10.08
갤러리 내부 검색
제목+내용게시물 정렬 옵션

오른쪽 컨텐츠 영역

실시간 베스트

1/8

뉴스

디시미디어

디시이슈

1/2