_

Always be tactful

전체 글 94

최적화를 위한 고민 (스크롤 이벤트, 분기 및 순회, 병렬 처리)

스크롤 이벤트일부 로직이 로컬 스토리지를 사용하는 경우, 메인 스레드를 차단할 우려가 있어 requestIdleCallback을 통해 브라우저가 유휴 상태일 때만 실행되도록 고려하였으나, 현재 실질적으로 사용하고 있는 로직은 간단한 연산 후 DOM에 스타일만 반영하는 수준이므로 쓰로틀 + 디바운싱 구조만으로도 충분하다고 판단하였다. 오히려 requestIdleCallback을 사용하면 불필요한 지연이 발생할 수 있다. 메인 스레드를 막을 정도로 무거운 작업이 추가된다면 그때 다시 고려해야겠다. 현재로서는 성능보다 UX 측면에서 지연으로 인한 부작용이 생길 가능성이 다분하다. *Progress Bar가 실질적으로 사용자 경험 향상에 도움이 되지 않는다면, 완전 삭제도 고려하고 있다. 스크롤 이벤트 자체가 ..

[업데이트] 세이브 취소/타이틀 축약/잔여 용량 체크/기억 잔존율 시각화

일단 기능 구현부터 마치기로 했다.최적화 문제는 어차피 아무리 고민해도 끝이 없다. 막상 배포하고 나면 예상하지 못한 곳에서 새로운 이슈가 분명 터질 것이다.구현 목록1. 매뉴얼 세이브 취소 아주 작은 *이슈가 있었는데 해결했다.이제는 사용자가 직접 등록한 웹 페이지에 대해 직접 삭제할 수 있다.*HTML이 익숙하지 않아, 컨테이너 실수한 거랑 삭제 후 갱신된 정보로 새로 호출하지 않아 미적용되던 문제2. 타이틀 축약 및 툴팁 제공 타이틀이 너무 긴 웹 페이지인 경우, 타이틀을 축약해 표시하도록 패치했다.사용자가 마우스를 갖다 대면, 툴팁 형식으로 풀 타이틀이 제공된다.3. 잔여 용량 정보 확인 사용자가 현재 사용 중인 용량을 직접 알 수 있게 되었다.이를 통해 조금 더 원활한 관리가 가능할 것으로 기대..

배열 순회 문제와 팝업 진행률 이슈

현재는 savedSites 배열을 순회하며 새로 넘겨받은 url과 일치하는 사이트가 있는지, 인덱스를 통해 중복을 판단한다. 만약 중복이라면 url을 제외한 모든 요소를 갱신하고 있다. (title, lastAccessed, scroll, height) 팝업의 경우, Manual Save를 누를 때마다 진행률이 갱신된다.실제 진행률을 동적으로 반영하지 않아, 사용자가 직접 갱신해 주는 것이나 다름없다. 아쉬운 점이 몇 가지 보인다.일단 첫째, Map으로 관리했다면 어땠을까?왜 배열로 관리했을까?Map을 사용할 경우, 직렬화 이슈가 발생한다.배열은 JSON으로 자동 변환되지만, Map은 그렇지 않기 때문이다. 그럼에도 불구하고, 로직상 Map이 훨씬 깔끔하고 빠른 건 명백하다.적절한 변환 과정만 거치면 충..

WWI: Where-Was-I?

Where Was I?Where-Was-I?는 크롬을 통해 여러 웹 페이지를 오가는 사용자들을 위해 만들어졌다. 바쁜 현대 사회 속에서, 우리는 참 다양한 웹 페이지를 이용하게 되는데,여기서 문제는, 자주, 혹은 가끔이라도 재방문해야 하는 경우가 존재한다는 것이다.북마크는 WWI를 대체할 수 없다.크롬에서는 자주 이용하는 웹 페이지를 북마크로 관리할 수 있다.그렇다면 Where-Was-I?는 왜 필요한 걸까? 답은 간단하다.북마크는 Where-Was-I?를 대체할 수 없다.1. 북마크의 관리 범위는 상당히 제한적이다.웹 페이지를 북마크에 직접 등록해야 하는 수고스러움이 있다.나는 이것에 대해 사용자 의존도 문제라고 부른다.사용자가 북마크 하는 것을 깜빡할 수 있다.사용자는 북마크 대상을 명확히 구분할 능..

