무슨 일이 있었나 오픈AI가 DevDay 2026에서 상시 작동(always-on) AI 에이전트 'dots'를 공개했다. dots는 자체 클라우드 컴퓨터에서 24시간 구동되며 리서치, 데이터 분석, 코딩 등의 작업을 사용자 개입 없이 스스로 처리한다. 최상위 모델인 GPT-6 Astra를 기반으로 동작한다. dots는 사용자와 관련된 맥락을 지속적으로 학습해 무엇이 중요한지 파악하고, 사용자를 대신해 계속 작업을 수행하며, 중요한 업무 부담을 덜어주는 것을 목표로 설계됐다. 4000개 이상의 앱과 연동할 수 있고, 사용자 피드백을 통해 점차 개선되는 방식으로 동작한다. 예컨대 Slack에 버그가 보고되면 dots가 즉시 원인 조사에 착수하거나, 새 디자인 시안이 도착하면 실제 동작하는 앱으로 구현하는 식이다. dots는 발표 당일부터 Pro 및 Business Premium 사용자에게 제공되며, Enterprise 사용자도 워크스페이스 관리자의 승인을 받으면 사용할 수 있다. 사용자는 ChatGPT, Slack, Teams 안에서 dots에 메시지를 보내 작업을 지시할 수 있고, 문자메시지(SMS) 연동도 곧 지원될 예정이다. 왜 중요한가 dots는 '질문에 답하는 챗봇'에서 '알아서 일하는 동료'로 AI의 역할을 바꾸려는 오픈AI의 승부수다. 이는 최근 메타가 기업용 AI 플랫폼 '뮤즈(Muse)'를 앞세워 상시 구동 에이전트 시장에 뛰어든 것과 정확히 같은 타깃을 겨냥한다. 두 회사 모두 업무 자동화의 무게중심을 '사람이 프롬프트를 입력하는 모델'에서 '스스로 판단하고 지속적으로 일하는 에이전트'로 옮기려 하고 있다. 이런 상시 에이전트는 기업 생산성 소프트웨어 시장의 판도를 바꿀 잠재력이 있지만 동시에 보안·거버넌스 문제도 키운다. 4000개 앱에 연동되고 스스로 판단해 작업을 수행하는 에이전트는 권한 오남용, 데이터 유출, 의도치 않은 행동 등의 리스크를 동반하기 때문에, 기업들은 편의성과 통제 가능성 사이에서 새로운 균형점을 찾아야 할 것으로 보인다. 같은 날 앤스로팩이 오픈소스 모델의 사이버 위협 능력을 경고하는 연구를 발표한 것도 이런 맥락에서 시사하는 바가 크다 — 자율성이 높은 AI 시스템이 늘어날수록 안전장치의 중요성도 함께 커지고 있다. 원문: https://openai.com/index/introducing-dots/
김영한님의 자바 ORM 표준 JPA 프로그래밍 강의를 듣고 정리한 글입니다. 실습 환경: PostgreSQL + Hibernate 6(jakarta) 1. JPA에서 가장 중요한 2가지 객체와 관계형 데이터베이스 매핑하기 (ORM, Object Relational Mapping) → 설계와 관련된 부분. "엔티티를 테이블에 어떻게 매핑할까?" 영속성 컨텍스트 → JPA가 내부에서 실제로 어떻게 동작하는지 에 대한 부분 이번 글은 2번, 영속성 컨텍스트 를 다룹니다. 이 부분을 이해하면 " persist() 를 했는데 왜 INSERT가 바로 안 나가지?", "수정할 때 왜 update() 가 없지?" 같은 궁금증이 전부 풀립니다. 2. 엔티티 매니저 팩토리와 엔티티 매니저 [요청1] → EntityManager1 ─┐ ├─ (EntityManagerFactory가 생성) [요청2] → EntityManager2 ─┘ │ └─ 커넥션 풀의 conn 사용 → DB EntityManagerFactory : 애플리케이션에 하나 만 존재합니다. EntityManager : 고객의 요청이 올 때마다 팩토리가 새로 만들어 줍니다. EntityManager는 DB 작업이 필요할 때 커넥션 풀에서 커넥션을 하나 빌려서 사용합니다. 3. 영속성 컨텍스트란? "엔티티를 영구 저장하는 환경" 이라는 뜻입니다. em.persist(member); 이 코드를 "DB에 저장한다"로 이해하기 쉽지만, 정확히는 "member 엔티티를 영속성 컨텍스트에 저장한다" 는 뜻입니다. DB에 실제로 저장되는 시점은 그 뒤입니다. 아래에서 자세히 다룹니다. 눈에 보이지 않는 논리적 개념 영속성 컨텍스트는 논리적인 개념 이라 코드에서 직접 볼 수 없습니다. 대신 EntityManager를 통해서 접근 합니다. 쉽게 비유하면 이렇습니다. EntityManager = 창구 직원 , 영속성 컨텍스트 = 창구 뒤에 있는 작업 공간(메모리) 우리는 창구 직원( em )에게 요청만 하고, 직원은 뒤쪽 작업 공간에서 엔티티를 관리합니다. 환경에 따른 관계 환경 EntityManager : 영속성 컨텍스트 J2SE (지금 실습처럼 main 메서드) 1 : 1 J2EE, 스프링 같은 컨테이너 환경 N : 1 (같은 트랜잭션이면 같은 영속성 컨텍스트 공유) 지금은 "EntityManager를 하나 만들면 영속성 컨텍스트도 하나 생긴다" 정도로 이해하면 충분합니다. 4. 엔티티의 생명주기 엔티티는 영속성 컨텍스트와의 관계에 따라 4가지 상태 를 가집니다. 상태 의미 어떻게 되나 비영속 (new/transient) 영속성 컨텍스트와 전혀 관계없는 새 객체 new Member() 영속 (managed) 영속성 컨텍스트가 관리하는 상태 persist() , find() , JPQL 조회 준영속 (detached) 관리받다가 분리된 상태 detach() , clear() , close() 삭제 (removed) 삭제하기로 예약된 상태 remove() detach/clear/close ┌────────────────────────────→ [준영속] │ ←──── merge() ────────┘ [비영속] ── persist() ──→ [영속] ── flush() ──→ DB │ ↑ remove() persist() ↓ │ [삭제] ── flush() ──→ DB 비영속 // 객체를 생성만 한 상태 → JPA와 아무 관계 없음 Member member = new Member(); member.setId(1L); member.setName("회원1"); 그냥 평범한 자바 객체입니다. 영속 EntityManager em = emf.createEntityManager(); em.getTransaction().begin(); // 객체를 저장한 상태 → 영속성 컨텍스트가 관리 시작 em.persist(member); ⚠️ 영속 상태가 됐다고 DB에 저장된 것은 아닙니다! persist() 시점에는 INSERT 쿼리가 나가지 않습니다. 트랜잭션을 커밋하는 시점 에 나갑니다. 직접 확인하고 싶으면 persist() 전후와 commit() 전후에 System.out.println 을 찍어 보세요. 준영속, 삭제 // 영속성 컨텍스트에서 분리 → 준영속 em.detach(member); // 삭제 예약 → 커밋 시 DELETE 쿼리 실행 em.remove(member); 5. 영속성 컨텍스트를 쓰면 좋은 점 애플리케이션과 DB 사이에 중간 계층 이 하나 생기는 셈입니다. 중간 계층이 있으면 버퍼링 과 캐싱 을 할 수 있고, 그 덕분에 아래 기능들이 생깁니다. 1차 캐시 동일성(identity) 보장 트랜잭션을 지원하는 쓰기 지연 변경 감지 (Dirty Checking) 지연 로딩 (Lazy Loading) → 뒤에서 다룸 5-1. 1차 캐시 영속성 컨텍스트 내부에는 1차 캐시 라는 Map이 있습니다. @Id (Key) Entity (Value) 1L member 객체 persist() 를 하면 1차 캐시에 먼저 저장 됩니다. 1차 캐시에서 조회 Member member = new Member(); member.setId(1L); member.setName("회원1"); em.persist(member); // 1차 캐시에 저장 Member findMember = em.find(Member.class, 1L); // 1차 캐시에서 조회 → SELECT 안 나감! find() 를 하면 DB보다 1차 캐시를 먼저 확인 합니다. 있으면 DB에 가지 않고 캐시에서 바로 꺼내 줍니다. DB에서 조회 Member findMember2 = em.find(Member.class, 2L); 1차 캐시에서 2L을 찾음 → 없음 DB에서 조회 (SELECT 쿼리 실행) 조회한 결과를 1차 캐시에 저장 엔티티 반환 그래서 같은 엔티티를 두 번 조회하면 SELECT는 한 번만 나갑니다. Member m1 = em.find(Member.class, 2L); // SELECT 쿼리 실행 Member m2 = em.find(Member.class, 2L); // 1차 캐시에서 조회 → 쿼리 없음 💡 1차 캐시는 성능상 큰 이점은 아닙니다. EntityManager는 보통 트랜잭션 단위 로 만들고 트랜잭션이 끝나면 사라집니다. 그래서 1차 캐시도 한 트랜잭션 안에서만 살아 있습니다. 여러 사용자가 공유하는 캐시는 2차 캐시 라고 부르며, 별개의 개념입니다. 1차 캐시는 성능보다 아래의 동일성 보장, 변경 감지를 가능하게 해 주는 기반 이라는 점이 더 중요합니다. 5-2. 영속 엔티티의 동일성 보장 Member a = em.find(Member.class, 1L); Member b = em.find(Member.class, 1L); System.out.println(a == b); // true 같은 1차 캐시에서 꺼내기 때문에 완전히 같은 인스턴스 입니다. 마치 자바 컬렉션에서 같은 key로 두 번 꺼낸 것 처럼 동작합니다. 💡 어려운 말로 하면 1차 캐시 덕분에 반복 가능한 읽기(REPEATABLE READ) 수준의 트랜잭션 격리를 DB가 아니라 애플리케이션 차원에서 제공합니다. 즉 같은 트랜잭션 안에서 같은 엔티티를 몇 번 조회하든 항상 같은 결과를 보장합니다. 5-3. 트랜잭션을 지원하는 쓰기 지연 (엔티티 등록) EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); tx.begin(); // 트랜잭션 시작 em.persist(memberA); em.persist(memberB); // 여기까지 INSERT SQL을 DB에 보내지 않음! tx.commit(); // 커밋하는 순간 INSERT SQL을 한꺼번에 보냄 내부 동작 영속성 컨텍스트 안에는 1차 캐시 말고도 쓰기 지연 SQL 저장소 가 있습니다. 1 em.persist(memberA) memberA를 1차 캐시에 저장 INSERT A 쿼리를 만들어서 쓰기 지연 SQL 저장소에 쌓아 둠 2 em.persist(memberB) memberB를 1차 캐시에 저장 INSERT B 쿼리를 쓰기 지연 SQL 저장소에 추가 3 tx.commit() flush : 쌓아 둔 SQL(INSERT A, INSERT B)을 DB로 전송 commit : 실제 DB 트랜잭션 커밋 왜 모아서 보낼까? 비유: 마트에서 물건 하나 살 때마다 계산대에 가지 않고, 장바구니에 담았다가 한 번에 계산 하는 것과 같습니다. 어차피 커밋 전에는 DB에 반영돼도 확정된 게 아닙니다. 그러니 커밋 직전에만 보내면 됩니다. 모아서 보내면 DB와의 통신 횟수를 줄일 수 있습니다. <!-- persistence.xml: 쿼리를 최대 10개씩 모아서 한 번에 전송 --> <property name="hibernate.jdbc.batch_size" value="10"/> 💡 예외 : 기본 키 생성 전략이 IDENTITY (DB의 auto increment, PostgreSQL의 serial / identity )라면 DB에 INSERT를 해야 ID를 알 수 있습니다. 그래서 persist() 시점에 바로 INSERT가 나갑니다. 기본 키 매핑 파트에서 자세히 다룹니다. 5-4. 변경 감지 (Dirty Checking) - 엔티티 수정 tx.begin(); // 영속 엔티티 조회 Member memberA = em.find(Member.class, 1L); // 영속 엔티티 데이터 수정 memberA.setName("hi"); // em.update(memberA); ← 이런 코드가 있어야 할 것 같지만... 필요 없음! tx.commit(); // UPDATE 쿼리가 자동으로 나감 JPA의 목표는 "자바 컬렉션처럼 다루기" 입니다. 컬렉션에서 꺼낸 객체의 값을 바꾸고 나서 list.set() 을 다시 호출하지 않는 것과 같은 원리입니다. 내부 동작: 스냅샷 1차 캐시에는 사실 스냅샷 칸이 하나 더 있습니다. @Id Entity 스냅샷 1L memberA (현재 값) memberA (처음 조회했을 때 값) commit() → 내부적으로 flush() 호출 엔티티와 스냅샷을 하나하나 비교 바뀐 게 있으면 UPDATE SQL을 만들어 쓰기 지연 SQL 저장소에 등록 SQL을 DB로 전송 (flush) DB 커밋 ⚠️ 변경 감지는 영속 상태 인 엔티티에만 동작합니다. 준영속이나 비영속 엔티티는 값을 바꿔도 UPDATE가 나가지 않습니다. 💡 Hibernate는 기본적으로 모든 컬럼을 UPDATE 합니다. (바뀐 컬럼만 보내지 않음) 쿼리 모양이 항상 같아서 재사용하기 좋기 때문입니다. 바뀐 컬럼만 보내고 싶다면 엔티티에 @DynamicUpdate 를 붙이면 됩니다. 5-5. 엔티티 삭제 Member memberA = em.find(Member.class, 1L); em.remove(memberA); // 커밋 시점에 DELETE 쿼리 실행 등록과 마찬가지로 DELETE 쿼리도 쓰기 지연 SQL 저장소에 쌓였다가 커밋 시점에 나갑니다. 6. 플러시 (flush) 영속성 컨텍스트의 변경 내용을 DB에 반영(동기화)하는 것 플러시가 일어나면 생기는 일 변경 감지 동작 수정된 엔티티의 UPDATE 쿼리를 쓰기 지연 SQL 저장소에 등록 쓰기 지연 SQL 저장소의 쿼리를 DB에 전송 (등록, 수정, 삭제 쿼리) ⚠️ 플러시 ≠ 커밋 플러시는 쿼리를 DB에 보내기만 하는 것이고, 확정은 커밋이 합니다. 플러시 후에 롤백하면 DB에 반영된 내용도 취소됩니다. 플러시하는 방법 3가지 방법 설명 em.flush() 직접 호출 (거의 안 씀. 테스트할 때 가끔 사용) 트랜잭션 커밋 플러시 자동 호출 JPQL 쿼리 실행 플러시 자동 호출 Member member = new Member(200L, "member200"); em.persist(member); em.flush(); // 이 시점에 INSERT 쿼리가 바로 나감 System.out.println("=========="); tx.commit(); JPQL을 실행하면 왜 자동으로 플러시될까? em.persist(memberA); em.persist(memberB); em.persist(memberC); // 아직 INSERT는 쓰기 지연 저장소에만 있고 DB에는 없음 // 중간에 JPQL 실행 List<Member> members = em.createQuery("select m from Member m", Member.class) .getResultList(); JPQL은 1차 캐시를 거치지 않고 SQL로 번역돼서 바로 DB에 날아갑니다. 그런데 이 시점의 DB에는 memberA, B, C가 아직 없습니다. 플러시를 하지 않으면 방금 저장한 데이터가 조회되지 않는 문제가 생깁니다. 그래서 JPA는 이런 실수를 막기 위해 JPQL을 실행하기 전에 자동으로 플러시 합니다. 플러시 모드 옵션 em.setFlushMode(FlushModeType.COMMIT); 모드 동작 FlushModeType.AUTO 커밋이나 쿼리 실행 시 플러시 ( 기본값, 이걸 그대로 쓰면 됨 ) FlushModeType.COMMIT 커밋할 때만 플러시 플러시 핵심 정리 플러시는 영속성 컨텍스트를 비우지 않습니다. (1차 캐시는 그대로 남아 있음) 영속성 컨텍스트의 변경 내용을 DB에 동기화 하는 것입니다. 트랜잭션이라는 작업 단위가 중요합니다 → 커밋 직전에만 동기화하면 됩니다. 7. 준영속 상태 영속 상태였던 엔티티가 영속성 컨텍스트에서 분리(detached)된 상태 분리됐기 때문에 영속성 컨텍스트가 제공하는 기능(1차 캐시, 변경 감지 등)을 사용할 수 없습니다. 준영속 상태로 만드는 방법 메서드 동작 em.detach(entity) 특정 엔티티만 준영속으로 전환 em.clear() 영속성 컨텍스트를 완전히 초기화 (1차 캐시 전부 비움) em.close() 영속성 컨텍스트를 종료 예제 1: detach하면 변경 감지가 안 된다 Member member = em.find(Member.class, 1L); // 영속 member.setName("AAAAA"); em.detach(member); // 준영속으로 분리 tx.commit(); // UPDATE 쿼리 안 나감! (SELECT만 한 번 나감) JPA가 더 이상 member를 관리하지 않기 때문에 값을 바꿔도 모릅니다. 예제 2: clear 후 다시 조회하면 SELECT가 또 나간다 Member member1 = em.find(Member.class, 1L); // SELECT 쿼리 em.clear(); // 1차 캐시 초기화 Member member2 = em.find(Member.class, 1L); // 캐시가 비었으므로 SELECT 쿼리 또 나감 System.out.println(member1 == member2); // false! (다른 인스턴스) 💡 em.clear() 는 테스트 코드에서 자주 씁니다. 1차 캐시 때문에 DB에 가지 않고 캐시 값이 나오는 걸 막고, DB에서 실제로 어떻게 조회되는지 확인하고 싶을 때 사용합니다. 💡 준영속 엔티티를 다시 영속으로 만들 때는 em.merge() 를 씁니다. 웹 애플리케이션 파트에서 자세히 다룹니다. 정리 개념 한 줄 요약 영속성 컨텍스트 엔티티를 관리하는 논리적인 공간. EntityManager로 접근 생명주기 비영속 → 영속 → 준영속/삭제 1차 캐시 영속성 컨텍스트 안의 Map. 조회 시 DB보다 먼저 확인 동일성 보장 같은 트랜잭션에서 같은 ID로 조회하면 == 비교가 true 쓰기 지연 SQL을 모아 뒀다가 커밋 시점에 한 번에 전송 변경 감지 스냅샷과 비교해서 바뀐 엔티티는 자동으로 UPDATE 플러시 변경 내용을 DB에 동기화 (비우는 게 아님, 커밋도 아님) 준영속 영속성 컨텍스트에서 분리 → 변경 감지 등 기능 사용 불가
무슨 일이 있었나 앤스로픽이 2026년 9월 29일 발표한 연구에서 중국 지푸AI(Z.ai)의 오픈웨이트 모델 'GLM-5.3'을 "지금까지 공개된 오픈웨이트 모델 중 가장 사이버 공격 능력이 뛰어난 모델"(NIST 평가 기준)이라고 지적했다. 문제는 이 모델이 이전 최상위 모델들과 달리 오남용을 막는 실질적 안전장치 없이 공개됐다는 점이다. 연구진에 따르면 GLM-5.3은 크롬 V8 버그를 대상으로 한 'ExploitBench'에서 약 12%의 확률로 종단간(end-to-end) 익스플로잇 개발에 성공했고, 앤스로픽 자체 바이너리 익스플로잇 벤치마크(제어 흐름 탈취)에서도 4%의 성공률을 보였다. 이는 앤스로픽의 최신 모델 'Claude Mythos Preview'와 맞먹는 수준으로, 이전 세대 모델 대비 큰 도약이라는 평가다. 실제 실험에서는 GLM-5.3이 하루 만에 한 웹브라우저의 자바스크립트 엔진에서 알려지지 않은 취약점을 발견하고, 이를 연결해 방문자 컴퓨터의 임의 파일을 탈취하는 작동 가능한 익스플로잇 체인을 만들어낸 사례도 확인됐다. 경량화 버전인 GLM-5.3-Flash는 이미 공개된 크롬 취약점을 단 20분의 작업만으로 실동작하는 익스플로잇 체인으로 바꿔냈으며, 소요 비용은 API 기준 약 20.40달러에 불과했다. 더 심각한 문제는 안전장치 우회가 매우 쉽다는 점이다. 연구진은 △거짓 명분을 내세운 기만적 프롬프트(우회율 64%) △추론 토큰 사전 주입(92%) △가중치를 직접 수정하는 '어블리테이션(abliteration)'(100%) 등 단순한 기법만으로 GLM-5.3의 안전장치를 64~100% 확률로 무력화할 수 있었다고 밝혔다. 특히 어블리테이션은 해당 기법 경험이 없는 연구자가 GPU 2200시간(약 4400달러)만 들여도 거부율을 95%에서 약 6%로 낮추면서 성능은 그대로 유지할 수 있었다. 반면 안전장치가 적용된 앤스로픽의 클로드 모델들은 세 가지 우회 기법 모두에 저항력을 유지했다. 왜 중요한가 이번 연구는 오픈웨이트 AI 모델의 확산이 사이버 보안 지형을 실질적으로 바꾸고 있음을 구체적 수치로 보여준다. 앤스로픽은 국가 행위자는 물론 비국가 행위자까지 이런 능력을 실제 공격에 악용할 가능성이 높다고 평가했으며, 이미 공격자들이 AI 시스템을 무기화하려는 시도가 문서로 확인되고 있다고 밝혔다. 동시에 연구진은 방어자 역시 공격자와 대등한 수준의 AI 도구를 확보해야 한다고 강조했다. 이는 단순히 위험한 모델의 공개를 막는 것만으로는 문제가 해결되지 않으며, 검증된 보안 방어팀에 최첨단 모델 접근권을 확대하고 각국 정부가 독립적인 안전성 테스트를 수행해야 한다는 정책적 권고로 이어진다. 오픈소스·오픈웨이트 모델의 안전장치를 어떻게 설계하고 검증할 것인가는 앞으로 AI 업계 전반에서 더욱 첨예한 쟁점이 될 전망이다. 원문: https://www.anthropic.com/research/glm-5-3-and-the-spread-of-advanced-cyber-capabilities
VLSI Power Vdd -> Capacitor -> Gnd Dynamic power capacitance swithcing crowbar current Static power Leakage current relation with energy and delay Low swing circuit idea: let's change unitil vdd/3 so that we can save power cons: we can not use normal gate weak at noise, can not tolerate noise, noise sensitive Gated clocks stop the clock and put the logic to sleep put the and gate with enable signal Increase length of transistors but sacrifice speed
게임 UI는 이미지나 버튼 같은 작은 요소부터 메인 화면, 인벤토리, HUD처럼 큰 묶음까지 다양한 단위가 있음 UI 단위를 구분하는 기준 구성 규모: 기본 요소인지, 여러 요소를 묶은 영역인지, 화면 전체인지 사용 역할: 조작, 상태 표시, 알림, 확인 등 어떤 목적을 가지는지 표시, 상호작용 방식: 다른 UI 위에 겹치는지, 뒤쪽 UI의 조작을 제한하는지 주의 사항 프로젝트와 팀에 따라 다를 수 있음 모든 단위가 하나의 엄격한 계층을 이루는 것은 아님 예를 들면 HUD는 사용 목적을 나타내며 내부에 Panel, Widget, Control 등이 포함될 수 있음 이 글에서는 UI의 구성과 역할을 설명하기 위해 용어를 구분하며, 엔진이나 프레임워크의 공식 타입 분류와는 다를 수 있음 (Unreal UMG에서는 Text, Button도 Widget으로 봄) UI 단위 정리 Element - 기본 구성 요소 이 글에서는 이미지, 텍스트, 구분선처럼 UI를 구성하는 기본적인 시각 요소를 Element로 구분함 다른 UI 단위를 구성하는 재료로 사용됨 배경 이미지 아이콘 이름, 수량 텍스트 구분선 등 Element 하나가 독립적인 기능을 가질 필요는 없음 모든 Element를 별도의 재사용 단위로 분리할 필요는 없음 예: Unity에서 아이템 슬롯 Prefab을 구성하는 Element(아이템 이름 Text, 아이템 아이콘 Image)들을 별도의 Prefab으로 만들 필요 없음 특정 화면에서만 사용하는 장식이나 문구는 해당 화면 내부에서 관리해도 됨 Control - 사용자 입력 요소 사용자의 조작을 받아 명령이나 값 변경을 전달하는 UI 클릭, 선택, 드래그, 문자 입력 등의 상호작용을 담당 Button, Toggle, Slider, Dropdown, Input Field 등 Control은 여러 Element로 구성될 수 있음 Button: 배경 Image + 버튼 문구 Text + 아이콘 Image Slider: 손잡이 Image + 채움 영역 Image + 트랙 Image 외형뿐 아니라 상호작용 상태도 고려해야 함 기본 상태 눌린 상태 선택, 체크 상태 포커스 상태 상호작용 불가 상태 등 여러 곳에서 동일한 외형과 동작을 사용하는 경우 독립적인 재사용 단위로 분리할 수 있음 예: 공통 확인 버튼, 닫기 버튼, 설정용 토글 Widget - 작은 기능 단위 여러 Element나 Control을 묶어 하나의 기능 또는 정보를 표현하는 단위 다른 화면에서 재사용하기 좋은 구성 단위 CurrencyDisplay: 재화 아이콘 + 보유량 ItemSlot: 아이템 아이콘 + 수량 + 선택 표시 HealthBar: 체력 게이지 + 현재 체력 SkillSlot: 스킬 버튼 + 쿨타임 + 사용 불가 표시 QuestEntry: 퀘스트 이름 + 진행도 + 상태 표시 구체적인 역할에 따라 ItemSlot, QuestEntry, CurrencyDisplay처럼 이름을 붙이기도 함 표시할 데이터를 전달받아 자신의 영역을 갱신하도록 구성할 수 있음 재사용뿐 아니라 기능별 책임 분리와 유지보수를 위해 구성할 수도 있음 외부에서 재사용하기 쉽도록 책임 범위를 작게 유지하는 편이 좋음 Widget은 프레임워크에 따라 Button이나 Text까지 포함하는 넓은 용어로 사용되기도 함 Panel - 관련 기능을 모은 영역 관련된 정보와 조작 기능을 하나의 구역으로 묶은 단위 화면 전체 또는 화면 일부를 차지할 수 있음 항상 표시하거나 필요할 때만 열고 닫을 수 있음 예시 ProfilePanel 닉네임, 레벨, 경험치 EquipmentPanel 장비 슬롯, 장비 능력치 ItemDetailPanel 아이템 이름, 설명, 능력치, 장착 버튼 인벤토리 화면에서는 아이템 목록 영역과 상세 정보 영역을 각각 Panel로 나눌 수도 있음 Screen / Page - 화면 단위 사용자가 하나의 화면으로 인식하는 큰 단위 여러 Panel, Widget, Control을 포함 화면 진입, 이탈과 전환의 기준으로 사용 예시 MainScreen: 메인 화면 ShopScreen: 상점 화면 InventoryScreen: 인벤토리 화면 ResultScreen: 결과 화면 Screen 수준에서 다음과 같은 흐름을 관리할 수 있음 화면에 진입할 때 필요한 정보 표시 하위 Panel 사이의 선택 상태 전달 다른 화면으로 이동하는 요청 전달 화면을 벗어날 때 입력과 이벤트 연결 정리 이러한 흐름은 Screen에 직접 구현하거나, Presenter·Controller·Flow 등 별도 객체에서 조율할 수 있음 Screen과 Page는 프로젝트에 따라 비슷하게 사용되거나, Screen 내부의 전환 영역을 Page라고 구분하기도 함 Screen 하나가 엔진의 Scene이나 Level 하나와 반드시 대응되는 것은 아님 Popup / Dialog - 임시 표시 단위 현재 화면을 유지하면서 추가 정보나 선택지를 제공하는 UI 일반적으로 기존 화면 위에 임시로 표시됨 Popup 보상이나 추가 정보, 부가 기능을 표시하는 창 예: 보상 팝업, 설정 팝업 Dialog 사용자의 확인이나 선택을 요청하는 창 예: 구매 확인, 게임 종료 확인 모든 임시 창을 Popup이라 부르기도 함 Popup / Dialog는 뒤쪽 UI와의 상호작용 허용 여부에 따라 Modal과 Modeless로 구분할 수 있음 Modal 닫거나 응답하기 전까지 뒤쪽 UI와의 상호작용을 제한 예: 구매 확인창 Modeless 표시된 상태에서도 뒤쪽 UI와 상호작용 가능 예: 이동하면서 확인할 수 있는 정보창 여러 창이 겹치면 입력 우선순위, 닫기 순서, 포커스 복귀도 고려해야 함 HUD - 플레이 중 정보와 조작 Heads-Up Display의 약자 게임을 플레이하면서 필요한 상태 정보를 제공하는 UI 모바일에서는 전투 버튼이나 가상 조이스틱 같은 조작 UI를 함께 묶기도 함 대표적인 구성 체력, 마나 점수, 남은 시간 현재 웨이브 미니맵 탄약 수 스킬 버튼, 쿨타임 HUD는 크기보다 플레이 중 사용한다는 목적에 따른 분류 플레이 영역을 지나치게 가리지 않아야 함 중요한 정보를 빠르게 읽고 조작할 수 있어야 함 Overlay - 다른 UI 위에 겹치는 표시 화면이나 다른 UI 위에 겹쳐 표시하는 단위 또는 레이어 화면 전환, 로딩 표시, 입력 차단 등에 사용 예시 LoadingOverlay 로딩 상태와 진행 정보 표시 FadeOverlay 화면 전환 시 밝아지거나 어두워지는 효과 DimOverlay 뒤쪽 화면을 어둡게 표시 InputBlocker 뒤쪽 UI로 전달되는 입력 차단 화면 전체 또는 일부를 덮을 수 있음 표시 순서와 입력 처리 순서를 고려해야 함 Popup을 Overlay 레이어에 배치할 수도 있음 Toast / Tooltip - 알림과 보충 설명 Toast 짧은 메시지를 전달하고 일정 시간이 지나면 사라지는 알림 일반적으로 사용자의 응답을 요구하지 않음 예시 "저장되었습니다" "골드가 부족합니다" "아이템을 획득했습니다" 여러 알림이 연속해서 발생한다면 표시 개수, 대기열, 중복 메시지 처리 등을 정할 수 있음 Tooltip 특정 UI 요소나 대상에 대한 보충 설명 대상과 연결된 문맥을 제공 예시 아이템 능력치 스킬 효과 상태 효과 설명 표시 방식 PC: 마우스 올리기, 키보드 포커스 Mobile: 터치, 길게 누르기 화면 밖으로 잘리지 않도록 표시 위치를 조절하고, 설명 대상과의 관계가 명확하게 보이도록 배치하는 것이 중요 재사용 단위를 나누는 기준 UI를 분리할 때 이름이나 크기뿐 아니라 재사용성과 책임 범위를 고려해야 함 아래 이유들이 어느 정도 충족된다면 프리팹이나 재사용 컴포넌트로 분리할 수 있음 여러 화면에서 반복 사용되는지 확인 버튼 공통 디자인을 한 번에 수정해야 하는지 목록 항목처럼 반복 생성되는지 아이템 슬롯 독립적으로 열고 닫는지 별도로 관리할 만큼 기능과 책임이 명확한지
2026년 목표 클라우드 환경 운영 경험(상세 내용은 추후 작성) 보안관제 자동화 경험 블로그 꾸준히 작성 자격증 : 정보처리기사(9월 시작), 정보보안기사, AWS-SAA,/// CISA 및 CISSP(정보 보안 관련 경력 5년 이상 필요 (4년 경력+보안 관련 학위 가능)) 개발 공부 영어 공부 운동 리팩토링 과정 복습 및 벨로그에 새롭게 작성 클라우드 보안 복습 및 벨로그에 작성 <내년 예정 - 석사 과정> 📅 공부 순서 - (Version 9-10월) 파이썬(점프 투 파이썬) 완강했음 정보처리기사 실기 - 10월 25일에 시험있음 합격 목표 모의해킹(노말틱 강의) - 10월 말까지 완료 목표 영어 - 11월부터 시작! 혼자공부하는 네트워크(인프런) 완강했음 - 10월에 지속적인 복습 리펙토링 과정 복습 시작(실습 및 블로그 재작성) Docker(인프런_devsecops) 강의(모의해킹 끝나고 시작) AWS 보안 가이드(인프런 강의) - (Docker 인프런 끝나고 시작) JAVA - (파이썬 끝나고 시작) 📅 금주 목표 - (09/28(월)~10/04(일)) 파이썬(점프 투 파이썬) Youtube 강의 + Ebook 참고 목표 : 점프 투 파이썬 학습 계속 진행 및 진도율 향상 정보처리기사 실기 목표 : 2020년도 기출문제 2회차 풀이 범위 : 1회차 ~ 4회차 목표 : 2021년도 기출문제 1회차 풀이 범위 : 1회차 ~ 3회차 목표 : 2022년도 기출문제 1회차 풀이 범위 : 1회차 ~ 3회차 모의해킹 목표 : Day 1 ~ Day 2 완료 범위 : 1주차 ~ 2주차 📅 오늘의 목표 : 완료 OR 미완료 OR 진행중 모의해킹(노말틱 강의) 1주차 ~ 하는데 까지 + 블로그 정리 파이썬(nmap 기능 구현해보기)DAY-1 + 블로그 정리 household account 작성(23:50분에 작성) 정보처리기사 DAY3(2020년도 2회차 문제풀이 및 복습) + 2021년도 1회차 문제풀이 + 2022년도 1회차 문제풀이 방청소 JAVA 뭘로 공부할지 찾아보기 혼자공부하는 네트워크 복습 DAY1 💻 오늘(완료) 한 일 파이썬(nmap 기능 구현해보기)DAY-1 + 블로그 정리
문제 : 모의고사 < 내가 생각한 풀이 > 목표 누가 가장 많은 문제를 맞혔는가? 수포자 1 분석 1번 수포자는 1 > 2 > 3 > 4 > 5 를 반복한다. 이 패턴을 배열 arr = [1, 2, 3, 4, 5] 로 두면, answers 의 인덱스 i 번 문제에 대한 답은 arr[i % 5] 이다. 주의 사항 문제는 1번부터 시작하므로, n번 문제의 인덱스는 n - 1 예시 30번 문제: 인덱스 29 -> 29 % 5 == 4 -> arr[4] = 5 48번 문제: 인덱스 47 -> 47 % 5 == 2 -> arr[2] = 3 66번 문제: 인덱스 65 -> 65 % 5 == 0 -> arr[0] = 1 수포자 2 분석 2번 수포자는 조금 특이해 보이지만, 2개씩 묶어 보면 규칙이 보인다. 2 1 | 2 3 | 2 4 | 2 5 | 2 1 | 2 3 | ... 짝수 인덱스 ( 0, 2, 4, ... ) -> answers 의 인덱스 i 번 문제에 대한 답은 항상 2 홀수 인덱스 ( 1, 3, 5, ... ) 1 > 3 > 4 > 5 를 반복한다. 이 패턴을 배열 arr = [1, 3, 4, 5] 로 두면, 홀수 인덱스 1, 3, 5, 7, ... 에서 1을 빼고 2로 나누면 0, 1, 2, 3, ... 이 된다. 이 번호로 arr 에서 순서대로 꺼내면 되므로, answers 의 인덱스 i 번 문제에 대한 답은 arr[((i - 1) / 2) % 4] 이다. 주의 사항 위에서 말한 짝수/홀수는 문제 번호가 아니라 인덱스 기준이다. 문제 번호는 1번부터 시작하므로, 문제 번호로 따지면 반대가 된다. 짝수 인덱스 ( 0, 2, 4, ... ) = 홀수번 문제 (1, 3, 5, ...) -> 항상 2 홀수 인덱스 ( 1, 3, 5, ... ) = 짝수번 문제 (2, 4, 6, ...) -> 1 > 3 > 4 > 5 반복 예시 30번 문제: 인덱스 29 -> ((29-1) / 2) % 4 == 2 -> odd[2] = 4 48번 문제: 인덱스 47 -> ((47-1) / 2) % 4 == 3 -> odd[3] = 5 66번 문제: 인덱스 65 -> ((65-1) / 2) % 4 == 0 -> odd[0] = 1 수포자 3 분석 3번 수포자도 조금 특이해 보이지만, 1번과 2번을 조금씩 섞은 듯한 규칙이 보인다. 3 3 | 1 1 | 2 2 | 4 4 | 5 5 | 3 3 | 1 1 | ... 2개씩 묶어서 보면 3 > 1 > 2 > 4 > 5 를 반복한다. 이 패턴을 배열 arr = [3, 1, 2, 4, 5] 로 두면, 인덱스 i 를 2로 나눈 몫( i / 2 )이 몇 번째 묶음인지를 나타내므로, answers 의 인덱스 i 번 문제에 대한 답은 arr[(i / 2) % 5] 이다. 예시 30번 문제: 인덱스 29 -> (29 / 2) % 5 == 4 -> arr[4] = 5 48번 문제: 인덱스 47 -> (47 / 2) % 5 == 3 -> arr[3] = 4 66번 문제: 인덱스 65 -> (65 / 2) % 5 == 2 -> arr[2] = 2 < 코드 > import java.util.*; class Solution { public int[] solution(int[] answers) { int a = 0, b = 0, c = 0; for (int i=0; i<answers.length; i++) { if (people1(i, answers[i])) a++; if (people2(i, answers[i])) b++; if (people3(i, answers[i])) c++; } int max = Math.max(a, Math.max(b, c)); int count = 0; if (a == max) count++; if (b == max) count++; if (c == max) count++; int[] answer = new int[count]; int index = 0; if (a == max) answer[index++] = 1; if (b == max) answer[index++] = 2; if (c == max) answer[index++] = 3; return answer; } public boolean people1(int num, int answer) { int[] arr1 = {1, 2, 3, 4, 5}; return arr1[num % arr1.length] == answer; } public boolean people2(int num, int answer) { int[] arr2 = {1, 3, 4, 5}; if (num % 2 == 0) return 2 == answer; else return arr2[((num - 1) / 2) % arr2.length] == answer; } public boolean people3(int num, int answer) { int[] arr3 = {3, 1, 2, 4, 5}; return arr3[(num / 2) % arr3.length] == answer; } } 코드 설명 people1 , people2 , people3 은 위에서 분석한 수포자 1, 2, 3의 규칙을 그대로 코드로 옮긴 함수로, 인덱스 i 번 문제에서 각 수포자의 답이 정답과 맞는지 확인한다. int max = Math.max(a, Math.max(b, c)); int count = 0; if (a == max) count++; if (b == max) count++; if (c == max) count++; int[] answer = new int[count]; int index = 0; if (a == max) answer[index++] = 1; if (b == max) answer[index++] = 2; if (c == max) answer[index++] = 3; return answer; 가장 많은 문제를 맞힌 사람의 번호를 담아 반환하는 부분이다. 세 명의 점수 중 최댓값 max 를 구한다. max 와 같은 점수를 받은 사람이 몇 명인지 세서, 그 크기만큼 배열을 만든다. 1번 → 2번 → 3번 순서로 확인하며 max 와 같은 사람의 번호를 담는다. 문제의 반환 조건을 보면 오름차순으로 정렬하라고 되어 있다. 하지만 수포자가 3명으로 고정되어 있으므로 따로 정렬할 필요 없이, 1, 2, 3번 순서대로 비교해서 담기만 하면 자연스럽게 오름차순이 된다.