깃 히스토리와 짧은 회고

체리픽 결과이전 커밋 메시지 이슈로 git rebase 하다 보니, 중복된 커밋들이 있다.기능별 브랜치 히스토리를 남기기 위해, develop 브랜치를 다시 분기해 체리픽 하고 push 했다.Merge pull request #2 커밋에서 분기해 feature/* 작업했더라면 깔끔했겠지만, 대신 체리픽이 불가능하다.일관된 커밋 메시지를 작성하고자 한 git rebase, 기능별 브랜치 히스토리를 추적할 수 있도록 다시 분기해 git cherry-pick 한 것이 오히려 히스토리를 난잡하게 만든 감이 없지 않아 있다.깃 히스토리많은 생각이 들었다. 고작 대소문자 구분을 위해 강박적으로 수정한 것과 히스토리에 집착해 이미 했던 작업을 다시 분기해 체리픽 하는 과정에서 너무 많은 시간을 투자하였고, 결과적으로..

실수를 통해 성장하는 개발자가 되자 (rebase? cherry-pick?)

커밋 메시지 실수어제 오랜 시간 작업하다 보니, 커밋 메시지를 일관되게 작성하지 못 했다.문제의 커밋은 아래 이미지를 통해 볼 수 있다.커밋에 있어서 정말 신경 써서 남기고 있었는데, 한 커밋에서 대문자로 시작한 걸 미처 인지하지 못 한 채 병합까지 해버렸다. 슬픈 사실은 이미 PR 날리고 병합까지 하고 나서야 이 사실을 알게 되었다는 것이다. 사실, 이미 push 한 상태에서 해당 커밋을 수정한다는 게 얼마나 위험한 일인지는 알고 있다. 그리고 본 프로젝트를 시작할 때 다짐했던 것이 개인 프로젝트지만 협업처럼 작업하자는 것이었기 때문에, 모순되는 행동일 수도 있지만 수정하고 싶은 욕구를 이겨내지 못 하고, 마침내 일을 저지르게 되었다.git rebase -i HEAD~10물론 아무 생각 없이 시도한 것..

Vite 기반 번들링 환경 구축과 타입 안정성을 위한 TS 마이그레이션

번들링 환경 구축Vite를 사용할 예정인데, 그러려면 일단 Node.js부터 설치해야 한다.*Node.js가 설치되어 있는지는 터미널에서 node -v로 간단하게 확인 가능하다.공식 사이트에서 LTS 버전 다운로드하고 설치하면 된다.참고로, 설치 과정에서 npm도 같이 깔리니 따로 설치할 필요는 없다.설치가 끝나면 node -v, npm -v 찍어서 확인하자.아마 높은 확률로 이렇게 뜰 텐데, PowerShell 보안 정책상 npm 실행이 차단된 상태라고 볼 수 있다.Windows PowerShell은 .ps1 스크립트 실행을 막아서 실수나 악성 코드 실행을 방지하려고 한다. npm.ps1도 일종의 스크립트이기 때문에, 기본 정책인 Restricted에서는 사용할 수 없다. 관리자 권한으로 실행해 다음 ..

개인 프로젝트지만 협업처럼 행동하자 (git flow, inject issue?)

들어가며항상 들려오는 말이 있다."아무리 능력이 뛰어난 사람이라도 같이 일하기 어려운 상대는 기피하게 된다." 개발에서 말하는 협업은 단순히 사람 대 사람으로서 말이 잘 통하느냐를 의미하지 않는다.개인 프로젝트지만, 마치 협업인 것처럼 행동하자.깃 브랜치란 무엇이며, 왜 있는 걸까?커밋은 어떻게 하는 게 좋을까?브랜치 관례와 커밋 관례를 찾아보며, 이번 프로젝트에서 최대한 적용해보려 한다.리포지토리아래 깃허브 링크를 남겨두겠다.기획부터 개발, 배포, 마케팅까지 고독하지만 재미있는 기록이 될 것이다. GitHub - funczun/where-was-iContribute to funczun/where-was-i development by creating an account on GitHub.github.co..

불편함이 나를 개발로 이끌었다

개발 동기경영학부 학생인 나는 개발자를 꿈꾸며 멋쟁이사자처럼이라는 동아리에 가입하게 되었다. 감사하게도, 우리 동아리 운영진은 유용한 아티클을 종종 공유해 주곤 한다. 문제는 나에게 있다. 공유받은 아티클을 그때그때 읽으려 노력하지만, 개수가 많고 분량도 적지 않아 한번에 소화하기 어려웠다. 웹사이트 자체가 유용하다 싶으면 북마크 해두고, 그게 아니라면 해당 링크만 카톡방에 저장해 두었다가 다시 보는 편인데, 이 부분에서 적지 않은 피로감을 느꼈다. 크게 불편하지는 않지만 개선시키면 좋을 것 같다는 생각이다.문제 상황1. 마지막으로 읽었던 지점을 찾아야 한다.아티클을 읽다가 중단하고 나중에 다시 읽으려 할 때, 마지막 위치를 기억해 찾아야 하는 번거로움이 있다.2. 읽고 있던 아티클을 깜빡 잊는 문제가 ..

RESTful API에서 '응답 설계'가 반이라고?

ResponseEntity응답 설계 핵심 도구우리는 ResponseEntity에 대해 왜 알아야 할까?이유는 간단하다.스프링 프레임워크에서 HTTP 응답을 정교하게 제어하기 위한 핵심 도구이기 때문이다.단순한 "값 반환"이 아니라, HTTP 상태 코드, 헤터, 본문까지 직접 다룰 수 있다. 1. RESTful API에서 '응답 설계'는 감히 절반이라 할 수 있다.REST는 HTTP 자체를 프로토콜로 삼는다.응답에 상태 코드, 헤더, 본문을 정밀하게 제어해야 하며, 이걸 직접 제어하는 대표적인 도구가 ResponseEntity다.return ResponseEntity.status(HttpStatus.NOT_FOUND).body("User not found");→ 단순한 return "User not fou..

비즈니스 로직이니까 서비스에 있어야지!

비즈니스 로직, 무조건 서비스에 두어야 할까?도메인 주도 설계(DDD)를 공부하다 보면 흔히 맞닥뜨리는 질문이 있다."비즈니스 로직이면 원래 서비스 레이어에 두는 거 아닌가?" 이 질문은 언뜻 맞는 말처럼 들리지만, 사실 절반만 맞는 말이다. 이 글에서는 비즈니스 로직의 위치에 대해 하나씩 짚어보며, 헷갈릴 수 있는 지점들을 정리해본다.서비스에 로직을 두는 게 맞는 경우다음과 같은 경우에는 비즈니스 로직을 서비스 레이어에 두는 것이 자연스럽다.여러 도메인 객체 간의 상호작용이 필요한 경우외부 시스템과의 연동이 포함되는 경우 (예: 메일 전송, 결제 API 호출 등)도메인 객체 내부에 두기엔 과도하거나 부적절한 경우예를 들어, "예약을 저장하고, 알림도 보내고, 결제도 트리거하는 흐름"이라면 이는 하나의 ..

DDD에서는 private을 안 쓴다면서?

DDD에서는 private을 지양한다?객체지향에서는 정보를 감추라고 하는데, 도메인 주도 설계에서는 왜 자꾸 public을 강조할까? 들어가며객체지향에서는 이렇게 배운다."메서드와 필드는 최대한 감춰라.""캡슐화를 통해 객체의 내부 구현을 보호해야 한다."그런데 도메인 주도 설계(DDD)를 공부하다 보면 이렇게 말한다.“비즈니스 규칙은 숨기지 말고, 드러내라.” 그럼 결국, private 쓰지 말라는 건가?헷갈릴 수밖에 없다.도메인 개념은 감추지 말고 드러내야 한다스케줄을 체크하는 것은 꽤 중요한 도메인 개념이다.👉 그래서 다음과 같은 메서드를 외부에 열어주는 게 좋다.public boolean isSchedulable(LocalDateTime start, LocalDateTime end) { r..

[메모] 도메인 로직과 비즈니스 로직

도메인 로직(Domain Logic)도메인의 규칙과 행위 자체를 다루는 로직비즈니스의 본질적인 규칙들 (예: "환자가 같은 시간에 두 번 예약할 수 없다", "의사는 하루에 최대 20명만 진료 가능하다")Entity나 Value Object 안에 담기는 게 일반적변화 가능성은 낮고, 오히려 잘 구조화하면 유지보수성이 높아짐 비즈니스/애플리케이션 로직(Application Logic)요청 흐름을 제어하거나 유즈케이스 단위로 처리하는 로직예: "예약 요청을 받아서, 예약 가능한지 확인하고, 저장하고, 결과를 반환한다"보통 Service 계층에서 구현도메인 로직을 조합하고 orchestration 함도메인 모델은 이 시스템이 어떤 규칙을 가지는지 에 집중하고,애플리케이션 계층은 그 규칙을 언제, 어떻게 실행할..

[메모] DTO와 record

record란 무엇인가? record는 자바 14부터 도입된 클래스의 일종이다. 따라서 내부적으로도 final class로 컴파일된다.즉, record는 불변 객체를 간편하게 만들기 위한 클래스의 축약 문법인 것이다!record 선언을 통해 자동 생성되는 것들은 다음과 같다.- 모든 필드 private final 선언- 생성자- Getter (필드명과 동일한 이름의 메서드)- equals() / hashCode()- toString()요즘엔 DTO를 record로 선언한다. 사실 DTO는 필드를 외부에 노출하고, 읽기만 하는 경우가 많다.그래서 불변성 + 간결함을 모두 가진 record랑 찰떡궁합이라고 볼 수 있다!DTO 클래스 이름 짓기는 어떻게? 이름 짓기라는 게 사실 스타일 차이라서 어떤 게 맞다고..

[🦁3] OOP와 객체지향 설계체조

시청할 것우아한객체지향이번 주 키워드 정리상속(Inheritance) vs 조합(Composition)1. 상속(Inheritance)부모 클래스의 속성과 메서드를 자식 클래스가 물려받는 방식코드 재사용성이 높지만, 부모 클래스에 종속되어 강한 결합(High Coupling) 발생부모 클래스가 변경되면 자식 클래스에도 영향을 미쳐 유지보수가 어려워질 수 있음2. 조합(Composition)기존 클래스를 포함(Has-A 관계)하여 기능을 재사용하는 방식강한 결합을 피할 수 있어 유지보수가 용이하고 유연성이 높음상속보다 유연하며, 런타임 시 객체를 변경할 수도 있음🚀 언제 사용해야 할까?상속: 명확한 "is-a" 관계(예: Car is a Vehicle)조합: 유연한 "has-a" 관계(예: Car has..

무분별한 Getter & Setter 사용은 OOP 원칙을 위배한다.

들어가기에 앞서, 우리는 Getter와 Setter에 대해 학습했다. OOP 원칙 중 캡슐화에 대해 인지하였고, 따라서 Setter 사용을 지양해야 한다는 것 정도는 이미 알고 있는 사실이다. 그렇다면 왜 Getter 사용도 지양해야 하는 걸까?또는, Setter를 지양해야 하는 명확한 이유는 뭘까?Getter와 Setter의 탄생 객체 지향은 정보 은닉에서 시작한다.객체 지향 언어의 장점은 물론 다양하겠지만, 가장 큰 장점 중 하나가 유연성이다. 이러한 설계 방식은 변화하는 요구사항에 쉽게 대응할 수 있도록 한다. 유연성을 가능하게 하는 요소는 무엇일까?바로, 1. 캡슐화 2. 상속 3. 다형성이다. 그중 캡슐화, 이하 정보 은닉은 내부 구현을 숨기고 필요한 부분만 외부에 공개하도록 한다. 외부 코드가..