블로그

징니

인프런 워밍업 클럽 3기 BE 스터디 4주차

💻 강의입문자를 위한 Spring Boot with Kotlin - 나만의 포트폴리오 사이트 만들기 📚 학습@Transactional(readOnly = true)읽기 전용 트랜잭션으로 설정하면 데이터 변경이 일어나지 않기 때문에 스냅샷을 저장하는 동작을 생략해 좀 더 성능을 개선할 수 있다readOnly 참고Service 테스트@ExtendWith : 테스트 확장을 지원하며 JUniit5와 Mockito를 연동해 테스트를 진행할 경우에는 MockitoExtension.class를 사용@InjectMocks : Mockito에서 테스트 대상이 되는 클래스에 인스턴스를 주입하기 위해 사용@Mock : Mockito에서 Mock 객체를 생성할 때 사용하며 실제로 메서드는 갖고 있지만 내부 구현이 없는 상태참고 Repository 테스트를 했을 때와는 다르게 Service 테스트를 할 때는 Mockito를 사용한다@ExtendWith(MockitoExtension::class) class PresentationServiceTest { @InjectMocks lateinit var presentationService: PresentationService @Mock lateinit var presentationRepository: PresentationRepository }Service 테스트 코드 해석given일단 홀수이면 isActive = false, 짝수이면 true로 설정한다필터링을 해 isActive = true인 것만 남긴다presentationRepository.getActiveIntroductions()를 실행하면 필터링 한 데이터를 반환하도록 한다["2", "4", "6"]when테스트 대상 메서드를 실행한다thenDATA_SIZE = 7이므로 DATA_SIZE / 2 = 3.5이지만 정수 연산에서는 3이 반환 된다필터링 한 데이터 수가 일치하면 첫 번째 검증은 통과이다content 값을 정수로 변환하고, isEven()을 사용해 짝수인지 검증한다짝수이면 두 번째 검증도 통과이다@Repository class PresentationRepository( ...) { ... fun getActiveIntroductions(): List<Introduction> { return introductionRepository.findAllByIsActive(true) }... @Test fun testGetIntroductions() { // given val introductions = mutableListOf<Introduction>() for (i in 1..DATA_SIZE) { // 1, 3, 5, 7 -> false / 2, 4, 6 -> true val introduction = Introduction(content = "${i}", isActive = i % 2 == 0) introductions.add(introduction) } val activeIntroductions = introductions.filter { introduction -> introduction.isActive } Mockito.`when`(presentationRepository.getActiveIntroductions()) .thenReturn(activeIntroductions) // when val introductionDTOs = presentationService.getIntroductions() // then assertThat(introductionDTOs).hasSize(DATA_SIZE / 2) for (introductionDTO in introductionDTOs) { assertThat(introductionDTO.content.toInt()).isEven() } } Controller 테스트@SpringBootTest : 실제 애플리케이션과 유사한 환경을 구성하여 테스트 가능@AutoConfigureMockMVC : Spring MVC를 모의로 테스트하는 데 사용@SpringBootTest @AutoConfigureMockMvc @DisplayName("[API 컨트롤러 테스트]") class PresentationApiControllerTest(@Autowired private val mockMvc: MockMvc) { }Thymeleaf 문법th:fragment : 템플릿의 일부를 재사용 가능한 fragment로 정의th:replace : 해당 요소를 다른 요소로 대체할 때 사용 fragment 이름을 navigation으로 지정하고, 해당 경로에 있는 파일의 navigation fragment를 찾아서 대체한다// /templates/presentation/fragments/fragment-navigation.html <nav class="navbar navbar-expand-lg navbar-light bg-white py-3" th:fragment="navigation">// /templates/presentation/index.html <div th:replace="~{presentation/fragments/fragment-navigation :: navigation}"></div>  🎯 미션 6과 미션 7가상 프로필을 나의 프로필로 바꾸기강의 실습 프로젝트의 데이터 초기화 클래스 내용을 나의 프로필로 바꾼 뒤 커밋커밋 메시지 : [미션6] 가상 프로필을 나의 프로필로 바꾸기미션6 제출 스레드에 깃허브 커밋 링크를 공유프로젝트를 배포한 뒤 브라우저에서 접속미션7 제출 스레드에 도메인 주소를 공유문제이미지 태그를 지정하고 Dockerfile을 Build 하는 과정에서 test 실패 오류가 발생하였다테스트 코드가 문제인 건지 확인하기 위해 TestApplication을 실행해 전체 테스트 코드를 실행시키니 오류는 없었다원인을 찾을 수 없어서 계속 구글링을 해보니 아래 코드가 원인이 될 수도 있다고 한다tasks.withType<Test> { useJUnitPlatform() }해결아래 코드를 주석 처리하니 정상적으로 Build가 됐다tasks.withType<Test> { useJUnitPlatform() }참고

백엔드

클라우드 기반 스마트팩토리 - 이슈들

이 글은 제가 NIA [한국지능정보사회진흥원]의 < 디지털서비스 이슈리포트 > 2025년 3월호에 기고한 글입니다. 원본 글 '2025년 AI 현황 보고서 리뷰'를 이곳 브런치에서도 공유합니다.들어가며지난 두 편의 클라우드 기반 스마트팩토리에 대한 소개에 이어 이번 회에서는 현장에서 실제로 부딪히는 문제들을 정보통신의 관점에서 몇몇 사례를 들어 이야기 해 보겠다. 아래 내용들은 필자가 함께 하는 인이지를 비롯한 여러 회사들이 제조 공정 관련한 과제들을 수행하면서 만난 문제들과 이들을 해결하려는 방법들에 대한 내용들이다. 제조 산업에서도 스마트팩토리라는 키워드를 중심으로 여러 혁신의 노력들이 모이고 있고, 클라우드를 이용한 기술은 효율성과 유연성을 극대화하는 데 중요한 역할을 하며, 정보통신 업계에서의 노하우들을 다양하게 적용하면서 그 영향력을 넓혀 가고 있다. 특히 클라우드를 이용한 방법을 통해서는 다음과 같은 이득을 기대할 수 있다.  데이터 기반 의사 결정  유연성과 확장성  비용 효율성  디지털 전환(DX)의 가속화  이는 일반적으로 쓰이는 의미의 IT 시스템 도입과 이전으로 인한 이득과 같은 맥락이지만, 스마트팩토리는 현장의 물리적인 변화와 공정의 특성들을 고려할 때 단순한 IT 시스템 이전과는 다른 추가적인 복잡한 문제들이 발생한다.   물리적 한계와 엔트로피 문제  실시간 운영과 신뢰성 문제  데이터 관리의 어려움  디지털 전환과 문제 해결 가능성   이번 회에서는 이 추가적인 내용들에 대해 조금 더 구체적으로 살펴보겠다. 물리적 한계와 엔트로피 문제기존의 데이터센터 중심의 IT 환경과는 달리, 스마트팩토리는 물리적 환경과 밀접하게 연결되어 있으며, 다양한 기계적 요소와 데이터가 실시간으로 상호작용하는데, 이는 예상치 못한 물리적 한계와 엔트로피 문제를 야기할 수 있다.스마트팩토리는 제조 현장의 특성 상 생산 라인의 변화, 기계 설비의 교체, 센서 추가 등 물리적 변화가 빈번하게 발생한다. 이러한 변화는 데이터 흐름과 시스템 아키텍처에 직접적인 영향을 미치며, 클라우드 환경과의 통합을 복잡하게 만든다. 예를 들어, 새로운 센서를 추가할 때마다 데이터 수집 및 처리 시스템을 재설정해야 하고, 생산 라인 변경 시 데이터 분석 모델을 수정해야 하는 등. 이러한 물리적 변화에 유연하게 대응하지 못하면 시스템의 효율성이 저하되고 운영 비용이 증가할 수 있다.또한 스마트팩토리는 다양한 기계와 센서, IT 시스템이 복잡하게 연결된 시스템이다. 전선으로 연결되어 빛의 속도로 연결되는 환경이 아니라 어느 곳에서 어떤 연료를 투입하면, 몇미터 떨어진 곳의 온도가 몇 분 후에 어떻게 변하는 등의 주변의 상황들이 통제되지 않는 상황이 생기고, 대기의 온도, 습도 등에 따라 예기치 않은 변화들이 생기기도 한다. 시간이 지남에 따라 장치가 마모되거나 유지보수의 부담이 늘어나는 등 열역학 제2법칙인 엔트로피 증가의 법칙과 유사한 현상이 일어나게 되는데, 이로 인해 시스템의 안정성이 저하되고 오류 발생 가능성이 높아지며, 이는 생산 효율성 저하와 직결된다.실제로 디지털 전환을 도입하려는 많은 제조 현장의 경우 온도와 습도 등의 환경이 많은 영향을 미치기 때문에, 온프레미스 시스템을 구성하기 위해서도 오차 없이 사용 가능한 장비들의 사용이 필요하고, 여기에 특히 클라우드 환경을 도입할 경우, 온프레미스 시스템과의 연동, 데이터 동기화, 네트워크 안정성 등 추가적인 유지보수 요소가 발생하는데, 클라우드 도입의 이점을 제대로 누리기 위해 이들로 인한 복잡성을 효과적으로 관리해야 한다. 이후 데이터가 모여서 분석을 하는 경우, 도면이나 공정 같은 현장의 지식이 없이 센서 데이터만으로는 분석의 한계가 생긴다. 시멘트나 철강 등의 공정을 생각한다면 물리적으로 수십 미터 떨어져 있는 데이터들이며, 센서들 사이에 어떤 간섭이 있는지, 바람은 잘 통하는지, 하루에 몇 번씩 청소를 하는지 등의 내용들이 고려되어야 현장의 문제에 접근할 수 있게 된다. 마찬가지로 용해로 시계열 온도 예측 같은 경우, 900도 온도를 맞추기 위해서 850도인 현재 상황에서 용해물질에 어떤 재료를 얼마만큼 넣으면 몇 분 후에 온도가 올라가는지 등 데이터로 모아 놓기에 어려움이 많고, 산업공학, 기계공학, 화학공학 등의 정보들이 도메인 지식들을 익힌 후에 더 나은 분석을 할 수 있는 경우가 많다.  실시간 운영과 신뢰성 문제스마트팩토리는 고도의 자동화와 데이터 기반 운영을 통해 생산성을 극대화하는 것을 목표로 하는데, 이러한 목표를 달성하기 위해서는 실시간 운영과 시스템의 높은 신뢰성이 필수적이다. 하지만 스마트팩토리 환경은 다양한 변수와 복잡성으로 인해 실시간 운영과 신뢰성을 확보하는 데 어려움을 겪을 수 있다.스마트팩토리는 24시간, 365일 가동되는 경우가 많은데, 이는 생산 효율성을 극대화하고 시장 수요에 신속하게 대응하기 위한 필수적인 조건이다. 따라서 예기치 않은 시스템 다운타임은 생산 차질, 납기 지연, 고객 신뢰도 하락 등 심각한 문제를 야기할 수 있다. 특히, 실시간 데이터 처리와 제어가 중요한 생산 라인에서는 단 몇 분의 다운타임도 재가동하는 비용을 포함한 큰 손실로 이어질 수 있다. 따라서 스마트팩토리는 시스템의 안정성을 최우선으로 고려해야 하며, 다운타임 발생 시 신속하게 복구할 수 있는 체계를 구축해야 한다. 예를 들면 용해로 재시작 재가동 등의 일들은 일반 컴퓨터 재부팅보다 훨씬 더 준비해야 할 게 많으므로 이런 점이 고려가 되어야 한다. 또한 시스템의 신뢰성을 높이기 위해서는 이중화 시스템 구축이 필수적이고, 환경에 따라서 데이터 백업, 네트워크 이중화, 서버 이중화 등 다양한 방법을 통해 시스템 장애에 대비해야 한다. 자원들이 유기적으로 연결되어 있는 클라우드 환경에서는 상대적으로 이중화 혹은 다중화 지원이 용이하지만, 온프레미스 환경에서는 이를 지원하기 위해 네트워크 장비나 실제 서버들의 추가적인 설치와 운영이 필요하다. 온프레미스에 저장되어 있는 데이터를 클라우드에 저장하고 운영하는 것은 추가적인 네트워크 연결을 도입하는 것이기에 이로 인한 위험도 있게 되므로, 실시간 데이터 처리 및 중요 데이터는 온프레미스에 저장하고, 분석 및 장기 데이터는 클라우드에 저장하는 하이브리드 모델을 많이 고려한다.  이러한 하이브리드 모델은 데이터 처리 속도와 안정성을 동시에 확보할 수 있으며, 엣지 컴퓨팅을 활용하여 실시간성이 요구되는 데이터의 경우 추가적인 데이터 이동을 절약함으로써 현장에서 필요한 데이터 처리 속도를 향상시킬 수 있다. 그림 1. 고가용 시스템 네트워크 구조 예제스마트팩토리는 수많은 스마트 센서를 통해 데이터를 수집하고 분석하는데, 클라우드 기반 스마트 센서는 네트워크 연결이 필수적이므로, 안정적인 네트워크 환경을 구축해야 한다. 주변의 환경에 영향을 받기에 유무선 네트워크 장애는 센서 데이터 수집 및 전송에 문제를 일으킬 수 있고, 스마트 센서는 민감한 생산 데이터를 수집하므로, 데이터 보안을 강화해야 한다. 각각의 센서 혹은 시스템이 노출되는 형태이므로 데이터 암호화, 접근 제어, 보안 프로토콜 적용 등을 통해 데이터 유출 및 해킹을 방지해야 하고, 마지막으로 수많은 스마트 센서를 효율적으로 관리하고 유지보수해야 하는데, 원격 관리, 자동 업데이트, 센서 상태 모니터링 시스템 등을 통해 센서 관리 효율성을 높여야 한다. 데이터 관리의 어려움: 저장과 조회의 균형스마트팩토리는 생산 과정에서 발생하는 방대한 양의 데이터를 효율적으로 관리하는 것이 핵심이다. 현장에서 일어나는 모든 데이터가 관리 대상이기에 데이터의 양이 기하급수적으로 증가함에 따라 저장과 조회에 대한 어려움이 발생하고, 효율적인 데이터 관리 전략이 필수적이다.스마트팩토리에서 생성되는 데이터는 실시간 데이터와 장기 분석용 데이터로 나눌 수 있다. 실시간 데이터는 생산 라인 제어, 품질 검사 등 즉각적인 응답이 필요한 데이터이며, 온프레미스에 저장하는 것이 유리한 반면, 장기 분석용 데이터는 생산 공정 최적화, 설비 예지 보전 등에 활용되며, 클라우드 스토리지를 활용하는 것이 좋다. 클라우드는 이 확장성에 대해 확실한 강점이 있어, 이후 효율적으로 저장하고 처리할 수 있다. 전사적 자원관리(ERP: Enterprise Resource Planning)의 내용과 같이 현장 바깥의 정보들과 같이 사용하는 경우 훨씬 유용하게 쓰일 수 있다.스마트팩토리에서 생성되는 데이터는 많게는 초당 수백, 수천 건의 고화질 대용량 데이터들이 이용되기도 하는데, 이를 다루기 위해서 데이터 처리 성능이 중요하다. 데이터를 모으는 시스템과 읽는 시스템이 자원을 공유하기에 그 사이에서 오는 문제가 생기기도 한다. 실제 조회가 필요할 경우 제대로 운영하기 위해 알맞은 데이터베이스를 선택하고, 인덱스 설정, 쿼리 최적화 등을 통해 대응해야 하는데, 데이터를 이동시키는 데 드는 자원이 원래 시스템을 운영하는 데 방해가 되지 않아야 하고, 본래 시스템이 주어진 역할에 지장이 없도록 운영해야 한다.데이터 양이 증가함에 따라 저장 비용이 기하급수적으로 증가할 수 있다. 예를 들어 이미지를 통한 불량 탐지의 경우 불량률이 적어질 수록 중복된 정상 이미지들이 불필요하게 쌓이는 상황이 생기기도 하고, 모든 것들을 저장해야 한다고 하면 데이터 백업 등에도 추가적인 노력과 비용을 들여야 한다. 대용량 데이터를 실시간으로 처리하는 것은 클라우드 환경에서도 기술적으로 어려운데, 온프레미스에서도 분산 처리 시스템, 인메모리 데이터베이스, 엣지 컴퓨팅 등 다양한 방법들을 도입해야 한다.이처럼 스마트팩토리의 데이터 관리는 저장 위치 결정, 읽기/쓰기 성능 최적화, 저장 비용 및 처리 성능 한계 극복 등 다양한 어려움을 내포하는데, 이러한 문제를 해결하기 위해 먼저 현장을 이해한 후에 데이터의 특성과 사용 목적에 맞는 데이터 관리 전략을 수립하고, 최신 기술을 적극적으로 활용해야 한다. 디지털 전환과 문제 해결 가능성디지털 전환은 스마트팩토리의 생산성과 효율성을 향상시키기 위한 핵심 전략으로, 클라우드는 디지털 전환의 중요한 요소로 작용하며, 데이터를 중앙에서 실시간으로 분석할 수 있도록 지원한다. 이를 통해 공정 최적화와 이상 탐지가 가능하며, 공장 운영의 자동화를 가속화할 수 있다. 다양한 장점에도 불구하고, 현장의 문제를 풀어 낼 수 있는가 라는 문제에 많은 고민들이 있다.온도를 재는 아날로그 센서의 경우 고온고압의 환경을 센서가 버티지 못하는 경우도 있고, 최근의 화두인 탄소 수치의 경우 가상의 새로운 장치들이 필요하다. 제품의 완성도는 화면으로 100% 잡히지 않는 경우도 많고, 농도는 샘플링에 의존할 수밖에 없고, 물성은 완제품으로부터만 얻을 수 있는 경우가 대부분이다. 각각의 사례들이 데이터로 디지털화 되었다고 해도 세상의 물리와 화학은 이진 수학으로 떨어지지 않는 부분도 많고, 통계와 예측은 신뢰구간과의 끊임없는 싸움이다.앞의 여러 이슈들을 겪은 후 데이터가 모인 후에는, 실제 문제를 정의하고 풀어 나가는 마지막 단계에 오게 되고, 이 경우 인력 문제로 귀결이 된다. 이미 제조 현장은 소수의 인원이 오랜 세월의 노하우로 운영을 하고 있고, 그 문제를 데이터로 풀려 하는 인력들과 거리가 있어 많은 현장에서 디지털 전환을 했음에도 실질적인 이득을 얻기 힘들다는 현실과 닿아 있다. 이 거리가 좁혀진 후에는 시계열 예측 혹은 설명 가능 인공지능 등이 추가적인 가치를 창출해 낼 수 있겠으며, 필자가 속한 인이지를 비롯해 많은 인공지능 관련 업체들이 기존의 제조산업 업체들과 문제를 정의하고 풀어 나가고 있다.그림 2. 인이지의 산업용 공정 효율 최적화 솔루션 예제 맺으며클라우드 기반 스마트팩토리는 분명 제조업의 혁신을 가속화하고 생산성을 극대화할 수 있는 강력한 도구이지만, 앞서 살펴본 바와 같이, 물리적 한계, 실시간 운영의 신뢰성, 데이터 관리의 어려움 등 해결해야 할 과제들이 산적해 있다. 이러한 문제들을 극복하기 위해서는 단순히 기술을 도입하는 것을 넘어, 현장의 특성을 깊이 이해하고, 데이터 기반의 의사 결정을 통해 지속적인 개선을 추구하는 노력이 필요하다.또한, 스마트팩토리를 포함한 디지털 전환은 기술적인 변화뿐만 아니라, 조직 문화와 인력의 변화를 수반한다. 현장의 경험과 지식을 데이터 분석 및 활용 능력과 결합하여 시너지를 창출하는 것이 중요하겠으며, 클라우드 기반 스마트팩토리가 진정한 가치를 발휘하기 위해서는 기술, 사람, 그리고 조직의 조화로운 발전이 필수적이라 하겠고, 이 요소들이 다 고려되었을 때 비로소 디지털 전환이 되었다 할 수 있겠다.

대학 교육 기타

rjf1138

[인프런 워밍업 클럽 3기] BE 클린코드&테스트 - 4주차 발자국

💡 강의 핵심 내용 정리💻Practical Testing🔹 1. 왜 Mocking이 필요한가?외부 시스템(메일 전송, 결제, 알림 등)을 호출하는 코드는 실제 실행하면 부작용이 발생할 수 있음.테스트 시 외부 의존성을 제거하고 예측 가능한 결과를 주기 위해 Mock 객체를 사용함.이 과정을 Stubbing이라 하며, 원하는 동작을 가짜 객체에게 명시함.Mockito.when(mailSendClient.sendEmail(...)).thenReturn(true); 🔹 2. Mail 전송은 @Transactional을 붙이면 안 되는 이유메일 전송은 외부 네트워크 요청이며, 트랜잭션 범위 안에서 실행되면 DB Connection을 오래 점유하게 됨.이런 긴 작업은 트랜잭션 바깥에서 실행되어야 함.🔹 3. Test Double의 종류유형 설명 Dummy 사용되지 않는, 껍데기 객체 Fake 간단한 구현을 가진 실제 객체 (Map 기반 Repository 등) Stub 미리 정의된 응답을 제공하는 객체 (상태 검증용) Spy 일부는 실제처럼, 일부는 Stub. 호출 기록 추적 가능 Mock 행위 기반 검증용 객체 (몇 번 호출되었는지 등 검증)💡 Stub은 상태 검증, Mock은 행위 검증에 사용됨.🔹 4. 순수 Mockito 사용법@Mock, @InjectMocks, @ExtendWith(MockitoExtension.class) 조합으로 Spring Context 없이도 테스트 가능@Spy: 실제 객체 기반으로 필요한 부분만 StubbingdoReturn(true).when(mailSendClient).sendEmail(...); 🔹 5. BDDMockitowhen(...).thenReturn(...) 대신 Given-When-Then 스타일을 지향BDDMockito.given(mailSendClient.sendEmail(...)).willReturn(true); 테스트의 목적과 구조가 명확하고 선언적으로 표현됨.🔹 6. Classicist vs Mockist구분 Classicist Mockist 테스트 단위 실제 객체로 통합 테스트 협력 객체는 모두 Mock 강조점 시스템 동작 검증 객체 간 상호작용 검증 사용 시점 DB, HTTP 연동 등 진짜 동작 필요할 때 외부 의존이 많거나, 로직 복잡도 높은 객체✅ 일반적으로는 Classicist 접근을 사용하고, 외부 시스템 등 불가피한 경우에만 Mocking을 하자!🔹 7. 테스트 코드 개선 전략 요약📌 한 문단에는 한 주제테스트는 명확하게 하나의 동작만 검증해야 함.if, for 등의 분기/반복문이 테스트 코드에 들어가면 테스트 목적이 흐려짐.📌 제어 가능한 값만 사용하라현재 시간, UUID, 랜덤, 환경 변수 등은 직접 주입하거나 인터페이스로 추출하여 테스트 가능하게 설계.📌 테스트 간 독립성 보장static 공유 객체 금지 (@BeforeAll/@BeforeEach도 주의)fixture는 되도록 각 테스트 내에서 명시적으로 구성📌 Test Fixture는 생성자 기반 / Builder 활용팩토리 메서드 대신 Builder 패턴 선호data.sql로 데이터 주입 지양 → 테스트 목적 파악 어려움📌@ParameterizedTest, @DynamicTest 적극 활용경계값, 다양한 조건 검증이 필요한 경우 유용@DynamicTest는 상태 변화 시나리오 테스트에 특히 적합📌 공통 테스트 환경 통합@SpringBootTest를 반복 호출하지 않도록 상위 추상 클래스로 환경을 공통화@SpringBootTest @ActiveProfiles("test") public abstract class IntegrationTestSupport {} 📌 private 메서드는 테스트하지 말자테스트가 필요할 정도로 복잡해졌다면, 새로운 객체로 추출해서 테스트 가능하도록 리팩토링.

Yang HyeonBin

[인프런 워밍업 클럽 3기] 풀스택 과정 4주차 발자국 👣

이번 주차에는 SupabaseAuth, Realtime, RLS를 사용해봤고, Next.js 팀에서 만든 배포 플랫폼인 Versel을 이용해 지금까지의 작업물을 배포해보았다!  먼저 Auth를 살펴보자.1. 회원가입무료 Supabase 프로젝트는 이메일 인증 기본 제공량이 1시간에 3통⇒ SMTP 서버 직접 세팅하면 무제한 전송 가능1. Confirmation URL 방식 - 메일의 인증 링크 클릭, 리다이렉트supabase.auth의 signUp, exchangeCodeForSession, getSession을 이용 signUp 함수 options에 emailRedirectTo 값으로 exchangeCodeForSession을 실행할 페이지의 경로를 넘겨줌 경로 속 route.tsx 파일에서 exchangeCodeForSession 실행, redirect url의 code search param 값 이용해 세션을 얻어 로그인 처리 후, NextReseponse.redirect 이용해 기본 주소로 리다이렉트 처리 기본 주소에서 getSession 이용해 로그인 여부 확인, 상태에 맞는 화면(기본 화면 / 로그인(회원가입) 화면 중 하나) 보여주게 처리메일 인증 링크 형식https://{뭔가고유한문자열}.supabase.co/auth/v1/verify?token={tokenHash}&type=signup&redirect_to={리다이렉트url}절차메일의 ‘인증’ 버튼 클릭 시 위 링크로 이동하는데, 인증을 마친 뒤 {리다이렉트url}로 이동, code라는 searchParam과 함께 리다이렉트함Web client에서 code searchParam 값을 이용해 로그인 세션 획득, supabase.auth.exchangeCodeForSession 함수 이용해 로그인 처리supabase.auth.signUp 함수에 options 값으로 넘긴 redirectUrl 경로에서 열릴 파일을 정의 options: { emailRedirectTo: "<http://localhost:3000/signup/confirm>", // 인증 완료 후 리다이렉트 url }, 위 경로의 경우, app/signup/confirm/route.tsx에 정의하면 됨url과 일치하도록 폴더와 route.tsx 파일을 생성Next.js 14 이상부터 사용되는 개념API 정의 및 GET, POST, UPDATE 요청 등을 관장해당 url에 접속했을 때, 이 파일에 작성된 작업을 수행ex. GET을 정의 → GET 오퍼레이션을 날림// app/signup/confirm/route.tsx import { NextResponse } from "next/server"; import { createServerSupabaseClient } from "utils/supabase/server"; export async function GET(request: Request) { const requestUrl = new URL(request.url); // 이메일 인증 완료 후 redirect url에 'code' search param이 포함되어 돌아오게 됨 const code = requestUrl.searchParams.get("code"); if (code) { const supabase = await createServerSupabaseClient(); // 'code' search param 값을 이용, // supabase auth에서 제공하는 exchangeCodeForSession 메서드를 사용하여 // code를 이용해 로그인 세션 획득, 로그인 처리가 됨 await supabase.auth.exchangeCodeForSession(code); } // redirect url로 이동 (localhost:3000/signup/confirm/?code=... -> localhost:3000/) return NextResponse.redirect(requestUrl.origin); } 코드 → 세션 교환해 로그인 처리 후 NextResponse.redirect를 호출해 리다이렉트 (기본 url로 가게 설계)기본 url에서는 유저 로그인 상태를 체크해 상태에 맞는 페이지를 보여주도록 함// app/layout.tsx // async function RootLayout 안에서 (서버 컴포넌트여서 async function으로 정의 가능) const supabase = await createServerSupabaseClient(); const { data: { session }, } = await supabase.auth.getSession(); const loggedIn = !!session?.user; // return문 안에서 {loggedIn ? <MainLayout>{children}</MainLayout> : <Auth />} layout.tsx:23 Server Using the user object as returned from supabase.auth.getSession() or from some supabase.auth.onAuthStateChange() events could be insecure! This value comes directly from the storage medium (usually cookies on the server) and may not be authentic. Use supabase.auth.getUser() instead which authenticates the data by contacting the Supabase Auth server.2. 6자리 OTP 방식 - 메일의 6자리 OTP 토큰을 사용자가 복사해 인증 진행, OTP 입력 및 제출을 위한 인풋 UI 마련 필요1번에서 구현한 이메일, 패스워드로 signUp하는 것은 동일, 그 사이에 verifyOtp 를 사용해 인증을 한번 거치는 것mutationFn 작성email, password만 넘겨줬던 signUp과 달리, type, email, token을 넘겨줘야 함type은 “signup”mutationFn: async ({ email, otp }: { email: string; otp: string }) => { const { data, error } = await supabase.auth.verifyOtp({ type: "signup", // 왜 signup이지? email, token: otp, }); if (error) { handleError(error); } return data; }, 회원가입 form에서, confirmationRequired 상태일 때 보여줄 <input /> 추가(otp 입력 받을 창)otp용 useState, input 추가하고onSubmit과 button에 otp 관련 상태 처리 코드 추가3. 카카오로 로그인Kakao Developers에서 선행 작업 필요signInWithOAuth 함수 사용이 함수는, authentication에 없는 계정일 경우 새로 추가하고 아니면 다음 단계로 넘어가도록 설계가 되어 있나봄. 그래서 signin, signup에 별도로 구현할 필요 없이 이 함수 이용하는 동일한 하나의 로직을 이용하면 됨provider에 “kakao”, options에 redirectTo 전달authentication에는 Provider에 Kakao(1번 방법에선 Email)인 유저가 추가됨route 정의 필요1번 방법과 마찬가지로, redirect url로 설정했던 경로와 일치하는 route.ts 파일을 추가ex. app/auth/callback/route.ts마찬가지로 searchParams로 받은 code 값을 이용해 로그인 처리 가능 (exchangeCodeForSession)2. 로그인signInWithPassword로 간단히 구현 가능return useMutation({ mutationFn: async ({ email, password, }: { email: string; password: string; }) => { const { data, error } = await supabase.auth.signInWithPassword({ email, password, }); if (error) { handleError(error); } return data; }, }); 다음으로 Realtime도 살펴보자.Broadcast - 직접 방출과 리슨을 구현하는 듯전체 공지를 보낼 때 등에 유용강력하지만 구현 복잡성이 높음Presence - 현재 연결된 사용자를 실시간으로 추적. 유저가 들어왔다/나갔다를 파악 가능 (sync, join, leave)현재 온라인인 유저들 파악에 사용이 채널에 특정 유저가 있나 없나 확인 가능유저가 subscribe()하면 join으로, unsubscribe하면 leave로 인식됨subscribe할 때 user의 onlineAt 같은 컬럼 값을 업데이트해줌으로써 유저가 언제 온라인이었는지 파악 가능하다?sync는 join, leave 모두 감지 가능한, 말그대로 싱크가 맞춰져 있게 되는 것주로 sync를 사용하고, join, leave 발생 시 따로 노티를 띄워준다거나 하는 별도의 처리를 하고 싶을 때 join, leave를 사용하자Postgres Changes - DB에 INSERT, UPDATE, DELETE 이벤트가 발생하는 것을 스트림channel명을 정하고 subscribe하면 그 이후부터 db에 발생하는 이벤트를 리슨 가능유용한 패키지Javascript time agonpm install --save javascript-time-ago몇분전, 과 같은 문자열 표시를 돕는 패키지다. 로케일도 지원해 다국어를 지원해줘야 할 때 더 빛을 발한다. 그리고 RLS도 다뤄보았다.RLS = Row Level SecurityLow가 아니라 Row테이블의 Row 단위로 보안 규칙/제약을 설정할 수 있다는 의미테이블 컬럼 수정default value에는 함수 호출도 가능, auth.uid()는 로그인된 유저의 uid가 디폴트로 들어감!Can either be a literal or an expression. When using an expression wrap your expression in brackets, e.g. (gen_random_uuid()) - 함수 사용 시 ()까지 붙여 호출해주기 마지막으로 배포를 해보았는데, 깃허브 연동도 깔끔하게 되고 정말 매끄러운 배포 경험을 할 수 있었다.Vercel이란Next.js 만든 팀이 쉽게 배포할 수 있게 만든 플랫폼회원가입하고 github 연동해서 손쉽게 배포 가능배포하기배포 전 ide에서 npm run build 실행해 빌드 에러 없는지 먼저 체크하고,거의 다 디폴트 값으로 따르면 되는데,환경변수 값 넣어주기 - Environment Variables.env 파일을 복사해서 붙여넣어주면 알아서 들어감배포 전 실제 환경변수 값과 일치하는지 한번 더 체크하기!환경변수 값이 잘못 들어가 500 에러가 발생했지만, 수정과 재배포가 간단해서 금방 수정할 수 있었다. 전역 상태관리 Jotai 사용지난 주차에 전역 상태관리 툴 Recoil 버전 오류로 context api를 써서 갈음했었는데,이번 주차 내용은 좀더 많은 전역 상태 관리가 필요해, 가벼운 라이브러리라는 Jotai를 사용해보았다.정확히 어떤 원리로 동작하는지는 아직 뜯어보지 못했는데, 정말 간단하게 Provider를 만들어서 사용할 수 있었다.타입도 명시하여 정의하는 방식이라 명확한 부분이 마음에 들었다.사용법이 리코일보다도 간단해서 어떤 식으로 동작이 되는건지 살펴보고 싶다!

인프런 워밍업 스터디 클럽 3기 4주 차 발자국

섹션 7: Mockito로 Stubbing하기Test Double 종류Dummy: 아무 기능도 없는 객체.Fake: 간단한 형태로 실제 기능 수행 가능하지만, 프로덕션에 적합하지 않은 객체.Stub: 미리 준비된 결과를 반환하는 객체로, 상태 검증에 사용.Spy: Stub이면서 호출 기록을 제공하며 일부는 실제 객체처럼 동작 가능.Mock: 특정 행위를 명세하고 동작하도록 설계된 객체로, 행위 검증에 사용.Mockito 주요 어노테이션@Mock: Mock 객체 생성.@Spy: 실제 객체의 메서드를 수행하되 특정 메서드만 Mocking.@InjectMocks: Mock과 Spy 객체를 자동 주입.BDDMockito행동 주도 개발 방식으로 given().willReturn()을 사용하여 테스트 작성.Classicist vs MockistClassicist: 실제 객체를 사용해 자연스럽고 직관적인 테스트. 리팩토링에 유리하지만 상태 검증만으로는 동작 오류를 놓칠 수 있음.Mockist: 모든 협력자를 Mock으로 대체하여 동작을 명확히 검증. 세부 구현에 의존적이라 리팩토링 시 테스트가 깨질 가능성이 있음.섹션 8: 더 나은 테스트 작성법테스트 작성 원칙한 테스트는 한 목적만 가져야 하며, if와 for 사용을 지양.LocalDateTime.now() 같은 제어 불가능한 값은 파라미터로 넘겨 제어.테스트 환경 독립성공유 자원을 사용하지 말고, 테스트 간 독립성을 보장.픽스처(Test Fixture)는 각 테스트가 내부 구현을 몰라도 이해 가능해야 함.Test Fixture 클렌징deleteAll(): 순차적으로 삭제, 성능 저하 우려.deleteAllInBatch(): 단일 SQL DELETE 쿼리로 대량 데이터 삭제 가능.반복 및 동적 테스트@ParameterizedTest: 여러 파라미터 값으로 반복 테스트.예: CsvSource, MethodSource 활용.@DynamicTest: 런타임에 동적으로 테스트 케이스 생성 및 실행.통합 환경 최적화서버 부팅 횟수를 줄이기 위해 통합 테스트 클래스를 상속 구조로 설계.예: @SpringBootTest, @ActiveProfiles("test").Private 메서드와 테스트 전용 코드Private 메서드는 직접 테스트하지 말고, 객체 분리를 통해 public 메서드로 검증.테스트 전용 메서드는 필요하면 작성 가능하나 신중히 접근.추가 내용Spring REST Docs vs SwaggerREST Docs: 신뢰도 높고 프로덕션 비침투적이지만 설정이 복잡함.Swagger: 적용이 쉽고 API 호출 가능하지만 프로덕션 코드에 침투적이고 신뢰도가 낮음.    후기  생각보다 봐야할 강의 양도 많고 이해하기가 어려워서 한 강의당 3번씩 돌려본것 같다. 특히나 하다가 테스트를 시도했는데. 아니 강의에서는 통과하는데 나는 실패했을때 실패지점 찾는데 진짜 애먹었다. 정신나갈뻔한 상황도 많았지만 많이 배울 수 있었다. 그럼에도 아직 어려운 부분이 많았다.   강의 : https://www.inflearn.com/course/readable-code-%EC%9D%BD%EA%B8%B0%EC%A2%8B%EC%9D%80%EC%BD%94%EB%93%9C-%EC%9E%91%EC%84%B1%EC%82%AC%EA%B3%A0%EB%B2%95/dashboard

@Mock, @MockBean, @Spy, @SpyBean, @InjectMocks의 차이

 1. @Mock, @MockBean, @Spy, @SpyBean, @InjectMocks의 차이 @Mock@Mock은 Mockito에서 제공하는 애노테이션으로, 특정 클래스나 인터페이스의 가짜 객체(Mock)를 생성한다.Spring 컨텍스트와는 무관하며, 순수하게 단위 테스트를 위해 사용된다.테스트 대상 객체가 의존하는 객체를 가짜로 만들어 테스트를 고립시키고자 할 때 활용된다.@MockBean@MockBean은 Spring Boot에서 제공하는 애노테이션으로, Spring 컨텍스트에 등록된 Bean을 Mock 객체로 교체한다.통합 테스트에서 특정 Bean의 실제 동작을 대체해야 할 때 사용된다.주로 서비스 계층의 일부 Bean을 Mock으로 교체해 컨트롤러 테스트를 진행하는 경우에 적합하다.@Spy@Spy는 실제 객체를 기반으로 부분적으로 Mocking을 할 수 있게 해주는 Mockito 애노테이션이다.객체 전체를 Mock으로 만드는 것이 아니라, 특정 메서드만 가짜 동작을 설정할 수 있다. 나머지 메서드는 원래 동작을 그대로 유지한다.실제 객체의 일부 동작만 변경하거나 추적하려는 경우에 적합하다.@SpyBean@SpyBean은 Spring Boot에서 제공하는 애노테이션으로, Spring 컨텍스트에서 관리되는 Bean을 Spy로 교체한다.@Spy와 비슷하지만, Spring 컨텍스트 내에서 관리되는 Bean에 대해 부분적인 Mocking이 가능하다는 점에서 차이가 있다.Spring 환경에서 특정 Bean의 일부 메서드만 가짜로 설정하고 나머지는 원래 동작을 유지하고자 할 때 사용된다.@InjectMocks@InjectMocks는 테스트 대상 클래스에 필요한 의존성을 자동으로 주입해주는 Mockito 애노테이션이다.생성자, 필드, 또는 setter를 통해 Mock이나 Spy 객체를 자동으로 주입한다.테스트 대상 클래스가 여러 의존성을 가지고 있을 때 이를 효율적으로 설정할 수 있다.Mock이나 Spy 객체를 단순히 생성하는 것을 넘어, 이들을 테스트 대상 클래스와 연결해주는 역할을 한다.이 애노테이션들은 각각의 목적과 상황에 맞게 사용되며, 단위 테스트에서는 주로 @Mock과 @InjectMocks가 사용되고, 통합 테스트에서는 @MockBean과 @SpyBean이 적합한 경우가 많다. @Spy는 실제 객체의 일부만 Mocking해야 하는 상황에서 유용하다.   2. 테스트 코드 리팩토링공통 항목(@BeforeEach)테스트 코드에서 중복되는 사용자 및 게시물 생성 로직을 @BeforeEach로 이동하여 공통화할 수 있다. class CommentServiceTest { private User user; private Post post; @BeforeEach void setUp() { // 사용자 생성에 필요한 내용 준비 및 사용자 생성 user = createUser(); // 게시물 생성에 필요한 내용 준비 및 게시물 생성 post = createPost(user); } @DisplayName("사용자가 댓글을 작성할 수 있다.") @Test void writeComment() { // given Comment comment = prepareComment(post, user); // when commentService.writeComment(comment); // then assertThat(commentRepository.findById(comment.getId())).isPresent(); } @DisplayName("사용자가 댓글을 수정할 수 있다.") @Test void updateComment() { // given Comment comment = prepareComment(post, user); commentService.writeComment(comment); String updatedContent = "Updated content"; // when commentService.updateComment(comment.getId(), updatedContent); // then assertThat(commentRepository.findById(comment.getId()).get().getContent()).isEqualTo(updatedContent); } @DisplayName("자신이 작성한 댓글이 아니면 수정할 수 없다.") @Test void cannotUpdateCommentWhenUserIsNotWriter() { // given User anotherUser = createAnotherUser(); Comment comment = prepareComment(post, user); commentService.writeComment(comment); String updatedContent = "Updated content"; // when & then assertThrows(UnauthorizedException.class, () -> commentService.updateCommentAsUser(anotherUser, comment.getId(), updatedContent) ); } private User createUser() { // 사용자 생성 로직 구현 return new User("user1", "password"); } private User createAnotherUser() { // 다른 사용자 생성 로직 구현 return new User("user2", "password"); } private Post createPost(User user) { // 게시물 생성 로직 구현 return new Post("게시물 제목", "게시물 내용", user); } private Comment prepareComment(Post post, User user) { // 댓글 생성 로직 구현 return new Comment("댓글 내용", post, user); } }

Layered Architecture 구조의 레이어별 특징과 테스트 작성법

 1. 레이어별 특징Presentation Layer외부 세계의 요청을 가장 먼저 받는 레이어로, 사용자나 외부 시스템과의 인터페이스 역할을 한다.클라이언트로부터 전달받은 데이터를 검증하고, 비즈니스 로직을 수행할 수 있도록 Business Layer로 전달한다.주로 요청 파라미터에 대한 최소한의 검증과 API 응답 형식을 처리한다.Business Layer애플리케이션의 핵심 비즈니스 로직이 구현되는 레이어이다.Persistence Layer와 상호작용하며 데이터 처리 및 트랜잭션을 보장한다.비즈니스 규칙에 따라 데이터를 가공하거나 처리하는 역할을 담당한다.Persistence Layer데이터베이스와 직접적으로 상호작용하는 레이어로, 데이터 CRUD(Create, Read, Update, Delete) 작업에만 집중한다.비즈니스 로직이 포함되지 않으며, 순수하게 데이터 접근 및 저장소 관련 작업만 수행한다.2. 테스트 작성법Presentation Layer 테스트목적: 외부 요청에 대한 파라미터 검증과 컨트롤러 동작을 독립적으로 테스트한다.방법:하위 계층(Business Layer, Persistence Layer)은 @MockBean으로 모킹(mocking) 처리하여 독립적인 단위 테스트를 진행한다.Spring MVC 테스트를 활용해 HTTP 요청 및 응답 흐름을 검증한다.예를 들어, 잘못된 파라미터가 전달되었을 때 적절한 에러 메시지가 반환되는지 확인한다.Business Layer 테스트목적: 비즈니스 로직이 의도한 대로 동작하는지 검증하고, Persistence Layer와의 상호작용을 확인한다.방법:단위 테스트를 작성하여 특정 메서드의 동작을 검증한다.Persistence Layer를 실제로 호출하지 않고, Mock 객체를 사용해 독립적으로 테스트할 수도 있다.통합 테스트 시에는 @SpringBootTest와 실제 DB를 활용하여 트랜잭션 롤백 기능으로 데이터를 정리하며 테스트를 진행한다.Persistence Layer 테스트목적: SQL 쿼리가 제대로 동작하는지 검증하고, 데이터베이스와의 CRUD 작업이 정상적으로 수행되는지 확인한다.방법:@DataJpaTest를 활용하여 인메모리 DB(H2 등)를 사용해 빠르게 검증한다.단위 테스트 성격을 가지며, Repository 계층에서 작성한 쿼리 메서드가 의도한 대로 동작하는지 확인한다.테스트용 프로필 설정과 초기 데이터 주입 설정을 활용하면 편리하다.3. 테스트 방법 요약레이어주요 특징테스트 방법Presentation외부 요청 처리 및 파라미터 검증MockBean으로 하위 계층 모킹 처리 후 단위 테스트 진행 (Spring MVC Test 활용)Business비즈니스 로직 구현 및 트랜잭션 보장단위 테스트 또는 통합 테스트 (@SpringBootTest)Persistence데이터 CRUD 작업@DataJpaTest와 인메모리 DB로 SQL 쿼리 및 CRUD 동작 검증이처럼 각 레이어는 역할과 책임이 명확히 분리되어 있으며, 각 레이어에 맞는 적절한 테스트 전략을 적용함으로써 코드 품질과 유지보수성을 높일 수 있습니다.  출처 : https://inf.run/pZXb7

인프런 워밍업 스터디 클럽 3기 3주 차 발자국

Layered Architecture 테스트하기 어려운 부분 분리,테스트 하고자 하는 영역에 집중,명시적이고 이해할 수 있는 형태의 문서 작성 가능여러 가지 모듈이 합쳐진 결과를 우리는 예상 할 수 있는가?이를 위한 통.합.테.스.트통합 테스트🔸 여러 모듈이 협력하는 기능을 통합적으로 검증하는 테스트🔸 일반적으로 작은 범위의 단위 테스트만으로는 기능 전체의 신뢰성을 보장할 수 없다.🔸 풍부한 단위 테스트 & 큰 기능 단위를 검증하는 통합 테스트Library vs. Framework내 코드가 주체가 되어서 필요한 기능은 외부에서 끌어다 옴 vs. 이미 갖춰진 동작 환경에서 내 코드가 수동적으로 역할을 하게 됨Spring🔸 Ioc (Inversion of Control)객체의 생명주기를 주관해서. 필요한 객체가 있을때 필요한 객체를 제3자가 만들어서 주입해줌🔸 DI (Dependency Injection)생성자를 주입해서 사용함. 어디서 온 것인지는 알 수 없음(주는 것만 사용)🔸 AOP (Aspect Oriented Programming)비즈니스 흐름과 관계없는 부분을 하나로 모아서 다른 모듈로 분리해서 사용(스프링에서는 프록시 사용해서 구현 함)ORM (Object-Relational Mapping)객체지향에 대한 개념과 관계형 DB 간의 패러다임이 달라서 DB에 넣기에 어려움🔸 객체 지향 패러다임과 관계형 DB 패러다임의 불일치🔸 이전에는 개발자가 객체의 데이터를 한땀한땀 매피하여 DB에 저장 및 조회(CRUD)🔸 ORM 을 사용함으로써 개발자는 단순 작업을 줄이고, 비즈니스 로직에 집중할 수 있다.JPA. (Java Persistence API)🔸 Java 진영의 ORM 기술 표준🔸인터페이스이고, 여러 구현체가 있지만 보통 Hibernate를 많이 사용한다.🔸 반복적인 CRUD SQL 을 생성 및 실행해주고, 여러 부가 기능들을 제공한다.🔸 편리하지만 쿼리를 직접 작성하지 않기 때문에, 어떤 식으로 쿼리가 만들어지고 실행되는지 명확하게 이해하고 있어야 한다.🔸 Spring 진영에서는 JPA를 한번 더 추상화한 Spring Data JPA 제공🔸 QueryDSL 과 조합하여 많이 사용한다. (타입체크, 동적쿼리에 대한 장점. 실무에서는 필수로 사용하지만 강의의 범위를 넘어섬)🔸@Entity 테이블 과 객체를 매핑, @Id , @Column Entity 정의🔸@ManyToOne 두 객체간의 연관관계, @OneToMany, @OneToOne, @ManyToMany(일대다 - 다대일 관계로 풀어서 사용)엔티티 설계Order 와 Product 는 다대다 관계로서. 주문 입장에서 여러 음료수, 음료수 입장에서 여러 주문들이 된다.다대다 관계는. 일대다, 다대일 관계로 풀어서 접근할 것Order — OrderProduct — Product요구사항🔸 키오스크 주문을 위한 상품 후보 리스트 조회하기🔸 상품의 판매 상태 : 판매중, 판매보류, 판매중지→ 판매중, 판매보류인 상태의 상품을 화면에 보여준다🔸 id, 상품 번호, 상품 타입, 판매 상태, 상품 이름, 가격Persistence Layer🔸 Data Access 의 역할(여기에 집중한 레이어)🔸 비즈니스 가공 로직이 포함되어서는 안 된다. Data에 대한 CRUD에만 집중한 레이어Business Layer🔸 비즈니스 로직을 구현하는 역할🔸 Persistence Layer 와의 상호작용(Data를 읽고 쓰는 행위) 을 통해 비즈니스 로직을 전개시킨다.🔸 트랜잭션을 보장해야 한다.(로직을 전개하다 문제가 생기면 롤백해야 하기에, 롤백에 대한 트랜잭션을 보장해 줘야 한다). 작업 단위에 대한 원자성

인프런 워밍업 스터디 클럽 3기 2주 차 발자국

코드 다듬기와 리팩토링에 대한 요약1. 코드 다듬기주석의 양면성:주석은 코드로 설명할 수 없는 의사결정 히스토리를 기록하는 데 사용하되, 자주 변하는 정보는 주석으로 작성하지 않는 것이 좋다. 주석이 많다는 것은 비즈니스 로직이 코드에 잘 녹아들지 못했음을 의미할 수 있다.가독성을 위한 메서드와 변수 정렬:메서드는 상태 변경 > 판별 > 조회 순으로 나열하고, 접근 제한자는 public → private 순서를 유지하면 가독성이 향상된다.패키지 구조 설계:패키지는 문맥 정보를 제공해야 하며, 너무 세밀하거나 큰 단위로 나누면 유지보수가 어려워진다. 대규모 변경 시 팀원들과 반드시 협의해야 한다.클린 코드의 현실적 접근:클린 코드는 은탄환이 아니다. 요구사항이 변하지 않는 경우 절차지향적인 코드가 더 적합할 수도 있다. 실무에서는 품질과 빠른 결과물 사이에서 균형을 잡는 것이 중요하다.2. 리팩토링리팩토링의 본질:리팩토링은 단순히 코드를 변경하는 것이 아니라, 응집도를 높이고 결합도를 낮추는 과정이다. 객체 간의 관계와 책임을 점검하며 진행해야 한다.예외 처리와 boolean 반환:기존의 boolean 반환 방식을 예외 처리로 변경하는 것은 상황에 따라 좋을 수도, 오버엔지니어링이 될 수도 있다. 예외 처리는 비용이 크므로 신중히 사용해야 한다.일급 컬렉션 활용:컬렉션을 직접 노출하지 않고 이를 감싸는 클래스를 사용하면 유지보수가 쉬워지고 테스트 가능성이 높아진다.객체에 메시지를 보내라:무분별한 getter 사용 대신 객체에 메시지를 보내는 방식으로 설계하자. 예를 들어, isSamePassTypeWith 메서드를 통해 객체 내부에서 비교하도록 하면 캡슐화가 강화된다.인터페이스 활용:조건별로 다른 동작을 수행해야 할 때 인터페이스를 도입해 if문 사용을 줄이고 유연성을 높일 수 있다.3. 리팩토링 사례✅ 리팩토링 성공 사례중복 제거 및 메서드 추출:중복된 로직을 제거하고 메서드로 분리해 가독성과 재사용성을 높였다.StudyCafePassMachine 의존성 주입:필요한 의존성을 외부에서 주입받도록 하여 내부 구현을 외부에 노출하지 않도록 개선했다.도메인 모델 개선:StudyCafePassType 내 LOCKER_TYPES 상수를 선언해 사물함 관련 로직을 간단하게 처리했다.특정 타입만 처리하는 로직을 enum 내부에서 해결하도록 하여 책임 분리를 명확히 했다.Order 도메인 추출:스터디 카페 좌석 이용권과 사물함 이용권을 합친 Order 도메인을 새로 만들어 FixedPassType 관련 분기문을 간소화했다.❌ 놓친 부분과 개선 방향FileHandler 개선 필요:데이터를 가져오는 로직만 포함되어 있으나, File 관련 로직이 추가되면 클래스가 방대해질 우려가 있다. Provider를 통해 데이터 요구사항 중심으로 설계하는 것이 바람직하다.도메인과 View 로직 분리 부족:StudyCafePassType enum에 입력 관련 필드(command)가 포함되어 있어 도메인 모델과 View 로직이 섞였다. 이는 입력 방식 변경 시 도메인 모델까지 수정해야 하는 문제를 초래한다.4. 최종 결론좋은 코드는 단순히 동작하는 코드가 아니라, 이해하기 쉽고 유지보수 가능한 코드다.완벽한 설계는 없으며, 지속적으로 개선하며 유연한 구조를 만들어가는 것이 중요하다.객체 지향 설계의 핵심은 변경에 유연한 구조를 만드는 것이다.

DABBB

[인프런 워밍업 클럽 스터디 3기] 미션 4

미션프로덕트의 Opportunity Solution Tree 만들기왜 그런 Opportunity들과 Solution들을 도출했는지, 생각의 과정도 함께 적기 대상 프로덕트마켓컬리  Desired Outcome 고객의 재구매율을 높인다지속적인 성장을 위해서는 신규 고객 유입뿐만 아니라 기존 고객이 반복 구매하도록 유도하는 것이 핵심이므로특히 마켓컬리의 주력상품인 신선식품(채소, 과일, 육류, 유제품 등)은 한 번 만족하면 재구매 가능성이 높음소비 주기가 짧아 일정 기간마다 지속적으로 필요하므로신선식품은 품질 차이가 크고, 온라인에서는 직접 보고 고를 수 없기 때문에 한 번 만족한 고객은 같은 곳에서 재구매하려는 경향이 강하므로 Opportunity & SolutionOpportunity : 첫 구매 후 사이트 방문 빈도가 낮다신선식품은 한 번 만족하면 재구매 가능성이 높은데, 고객이 첫 구매 후 방문하지 않는다면 그 경험을 이어나가지 못하는 문제가 생김 -> 재방문을 유도하는 방법들을 고민Solutions :첫 구매 고객에게 맞춤형 추천 상품 제공 구매 후 리뷰 작성 시 할인 쿠폰 지급 첫 구매 후 7일 내 재방문 유도 메시지 발송Opportunity : 장바구니에 담았지만 결제하지 않는 비율이 높다해당 상품에 관심이 있지만 가격이 비싸게 느껴지거나, 구매에 고민이 되어 결제하지 않는 것으로 생각 -> 가격이 변하거나 좋은 리뷰를 보여주어 상품에 매력을 느끼도록 함Solutions :장바구니에 있는 상품 가격 변동 알림 제공 장바구니 보관 기한 연장 & 리마인드 알림 베스트셀러 제품 리뷰 강조하여 신뢰도 향상Opportunity : 특정 고객층의 구매 주기가 길다신선식품이 필요하지만, 매번 주문하는 것이 귀찮은 고객층이 존재 -> 자연스럽게 재구매를 유도하는 방법이 효과적일 것으로 판단Solutions :정기구독 모델 도입 (필수 식료품 자동 배송) 최근 구매한 상품 기반으로 맞춤형 재구매 추천 "이번 주 인기 장바구니" 기능으로 구매 유도  

기획 · PM· PO

jurjur

CS 1주차 발자국

운영 체제운영체제 개요컴퓨터는 운영체제가 없어도 동작이 가능예전 전화기는 통화만 되지만 최신 휴대전화는 어플등 다양한 기능이 가능운영체제의 일프로세스 관리메모리 관리하드웨어 관리파일 시스템 관리운영체제의 역사1943 애니악1950초반 직접회로 개발후반 싱글 스트림 배치시스템1960시분할 시스템싱글 스트림 배치 시스템 한계 극복프로그램을 순서대로 실행하는 것이 아닌 메모리에 여러 프로그램을 올려 놓고 시간을 나누어서 빠르게 돌아가며 실행UNIX멀티 프로그래밍다중 사용자파일 시스템1970개인용 컴퓨터의 시대매킨토시, ms-dos 운영체제의 구조커널프로세스와 메모리, 저장 장치를 관리하는 기능사용자는 인터페이스를 통해 접속사용자는 GUI, CLI로 커널 제어어플리케이션과 커널의 인터페이스는 시스템 콜을 사용하드웨어와 커널의 인터페이스는 드라이버를 사용컴퓨터 하드웨어와 구조폰 노이만 구조CPU와 메모리 사이에 버스로 연결.메인보드다른 하드웨어를 연결하는 장치cpu와 메모리가 필수CPU(중앙처리 장치)산술 논리 연산장치, 제어장치, 레지스터의 구조메모리 종류ram전원을 끄면 메모리가 휘발ROM(Read Only Memory)전월을 꺼도 메모리가 보존.바이오스 등 수정되지 않는 데이터를 저장부팅 과정ROM에 저장된 바이오스 실행부트 오더인터럽트cpu는 입출력 작업이 들어오면 입출력 관리자에게 입출력 명령주기적으로 장치들에게 확인→ polling 방식. 효율이 좋지 않음polling방식의 단점을 보완한게 인터럽트입출력 명령을 내리고 입출력 관리자는 입출력이 발생하면 cpu에게 전달cpu는 isr실행시켜 작업 완료.하드웨어 인터럽트소프트웨어 인터럽트 프로그램하드디스크 등과 저장장치에 저장된 명령문의 집합체저장 장치만 사용하는 수동적인 존재프로세스실행중인 프로그램하드디스크에 저장되어 있는 프로그램이 메모리에 올라가있는 상태메모리도 사용하고 운영체제의 cpu 스케줄링 알고르즘도 사용, 출력와 입력도 하는 능동적인 존재프로세스 구조code, data, heap, stack 영역으로 구조code실행하는 코드가 저장data전역 변수와 static(정적) 변수가 저장heap동적으로 메모리를 할당하는데 사용.stack지역 변수와 함수를 호출했을때 필요한 정보들이 저장프로세스가 되는 과정컴파일 과정전처리기 → 컴파일러 → 어셈블러 → 링커(링킹)유니프로그래밍메모리에 오직 하나의 프로세스가 올라와 처리하는 것cpu는 프로세스를 실행하다가 i/o 작업을 만나면 기다렸다가 완료되면 작업을 처리하나의 프로세스를 다 끝내야 다른 프로세스를 실행하는 단점이 존재.멀티 프로그래밍메모리에 여러개의 프로세스를 올려서 실행cpu가 프로세스를 실행하다가 I/O 작업을 만나면 기다리면서 다른 프로세스를 실행cpu 쉬는시간이 줄어들어 효율적여러개의 프로세스를 돌아가면서 짧은시간동안 작업을 진행하여 모든 프로세스를 동시에 실행시키는 것처럼 느끼게 하는 기술→ 멀티태스킹cpu를 한개가 아니라 여러개를 이용→ 멀티 프로세서멀티 프로세서로 작업을 처리하는 방식을 멀티 프로세싱이라 칭함.PCB(Process Control Block)프로세스가 만들어지면 운영체제는 해당 프로세스의 정보를 갖고 있는 PCB를 만들고 저장.PCB들은 연결리스트라는 자료 구조로 저장.프로세스가 종료되면 연결리스트에서 해당 프로세스의 PCB를 제거.연결 리스트의 구조는 유지PCB 구조포인터부모와 자식 프로세스에 대한 포인터와 할당된 자원에 대한 포인터를 저장프로세스 상태현재 프로세스의 5가지 상태를 나타냄생성, 준비, 실행, 대기, 완료프로세스 ID프로세스를 식별하기 위한 숫자프로그램 카운터다음에 실행될 명령어의 주소를 포함하는 프로그램 카운터를 저장레지스터 정보프로세스가 실행될때 사용했던 레지스터 값들을 저장메모리 관련 정보메모리에 있는 위치정보, 경계레지스터 값 등이 저장CPU 스케쥴링 정보스케쥴링에 필요한 우선순위, 최종 실행시간, CPU 점유 시간등이 저장프로세스 상태시분할 시스템을 사용하는 운영체제는 여러개의 프로세스를 돌아가면서 실행cpu가 여러개의 프로세스를 동시에 실행하는 것이 아니라 한 순간에는 하나의 프로세스밖에 처리하지 못함속도가 빨라 사람이 보기엔 동시에 처리로 보임.생성 상태PCB를 생성하고 메모리에 프로그램 적재를 요청한 상태준비 상태CPU를 사용하기 위해 준비하고 있는 상태CPU 스케쥴러에 의해 CPU가 할당됨.대부분의 프로세스 상태실행 상태준비상태에 있는 프로세스가 CPU 스케쥴러에 의해 CPU를 할당받아 실행되는 상태실행상태에 있는 프로세스의 수는 CPU의 갯수만큼부여된 시간만큼만 사용이 가능시간이 완료되면 다시 준비 상태로 변경대기 상태프로세스가 입출력을 요청하면 입출력이 완료될 때까지 기다리는 상태완료 상태프로세스가 종료된 상태데이터를 메모리에서 제거하고 생성된 PCB제거 컨텍스트 스위칭프로세스를 실행하는 중에 다른 프로세스를 실행하기 위해 실행중인 프로세스의 상태를 저장하고 다른 프로세스의 상태값으로 교체하는 작업실행중인 프로세스의 작업 내용을 PCB에 저장하고 실행될 기존 프로세스의 PCB의 내용대로 CPU가 다시 세팅됨. PCB에 변경되는 값들은 프로세스 상태, 프로그램 카운터, 레지스터 정보, 메모리 관련 정보 등컨텍스트 스위칭이 발생하는 이유CPU 점유 시간이 다 된 경우I/O 요청이 있는 경우다른 종류의 인터럽트가 있는 경우프로세스 생성과 종료.exe 파일 실행시 운영체제는 포로그램의 코드영역과 데이터 영역을 메모리에 로드하고 빈스택과 빈 힙을 만들어 공간을 확보프로세스를 관리하기 위한 pcb를 만들어 값을 초기화프로세스 생성과 정은 운영체제가 부팅되고 0번 프로세스가 생성될때 딱 1번만 실행.나머지 모든 프로세스는 새로 생성하지 않고 0번 프로세스를 복사해서 사용복사는 fork()함수를 사용새로 생성하는 것보다 복사하는게 빠르기 때문복사한 프로세스는 자식 프로세스0번 프로세스는 부모 프로세스자식 프로세스는 부모 프로세스의 코드영역, 데이터 영역, 스텍 영역가 pcb 내용을 전부 복사그럼 복사하면 0번 프로세스가 똑같이 실행되는거 아닌가?맞음. 그대로 복사하니 당연한 결과자기가 원하는 코드는 exec() 함수를 이용하여 실행.부모를 복사한 자식 프로세스의 코드와 데이터 영역을 원하는 겂으로 덮어쓰게됨.자식프로세스는 부모 프로세스와 다르게 동작 부모 프로세스와 자식 프로세스는 cpu 스케줄링에 따라 실행되는데 순서는 운영체제 따라 결정.부모 프로세스가 먼저 실행되는 경우pid 값을1 받으면 17번째 줄 함수 실행자식 프로세스의 exit 실행될때까지 대기.자식 프로세스 실행12번 함수 실행 후 13번 함수를 통해 프로세스 종료를 부모 프로세스에게 전달대기하고 있던 부모 프로세서는 자식 프로세스의 종료 신호를 받고 18번 함수 19번 함수를 실행하고 종료만약 부모 프로세스가 자식 프로세스보다 먼저 종료되거나 자식 프로세스가 비정상적인 종료가 되어서 exit신호를 주지 못해 ExitStatus를 읽어오지 못하여 메모리에 계속 살아 있는 상태를 좀비 프로세스라고 함쓰레드운영체제가 작업을 처리하는 단위는 프로세스프로세스를 생성하면 pcb가 생성되고 프로세스 수만큼 pcb, 코드, 데이터, 스택, 힙 영역도 만들어줘야 하기 때문에 너무 무거워짐.그래서 프로세스가 많아질수록 메모리를 많이 차지 하게 됨.⇒ 쓰레드 고안쓰레드는 프로세스 안에 있고 한개 또는 여러개가 존재하게 됨.쓰레드들은 프로세스의 pcb, code, data, heap영역을 공유. 단 stack은 쓰레드마다 하나씩 갖고 있음. 쓰레드들에게 id를 부여하고, 쓰레드를 관리하기 위한 TCB(Thread Control Blcok)이 생성.운영체제 관점에서 쓰레드들도 구분이 가능해짐.브라우저에서 탭을 하나 추가로 생성하면, 프로세스가 생성되는 것이 아니라 쓰레드가 하나 더 생성됨.프로세스와 쓰레드의 장단점안정성프로세스는 서로 독립적이기 때문에 하나의 프로세스가 문제 있어도 다른 프로세스는 영향을 받지 않는다.쓰레드는 하나의 프로세스 안에 존재하기 때문에 프로세스에 문제가 생기면 쓰레드에게도 문제가 생긴다.프로세스 방식이 쓰레드 보다 우수속도와 자원각각의 프로세스는 서로 고유한 자원을 갖고 있음. code, data, heap, stack영역을 전부 따로 두고 있고, 프로세스간 통신을 하려면 IPC를 이용해야 해서 오버헤드가 크고 속도가 느림.쓰레드는 한 프로세스 내에서 stack 영역을 제외한 영역을 공유하므로 오버헤드가 작음. 쓰레드 간의 통신은 데이터를 공유할 수 있으니 쉽지만, 공유되는 공간에서 문제가 생길 수 있음. CPU 스케쥴링 개요운영체제는 모든 프로세스에게 cpu를 할당/해제 하는데 이를 cpu 스케쥴링이라 함.스케줄러(운영체제)의 고려사항어떤 프로세스에게 cpu리소스를 주어야 하는가.cpu를 할당 받은 프로세스가 얼마나 cpu를 사용해야 하는가.시분할 처리 방식으로 여러 프로세스에 짧은 시간동안 돌아가면서 Cpu를 할당.→ 컴퓨터의 성능에 영향을 많이 미침.cpu를 할당받아 처리하는 작업을 CPU Burst. 입출력 작업을 I/O Burst.다중 큐큐먼저 들어온걸 먼저 처리하고, 나중에 들어온걸 나중에 처리하는 구조.프로세스가 실행상태에서 준비 상태로 돌아갈때운영체제는 해당 프로세스의 우선순위를 보고 그에 맞는 준비 큐에 넣음.cpu스케줄러는 준비 상태의 다중큐에 들어있는 프로세스들 중에 적당한 프로세스를 선택해서 실행 상태로 전환.프로세스가 실행상태에서 i/o 요청을 받아 대기상태로 오면i/o 작업 종류에 따라서 분류된 큐에 들어가게 됨.hdd, lan, 키보드 큐큐에 들어가는건 프로세스의 정보를 갖고 있는 PCB가 들어감.프로세스 정보를 담고 있는 PCB는 준비상태의 다중큐에 들어가서 준비되길 기다리며, CPU스케쥴러에 의해 실행 상태로 전환.CPU스케쥴러는 준비상태의 다중큐를 참조하여 어떤 프로세스를 실행시킬지 결정I/O 작업도 종류별로 나누어진 큐에 들어가고 CPU스케쥴러는 이를 참조해 스케쥴링을 진행.스케쥴링 목표리소스 사용률CPU사용률을 높이는것을 또는 I/O 사용률을 높이는것을 목표로 할 수 있음.오버헤드 최소화스케줄링을 하기 위한 계산이 복잡하거나 컨텍스트 스위칭을 자주하면 배보다 배꼽이 커지는 상황이 발생.스케줄러는 이런 오버헤드를 최소화 하는것을 목표공평성모든 프로세스에게 공평하게 CPU가 할당되어야 함.공평의 의미는 시스템에 따라 달라질 수 있음.처리량같은 시간내에 더 많은 처리를 할 수 있는 방법을 목표로 함.대기시간작업을 요청하고 실제 작업이 이뤄지기 전까지 대기하는 시간이 짧은 것을 목표로 함.응답시간대화형 시스템에서 사용자의 요청이 얼마나 빨리 반응하는지가 중요하므로 응답시간이 짧은것을 목표로 함.모든 목표를 최고 수준으로 유지하기는 힘듬.서로 상반된 목표가 있기 때문.처리량을 높이기 위해서는 하나의 프로세스에 cpu를 오래 할당해야함.응답시간을 줄이기 위해서는 여러 프로세스에 cpu를 골고루 할당해야함.→ 처리량과 응답시간의 목표를 같이 달성할 수 없음.→ 사용자가 사용하는 시스템에 따라서 목표를 다르게 설정.스케쥴링 알고리즘FIFO(First In First Out)먼저 들어온 작업이 먼저 나감.스케쥴링 큐에 들어온 순서대로 cpu를 할당하는 방식.먼저 들어온 프로세스가 완전히 끝나야만 다음 프로세스가 실행 됨.장점단순하고 직관적단점한 프로세스가 완전히 끝나야 다음 프로세스가 실행되기 때문에 실행시간이 짧고 늦게 도착한 프로세스가 실행시간이 길고 빨리 도착한 프로세스의 작업을 기다려야 함.또한 I/O작업이 있다면 cpu가 i/o작업이 끝날때까지 기다리기때문에 cpu 사용률이 떨어짐.스케줄링의 성능은 평균 대기 시간으로 평가평균 대기 시간은 프로세스가 여러개 실행될때 이 프로세스가 모두 실행될때까지 대기 시간의 평균.프로세스 1의 burst는 25초, 프로세스2는 5초 프로세스3은 4초.프로세스1이 먼저 도착했으므로 대기시은 0초.프로세스2는 프로세스1이 실행되고 실행 하므로 대기시간은 25초.프로세스 3은 프로세스1과 프로세스2가 실행되고 실행 하므로 대기시간은 30초.평균 대기시간은 18.3초.순서가 바뀌면프로세스3은 바로 시작 되었으므로 대기시간은 0초.프로세스2이 실행되고 프로세스2가 실행. 대기시간은 4초.프로세스1은 프로세스 3,2 실행 시간만큼 기다려서 대기시간은 9초.평균 대기시간은 4.3초.⇒ FIFO 알고리즘은 프로세스의 Burst Time에 따라 성능의 차이가 심하게 나서 현대 운영체제에서는 잘 쓰이지 않고 일괄 처리 시스템에 사용됨.SJF(Shortest Job First)FIFO의 단점을 보완.이론적으로 FIFO보다 성능이 좋음.하지만 문제점 발생어떤 프로세스가 얼마나 실행될 지 예측이 힘듦.BurstTime이 긴 프로세스는 아주 오래동안 실행되지 않을 수 있음.→ 이러한 문제때문에 SJF알고리즘은 사용되지 않음.RR(Round Robin)FIFO알고리즘은 일괄처리 시스템엔 적절하지만 시분할 처리 시스템엔 부적절SJF알고리즘의 단점은 프로세스의 종료 시간을 예측하기 힘듦.FIFO 알고리즘의 단점을 해결한 프로세스에게 일정 시간만큼 cpu를 할당하고, 할당시간이 지나면 강제로 다른 프로세스에게 일정 시간만큼 cpu를 할당.강제로 cpu를 빼앗긴 프로세스는 큐의 마지막으로 이당.프로세스에게 할당하는 일정 시간은 타임 슬라이스 또는 타임 퀀텀이라고 부름.평균 대기시간 측정타임슬라이스: 10sP1의 BursTime은 25초 / P2는 4초 / P3는 10초P1은 큐에 들어오자마 실행. 대기시간은 0초25초중 타임 슬라이스 값인 10초만 실행되고 나머지 시간은 큐의 제일 뒤로 이동.P2(4s) / P3(10s) / P1(15s)p2는 10초동안 기다림. 대기시간은 10초BurstTime인 4초만 실행하고 종료.P3(10s) / P1(15s)p3은 14초동안 기다림. 대기시간은 14초BurstTime인 10초만 실행하고 종료P1(15s)p1은 p2, p3의 실행 시가만큼 기다림. 대기시간은 14초.BurstTime이 타임 슬라이스 값보다 크므로 10초만 실행.남은 작업시간은 큐의 맨 뒤로 생성P1(5s)다시 P1의 남은 작업을 실행. 큐에 생성되자마자 실행 되므로 대기시간은 0초.→ 평균 대기시간은 12.67sRR방식과 FIFO방식의 평균 대기시간이 비슷할 수 있음.평균 대기시간이 비슷하면 RR방식이 비효율적→ 컨텍스트 스위칭이 있기 때문에 컨텍스트 스위칭 시간이 더 추가되기 때문.→ RR 알고리즘의 성능은 타임슬라이스 값에 따라 크게 달라짐.타임 슬라이스가 무제한인 경우 FIFO와 같음.타임 슬라이스가 작은경우에는 컨텍스트 스위칭이 너무 자주 발생함.타임 슬라이스에서 실행되는 프로세스의 처리 양보다 컨텍스트 스위칭을 처리하는 양이커져서 오버헤드가 너무 커지는 상황 발생.최적의 타임슬라이스를 설정하는 방법은 사용자가 느끼기에 여러 프로세스가 버벅 거리지 않고 동시에 실행된다고 느끼면서 오버헤드가 너무 크지 않는 값을 찾아야 함.윈도우는 20ms, Unix는 100msMLFQ(Multi Level Feedback Queue)가장 일반적으로 쓰이는 cpu 스케쥴링 기법탄생 배경RR의 업그레이드 된 알고리즘P1은 I/O 작업 없이 CPU연사만 하는 프로세스, P2는 1초 CPU 연산을 하고 10초 동안 I/O 작업.P1 → Cpu Bound Process // P2 → I/O Bound ProcessCpu Bound Process는 Cpu 사용률과 처리량을 중요하게 여김.I/O Bound Process는 응답 속도를 중요하게 여김타임 슬라이스 값에 따른 효율 분석. (P2가 먼저 시작된다고 가정)타임 슬라이스가 100초인 경우I/O 요청이 발생하고 P1이 100초동안 실행됨. 타임 슬라이스가 1초인 경우I/O요청이 발생하고 P1이 10번 실행되면 P2의 작업이 끝나 인터럽트가 발생되고, P2는 큐에 들어감.P2는 다시 1초 실행 되고 다시 I/O 작업을 기다림.이후 계속 반속 상황 비교CPU는 쉬지 않고 일해서 CPU사용률은 100%I/O 사용률을 보면 P1이 실행되는 동안 P2의 I/O 작업이 완료된 시점부터 기다리는 시간이 발생하기 때문에 10%밖에 되지 않음.타임 슬라이스가 작기 때문에 P2가 첫번째 상황처럼 기다리며 낭비되는 시간이 거의 없음. 90%정도 나오게 됨. CPU 사용률과 I/O 사용률이 좋게 나오는 작은 크기의 타임슬라이스를 선택그리고 CPU Boud Process 타임 슬라이스를 크게 설정.운영체제 입장에서 CPU Boud Process와 I/O Bound Process 구분하는 기준CPU를 실행하는 프로세스가 스스로 CPU를 반납하면 CPU사용량이 적은거니 I/O Bound Process일 가능성이 큼.반대로 CPU를 사용하는 프로세스가 타임 슬라이스 크기를 오버해서 강제로 CPU를 뺏기는 상황이면 CPU Boud Process일 확률이 높음.우선 순위를 가진 큐를 여러가지 준비.우선순위가 높으면 타임 슬라이스가 낮고 우선순위가 낮을 수록 타임 슬라이스 크기가 커짐.타임 슬라이스 크기를 오버해서 강제로 Cpu를 뺏기면 원래있던 순위보다 우선순위가 낮은 큐로 이동.자료구조 자료구조데이터가 어떻게 저장되고 어떻게 사용되는지 나타냄.가장 간단한 자료구조는 변수, 배열알고리즘어떤 문제를 해결하기 위한 확실한 방법자료구조가 바뀌면 알고리즘도 바뀐다시간복잡도특정 알고리즘이 어떤 문제를 해결하는 데 걸리는 시간시간을 측정하는 시간이 아닌 실행시간을 예측반복문이 많아지면 시간이 늘어난다.최선의 경우 - $\varOmega$최악의 경우 배열의 길이만큼 - Big-O평균의 경우 - $\Theta$ 배열기본적으로 제공하는 자료구조일반적인 프로그래밍 언어는 배열을 선언할때 배열의 크기를 선언.운영체제는 메모리에서 해당 크기만큼 연속된 빈공간을 찾아서 값을 할당.할당하지 않은 부분은 의미없는 쓰레기 값을 전달하고, 운영체제는 배열의 시작 주소만 기억.배열의 인덱스 참조는 크기에 상관없이 한번에 찾아와서 O(1)의 성능을 갖는다.하지만, 데이터 삽입, 삭제의 성능은 좋지 않음.배열의 데이터는 메모리에 연속된 공간에 할당하고 있음.배열 크기를 넘어서 할당하게 되면 문제가 발생.배열의 끝에는 다른 데이터가 있을경우 운영체제는 다시 연속적인 크기의 메모리를 찾아서 다시 할당하고. 기존의 데이터를 복사까지 해주어야함.그렇다고 배열의 크기를 처음부터 크게 할당하면 일시적으로 해결된것 처럼 보이지만, 처음부터 공간을 크게 할당하면 배열하나의 메모리양이 커지고, 다 사용하지 않으면 공간의 낭비이다.JS의 배열은 상황에 따라서 연속적, 불연속적으로 메모리를 할당하지만 대부분 불연속적으로 할당.메모리는 내부적으로 연결하여 사용자에게는 연속적처럼 느껴지게함.장점읽기, 쓰기와 같은 참조에는 O(1)의 성능을 가진다단점크기 예측이 힘들기 때문에 메모리 낭비가 발생할 수 있다.데이터 삽입, 삭제가 비효율적이다.연결리스트(Linked List)배열의 단점을 보완.저장하는 데이터들을 메모리에 분산해서 할당하고 데이터들을 서로 연결.Node라는 것을 만들어서 수행Node의 구조데이터를 담는 변수다음 노드를 가리키는 변수연결 리스트는 첫 노드의 주소만 알고 있으면 다른 모든 노드에 접근 할 수 있음.연결이라는 특성 때문에 배열과 다른 장단점을 갖고 있음.장점중간에 데이터를 삽입(삭제)하게 되는 경우 다음 노드의 정보만 바꿔주면 되므로 간단.단점특정 인덱스의 데이터에 바로 접근이 힘듦. 첫번째 노드에서 부터 순서대로 원하는 인덱스까지 이동해야 하므로 데이터 참조는 O(n)의 성능을 가짐.배열과의 비교크기배열은 고정연결리스트는 노드를 만들어 연결해주므로 동적주소배열은 연속적으로 할당연결 리스트는 불연속적인 공간에 할당데이터 참조배열은 메모리 접근이 빠름(O(1)연결리스트는 앞에서부터 해당 노드에 접근해야 하므로 느림(O(n))삽입과 삭제배열은 모든 데이터를 옮겨야해서 O(n)의 성능연결리스트는 삽입하려는 노드까지 계속 노드를 타고가야 하므로 O(n)의 성능 스택(Stack)First In Last Out(FIFO)먼저 들어온 데이터가 마지막에, 가장 늦게 나온 데이터가 제일 앞에 있는 데이터 구조.큐(Queue)First In First Out덱(Deque)덱은 데이터를 tail, head에 삽입과 삭제가 자유로운 자료 구조해시 테이블(Hash Table)해시, 맵, 해시맵, 딕셔너리로 언어마다 다른 이름을 갖고 있음.장점빠른 데이터 읽기삽입, 삭제단점메모리를 많이 차지함.좋은 해시 함수의 구현이 필수정Set데이터 중복을 허용하지 않는 자료 구조해시 테이블을 사용. HashSet이라고 불리기도 함.

운영체제

Jaeeun Jeong

워밍업 클럽 3기 PM/PO_미션4

미션 4여러분이 맡은 프로덕트의 Opportunity Solution Tree를 만들어보세요. (맡고 있는 프로덕트가 없는 경우, 프로덕트를 하나 정해서 해 보세요) 왜 그런 Opportunity들과 Solution들을 도출했는지, 생각의 과정도 함께 적어주세요. Opportunity 및 솔루션 도출 과정블로그를 운영하면서 생각보다 뜻대로 수익 창출이 되지 않아서 어떠한 방법으로 가능할지를 생각해보았습니다.사용자 유입일단 조회수가 계속해서 발생해야한다고 생각했습니다. 사용자가 유입이 되어야 광고 노출을 통한 수익을 기대할 수도 있고, 제휴사를 통한 수익이 발생할 수 있을 거라고 생각했습니다.블로그는 컨텐츠 발행을 통해 사용자가 유입되는 것이기에 어떻게 해야 유입이 될지를 생각해보았을 때,1) 블로그는 서로이웃/이웃을 맺게되면 신규 포스트로 보여지게 됩니다. 이를 이용해서 블로그 조회수를 높힐 수 있을거라고 생각했습니다. 특히 같은 성격의 게시글을 올리는 블로거와의 이웃을 맺음으로써 그 블로거의 포스팅을 통해 어떤 식으로 포스팅 해야할지에 대한 접근 방식도 분석이 가능할 수 있을 거라고 생각했습니다.2) 검색시 보여질 수 있도록 어떤 검색어가 유입이 많이 되는지 분석을 통해 조회수를 높힐 수 있을 거라고 생각했습니다. 또한, 정보성과 후기 콘텐츠의 조회수 차이를 분석하여 어떤 쪽에 집중하여 게시글 포스팅에 대한 방향성도 잡을 수 있을 거라고 생각합니다.2.수익모델 구축조회수를 높혀 포스트내의 광고 노출 수로 수익을 낼 수 있지만 제휴 업체를 통해 체험 또는 제품 제공을 통한 비금전적인 수익 및 제품을 광고함으로써 수익을 얻을 수 있을 거라 생각했습니다. 제휴 업체를 통한 수익을 내는 경우, 협찬글과 일반 게시글의 트래픽을 비교하여 방문객의 관심도에 대한 패턴을 파악하여 협찬되는 제품의 방향을 정하여 협찬 글의 조회수도 높힐 수 있는 방법도 있을 거 같습니다. 

제갈진우

[인프런 워밍업 클럽 3기] PM/PO 특별 미션

1. 앱 선정앱 이름: 알리미 (Alami)앱 카테고리: 알람 및 수면 관리2. 신규 사용자 온보딩(Onboarding) 분석2.1 온보딩 과정앱 시작하기:"알리미 소개와 기타 등등" 메시지 노출"변화가 기대돼요" 버튼 클릭 시 알람 설정 시작시간 선택:사용자가 원하는 알람 시간 선택권한 허용하기:알림 권한 요청알람 소리 선택:다양한 카테고리의 알람 소리 제공미션 선택:알람 해제를 위한 작은 미션 선택알람 화면 선택:사용자 맞춤형 알람 화면 디자인 선택취침 리마인더 설정:취침 리마인더 설정 옵션 제공광고 권한 요청:맞춤 광고 제공 권한 요청결제 창:7일간 무료 체험 안내 및 결제 플랜 선택쿠폰 혜택:신규 유저 전용 30% 할인 쿠폰 제공2.2 온보딩 전략비주얼 및 인터페이스:직관적이고 깔끔한 UI/UX 디자인커뮤니케이션:푸시 알림으로 사용자 맞춤형 정보 제공3. 사용자 인게이지먼트(Engagement) 전략3.1 인게이지먼트 요소푸시 알림:개인 맞춤형 알람 및 취침 리마인더친구 초대 기능:친구를 초대하면 선물 같은 혜택 제공 콘텐츠 업데이트:새로운 알람 소리 및 미션 추가3.2 인게이지먼트 전략사용자 피드백:정기적인 설문조사를 통해 사용자 의견 수집사용자 맞춤형 추천:사용자의 알람 패턴 분석 후 맞춤형 알람 소리 및 미션 추천커뮤니티 참여:사용자 피드백을 위한 포럼 운영 및 소통 강화4. 성과 판단을 위한 데이터 및 지표4.1 데이터 수집 방법앱 분석 도구:Product Analytics 툴설문조사:사용자 피드백을 위한 간단한 설문조사4.2 주요 지표알람 성공률:설정된 알람에 따라 사용자가 실제로 일어나는 비율.개운함 평가:사용자에게 알람 후 개운함을 느끼는 정도를 1~5점 척도로 평가, 평균 점수 수집.사용자 만족도:앱 사용 후 만족도를 1~10점 척도로 조사, 평균 점수 수집.재사용 비율:알람 설정 후 다시 사용하는 비율.알람 해제 후 재설정 비율:사용자가 알람을 해제한 후 다시 설정하는 비율, 사용자 지속성을 나타냄.취침 리마인더 활용률:취침 리마인더 기능을 사용하는 사용자 비율, 건강한 수면 습관 유도.알람 소리 선호도:사용자가 선호하는 알람 소리의 종류 및 효과를 조사하여 인기 있는 소리 파악.앱 크래시 비율:앱 사용 중 발생하는 크래시 비율, 안정성 평가에 중요.5. 결론 및 제안인게이지먼트 강화 방안:커뮤니티 기능 추가:사용자들이 수면 팁, 알람 설정 노하우 등을 공유할 수 있는 포럼을 제공하여 방문 유도.챌린지 및 보상 시스템:사용자가 특정 목표를 달성할 때마다 보상을 제공하는 챌린지 기능을 추가하여 지속적인 방문 유도.지속적인 데이터 모니터링:알람 성공률과 개운함 평가를 분석하여 사용자 만족도를 높이는 방향으로 기능 개선.앱 방문 빈도와 커뮤니티 참여도를 모니터링하여 사용자 참여를 증진할 수 있는 방안 마련.사용자 피드백 수집:정기적인 설문조사를 통해 사용자 요구 사항 및 불만 사항을 수집하고, 이를 바탕으로 앱 개선.안정성 확보:앱 크래시 비율을 지속적으로 모니터링하여 안정성을 높이고 사용자 경험을 개선.

기획 · PM· POPMPO알라미수면관리

mvc,api

🔹1. 내용(Content)✅ 첫 번째 메서드@GetMapping("hello-mvc") public String helloMvc(@RequestParam(value = "name") String name, Model model){ model.addAttribute("name", name); return "hello-template"; } 이건 MVC(Model-View-Controller) 방식이야.클라이언트가 /hello-mvc?name=spring으로 요청하면,Model에 데이터를 담고, "hello-template"이라는 뷰(HTML 템플릿)를 반환함.즉, Thymeleaf 같은 템플릿 엔진을 통해 HTML을 렌더링해서 브라우저에 보여줌.✅ 두 번째 메서드@GetMapping("hello-string") @ResponseBody public String helloString(@RequestParam(value = "name") String name){ return "hello" + name; } 이건 API 방식이야.클라이언트가 /hello-string?name=spring으로 요청하면, 그냥 "hello spring" 이라는 순수 문자열을 HTTP 응답 바디에 직접 내려보냄.@ResponseBody가 붙었기 때문에 템플릿을 찾지 않고, 바로 응답을 문자열로 반환함.🔹2. 이유(Reason)| 항목 | helloMvc | helloString ||------------|----------------------------------------------|------------------------------------------|| 응답 방식 | HTML 템플릿 렌더링 (뷰 이름 리턴) | 순수 문자열 응답 (바디 리턴) || 목적 | 사용자에게 웹 페이지 보여주기 | API 응답 (프론트/앱 등과 통신) || 사용 기술 | Thymeleaf 같은 템플릿 엔진 | @ResponseBody, REST 스타일 || 응답 예시 | 렌더된 HTML 페이지 | "hello spring" 텍스트 그대로 |🔹3. 요약(Summary)helloMvc: 웹 페이지(HTML)를 보여주기 위한 컨트롤러. 뷰 엔진을 통해 동적으로 페이지 생성.helloString: 문자열(API 응답)을 직접 반환하는 컨트롤러. JSON이나 단순 텍스트 응답에 적합.

워밍업클럽3기_미션4_Opportunity Solution Tree

미션맡고 있는 프로덕트의 Opportunity Solution Tree를 만들어 보고, 도출 과정도 정리하여 적어보기 Opportunity Solution Tree목표 성과 정의 기능을 1개 이상 사용하는 사용자의 3일자 리텐션을 35%로 증가시키기  기회 발굴 고객의 의견 시간, 초 단위로 기기 사용 내역을 볼 수 있다는 것이 가장 특색이 있다.며칠 동안 기기 사용 내역이 삭제되어 불안하다.화면 제한 기능을 카테고리 별로 생성하여 프로필처럼 활용하고 싶다. 잠자거나 명상할 때, 화면 제한 기능을 켜두는 것이 좋다 *구글 플레이스토어에서 별점 3-5점 대의 리뷰를 정리하여 보았다. 무조건적인 비난이나 단순 기능 오류에 대한 리뷰가 대다수인 1-2점 대 리뷰는 이번 분석에는 제외하였다.  데이터 분석 및 추가 조사 결과 화면 제한 기능을 1회 사용하는 신규 사용자의 비율은 높지만, 2회 이상 반복적으로 사용하는 사용자의 비율은 1회의 10분의 1 수준이다.화면 제한 기능을 다른 기능과 결합하여 보여주는 실험에서도 사용자들은 화면 제한 기능의 첫 화면으로는 이동해도 기능을 활용하는 화면까지 깊게 들어가지 않았다.로그인 후에 메인 화면에 기기 사용 데이터가 뜨지 않으면 신규 사용자들은 대부분 이탈한다. 기회 맵핑 집중할 영역 정하기 앱을 어떻게 사용할지 모르는 것에 집중하기로 하였다. 제품의 주요 기능을 사용하지 않는 사용자는 이탈할 확률이 높으며, 앱의 기능 사용에 대한 안내를 진행하는 것은 신규와 기존 사용자 모두에게 긍정적인 영향을 미칠 것으로 보이기 때문이다.  솔루션 탐색하기  검증할 솔루션 선택 주요 기능에 대한 안내가 없는 부분 개선.기능별로 메인화면에서 툴팁을 제공하여 기능별 활성화 지표에 영향이 있는지 살펴보기주요 기능 사용에 대한 안내가 리텐션 증가에 영향을 주는 유의미한 지표인지 가장 간단하게 테스트해볼 수 있는 방안이라고 생각하여 선택하였다. 

기획 · PM· PO

codestudy

[인프런 워밍업 스터디 클럽 3기 PM/PO] 4주차 발자국

[인프런 워밍업 스터디 클럽 3기 PM/PO] 4주차 발자국  인프런 워밍업 스터디 클럽 3기 PM/PO 4주차 발자국인프런 워밍업 스터디 클럽 3기 PM/PO 4주차 발자국📚 주간 학습 내용 요약1. 제품 발견(Product Discovery)의 개념과 중요성제품 발견이란 "무엇을 만들지 결정하는 과정" (deciding what to build)많은 제품들이 stakeholder-driven, sales-driven 방식 때문에 실패함제품팀(PM, 디자이너, 엔지니어)이 단순히 요구사항 수행보다 권한과 자율성을 가져야 함구시대적 프로세스(아이디어→로드맵→요구사항→디자인→개발)를 탈피해 이터레이션이 필요2. 성공적인 제품의 4가지 필수 요소Valuable(가치): 고객이 구매하고 유저가 사용하고자 하는 제품Usable(사용성): 사람들이 사용법을 익히고 사용할 수 있는 제품Feasible(실현 가능성): 우리 기술력으로 구현할 수 있는 제품Viable(지속 가능성): 사업적으로 타당하고 규제 및 이해관계자 요구를 충족하는 제품3. 제품 발견의 두 단계 프로세스Problem/Opportunity Discovery: 어떤 문제/기회에 집중할지 찾는 과정Solution Discovery: 문제를 어떻게 해결할지, 기회를 어떻게 활용할지 찾는 과정PM은 문제 정의에, 디자이너와 엔지니어는 문제 해결에 오너십을 갖되 긴밀한 협업 필요4. 가설(Assumptions)과 검증모든 제품 개발은 여러 가정에 기반함가치(Value), 사용성(Usability), 실현 가능성(Feasibility), 사업적 타당성(Viability) 관련 가정을 검증리스크가 크고 근거가 부족한 가정부터 우선적으로 검증해야 함검증 방법: 심층 인터뷰, 사용성 테스트, 데이터 분석, 프로토타이핑, A/B 테스트 등5. 제품 발견을 위한 전략적 프레임워크기회 솔루션 트리(Opportunity Solution Tree):고객 니즈/페인 포인트/욕구를 발굴하고 그룹핑기회를 상위 기회 밑에 구조화하여 집중할 영역 선정솔루션 아이디에이션, 가설 검증 및 실행으로 진행북극성 프레임워크(North Star Framework):지표에 초점을 맞춘 제품 발견 방법론북극성 지표: 제품팀이 영향을 끼칠 수 있고 장기적 사업 성과에 도움되는 지표인풋-아웃풋 관계 파악을 통한 가설 검증 중요6. 프로덕트 그로스(Product Growth)의 이해PMF(Product Market Fit) 달성 후에야 진정한 그로스 의미 가짐그로스 워크의 4가지 영역: Feature Work, Growth Work, PMF Expansion, Scaling Work그로스 레버(Growth Lever): Acquisition(획득), Retention(유지), Monetization(수익화)7. Acquisition(고객 획득) 전략마케팅/세일즈 외에도 제품을 통한 고객 획득 방법 중요신규 고객을 충분히 많이, 비용 효율적으로 획득하는 것이 목표비용 효율성 측정 지표: CAC, LTV, Payback Period네트워크 효과, UGC(User Generated Content), 검색엔진 최적화 활용B2B 제품에서도 Product-Led Growth(PLG) 방식 확산 중제품을 통한 획득의 장점: 자연스러운 성장, 광고효과, 마케팅 비용 절감8. Retention(유지)과 Activation(활성화)"Retention is King" - 리텐션이 그로스의 핵심 요소리텐션 측정 방식: 코호트 리텐션, Day N 리텐션, Bracket/Unbounded 리텐션리텐션이 좋은 제품은 장기적으로 큰 성장 차이를 만듦Activation은 리텐션을 위한 첫 번째 레버로, 사용자가 핵심 가치를 경험하는 과정Setup → Aha → Habit Moment의 3단계 구조:Setup Moment: 사용자가 제품 가치 경험을 위한 준비 완료Aha Moment: 사용자가 처음으로 제품의 핵심 가치 경험Habit Moment: 제품의 핵심 가치 경험이 습관화유저 온보딩은 단순한 기능 소개가 아닌, 핵심 가치 경험을 돕는 전체 과정사용자 행동 모델 (Nir Eyal의 'Hooked'): Trigger → Action → Reward → Investment9. Engagement(참여도) 측정과 개선리텐션을 위한 두 번째 레버로, 사용자의 제품 사용 활발도인게이지먼트 지표:Breadth(넓이): DAU, WAU, MAU (사용자 수)Depth(깊이): 기능 사용 깊이, 사용 시간Frequency(빈도): DAU/MAU, 재방문율Efficiency(효율성): 과업 성공률BJ Fogg의 행동 모델: Behavior = Motivation × Ability × PromptMotivation(동기): 즐거움, 기대, 소속감Ability(능력): 시간, 비용, 노력 등 행동 용이성Prompt(트리거): 행동 유도 알림인게이지먼트 핵심 시스템: 알림(Trigger) → 액션(Action) → 보상(Reward) → 투자(Investment)10. Monetization(수익화) 전략어디서 수익을 얻을 것인가?: 사용자, 광고주, 제3자무엇에 대한 대가로 돈을 받을 것인가?: Value Unit 정의가격 책정 고려 요소: 비용(Cost), 경쟁(Competition), 가치(Value)Usage-Based Pricing vs Seat-Based PricingIncentive Alignment: 고객과 회사의 이익 방향 일치시키기수익 극대화 전략:무료 사용자 그룹 늘리기 (Freemium, Free Trial)사용자가 지불하고 싶게 만들기 (Perceived Value 강화)인지편향 활용하기 (앵커링, 손실 회피 등)적절한 시점에 Prompt 제공하기11. 그로스 모델(Growth Model)제품 성장 메커니즘을 도식화한 개념적 지도제품의 성장에 영향을 끼치는 요소들을 시각화그로스 모델 예시: AARRR, Growth Loop, North Star Framework정성적 모델링부터 시작하여 각 요소의 영향력 이해12. PM/PO의 팀 협업 방식Hand-Off 방식보다 Collaboration 중심으로 접근엔지니어와 협업: 스테레오타입 버리기, 기술 이해하기디자인 피드백 주기: 프로젝트 이해 → 사용자 관점 경험 → 이슈 파악 → 우선순위화시도, 회고, 개선의 사이클 구축"PM이 항상 정답을 가질 필요는 없다" - 함께 좋은 방안 찾기🌟 핵심 학습 인사이트배운 점제품 성공의 핵심은 무엇을 만들지 결정하는 Product Discovery 과정에 있음성공적인 제품은 가치, 사용성, 실현 가능성, 지속 가능성 모두를 충족해야 함리텐션은 "왕(King)"으로서 장기적 성장의 핵심이며, Activation과 Engagement를 통해 개선그로스 모델링을 통해 제품 성장 메커니즘을 이해하고 전략적으로 접근 가능PM, 디자이너, 엔지니어는 각자의 영역만 담당하는 것이 아닌 협업이 핵심적용할 점문제/기회 발견과 솔루션 발견의 두 단계로 제품 발견 과정 체계화Setup → Aha → Habit의 명확한 경로 설계로 사용자 활성화 강화리텐션 개선을 위한 인게이지먼트 지표(Breadth, Depth, Frequency, Efficiency) 모니터링제품을 통한 Acquisition, Retention, Monetization 전략 구체화디자이너, 엔지니어와의 효과적인 협업 방식 도입BJ Fogg 행동 모델을 활용한 사용자 행동 유도 설계💭미션에 대한 회고이번 미션에서는 "코촉촉" 반려동물 돌봄 서비스의 Opportunity Solution Tree를 만들어보았습니다. 처음으로 OST를 작성해보는 경험이었는데, 생각보다 복잡했습니다.제품의 근본적인 문제와 기회를 식별하는 것부터 시작해서, 가장 중요한 기회를 선택하고 솔루션을 도출하는 과정을 경험했습니다. 특히 "바쁜 현대인의 반려동물 돌봄 시간 부족"과 "낯선 사람에게 반려동물 맡기는 불안감"이라는 두 가지 핵심 기회에 집중했습니다. 어려웠던 점은 너무 많은 기회와 솔루션이 떠올라서 정말 중요한 것을 선택하는 것이었습니다. 하지만 "전략의 핵심은 무엇을 하지 않을 것인가를 정하는 것"이라는 마이클 포터의 말을 떠올리며 집중할 부분을 좁혀갔습니다.앞으로 실제 프로젝트에서 OST를 활용한다면, 더 많은 사용자 리서치와 데이터를 기반으로 기회를 발굴하고, 팀원들과 함께 더 다양한 솔루션을 도출해보고 싶습니다. -------------------------수고 많으셨습니다!

기획 · PM· PO워밍업스터디클럽3기PM

[인프런 PM/PO 워밍업 클럽 3기] 과제4: 기회-솔루션 트리 만들기

저는 담당하고 있는 프로덕트가 없어, 쿠팡 어플리케이션 리뷰를 참고하여 개선 사항을 Opportunity-Solution-Tree로 구성해 보았습니다.기회: 고객 재구매율 증가기회1 : 어플리케이션 개선리뷰를 살펴보니, 어플리케이션에 대한 불만이 아래와 같이 존재하였습니다.기회 1-1: 어플리케이션을 키지도 않았는데 창이 저절로 뜨는 현상이 있습니다. (이 내용은 정말 많았습니다..)세부 솔루션 :어플리케이션을 키지 않았는데 창이 저절로 뜨는 현상은, 개발팀에 의뢰하여 개선을 해야 하는 사항. 기회 1-2:시각 장애인 분들이 사용하실 때, 어플 보이스 어시스턴스나 토크백 스크린리더가 숫자 를 읽어 주지 않아서 불편하다는 것이었습니다. 그러나, 다른 장애인 분의 리뷰에 의하면 편리하다고 하셔서 한번 테스트를 진행해볼 내용입니다. 세부 솔루션: 장애인 분 접근성 문제의 경우 접근성 테스트를 한 뒤, 개선을 해야한다고 생각이 들었음. 다른 1급 시각장애인 분은 편리한 어플이라고 평가 하셨기 때문임.기회2: 로켓배송 관련 개선리뷰를 살펴보니, 로켓배송 관련 불만이 아래와 같이 존재하고 있었습니다:기회 2-1: 로켓와우(새벽배송)으로 주문했는데, 결제하고 보니 로켓배송으로 변경되어 있었다는 의견세부 솔루션: 새벽 배송이 불가능하게 되면 푸시 알림으로 로켓배송으로 변경 되었다고 알려주는 방법 기회 2-2: 로켓 배송 상품이 제품당 하나씩 포장이 되어 있어서, 불편하다는 의견세부 솔루션: 묶어서 배송을 받아본 경험이 있었음. 추측을 해보자면:다른 물류센터에서 오면 개별 포장으로 올수 밖에 없는 구조 인거 같았고, 다른 주문 건이면 무조건 개별로 포장되어서 옴. 그래서 생각해 볼 수 있는 솔루션은..늦게 받아도 되는 고객에 대해서는 늦게 받아도 된다는 확인을 받아서 ,일정 시간 동안 (3-40분 정도) 기다려 준 뒤에, 모아서 배송을 해 주는 것임.

DABBB

[인프런 워밍업 클럽 스터디 3기] 4주차 발자국

📖 4주차 학습 내용 요약 제품 발견어떤 제품을 만들지 결정하는 과정 제품 발견은 가설(Assumption)을 수립하고 검증하는 과정고객의 문제를 이해하고, 아이디어 및 가설을 설정한 뒤, 검증(실험)을 반복바로 실행 vs 테스트하기Risk : 틀리면 우리는 얼마나 타격을 입는지?리스크가 큰 가설은 검증해야 함Evidence : 얼마나 탄탄한 근거를 가지고 있는지?제품 발견 이전에 제품 전략(비전, 목표, 방향성)이 선행되어야 함  프로덕트 그로스더 많은 유저들이 더 활발하게 제품을 사용하도록 하여 가치를 창출하는 것Acquisition제품을 활용해서 고객 획득하기Referral : 사용자들이 다른 사용자를 초대하게 만들기제품이 광고판이 됨user generated contents로 사용자 유입 Retantion가장 중요한 그로스 레버 Activation : 신규 사용자가 제품의 핵심 가치를 빠르게 경험하도록 만들기 Engagement : 활성화 이후에도 사용자가 계속해서 서비스를 사용하도록 만들기제품의 다양한 기능을 사용, 제품에 많은 시간을 할애, 이용 빈도가 잦음, 과업 완수율이 높음Monetization누구에게서, 무엇을 대가로, 얼마를 받을 것인지, 수익 극대화는 어떻게?  그로스 모델우리 제품의 성장 메커니즘을 도식화한 것제품 성장에 영향을 끼치는 중요한 요소들이 각자 어떤 역할을 하는지 이해하기 위함  💬 회고제품을 잘 모르는 사람들이 아이디어를 내고 실패하는 경우를 몸소 체험했던 입장에서.. 고객의 문제와 제품이 고객에게 주는 가치에 대해 진지하게 고민할 수 있는 회사에서 일하고 싶다. 그러려면 내가 먼저 고객의 문제를 이해하고, 제품이 고객 문제에 기여하는 가치에 대해 고민하고, 가설 수립과 검증을 여러 번 거치며 제품 성장을 만들어내는 사람이 될 수 있어야겠지.. 강의에서 배운 내용을 이론으로만 숙지하는 게 아니라 체화해서 내 경험으로 만들 수 있는 기회가 생겼으면 좋겠다!  🔖 출처강의명 : 시작하는 PM/PO들에게 알려주고 싶은, 프로덕트의 모든 것지식공유자 : 김민우강의 링크 : https://inf.run/AUWPe 

기획 · PM· PO

szun

워밍업 클럽 스터디 3기(PM) - [미션 4] 기회 솔루션 트리 만들기

[미션 4] Opportunity Solution Tree 만들기 프로덕트 개요현재 사이드 프로젝트로 진행 중인 저의 프로젝트는 '사이드 프로젝트 팀 빌딩을 돕는 웹서비스'로, 핵심적인 특징은 다음과 같습니다.온보딩 및 프로필 작성가입 후 온보딩 과정을 통해 회원들은 기술 스택, 경력, 희망 포지션, 프로젝트 이력 등 자신의 역량을 구체적으로 기재할 수 있습니다.프로필의 공개 여부를 회원 스스로 선택할 수 있으며, 공개로 설정하면 사이트 메인 페이지(또는 검색 결과 등)에 노출됩니다.프로필 열람 및 채팅 기능 제공공개된 프로필을 다른 회원들이 열람함으로써, 적합한 협업 상대를 찾도록 유도합니다.컨택하고 싶은 인재를 발견하면, 자체 채팅 기능을 통해 직접 대화를 나눌 수 있습니다.Desired Outcome현재 프로덕트는 아직 출시 이전이기 때문에 최상단 목표를 설정할 때 유저의 유입/전환, Engagement, Retention에 집중하였습니다.가장 첫 번째로 "서비스 론칭 후 3개월 이내에 가입자 수 1000명 획득"을 최상단 목표로 설정하였습니다. Opportunity가장 첫 번째로 주요 기회들을 다음 세 가지로 설정해보았습니다.인지도 부족설명: 우리 서비스를 모르는 사람이 너무 많다. 존재 자체가 알려지지 않아 유입이 적다.가치 및 차별점 불분명설명: 사용자가 서비스에 들어와도 '이걸 왜 써야하지?'라는 물음에 즉각적인 답을 주지 못해 가입이나 실제 이용으로 이어지지 않는다.초기 네트워크의 부족설명: 서비스에 들어온 사람이 봤을 때, 이미 등록된 프로필이나 활동 중인 유저가 거의 없으면 '사람이 없네?' 하고 떠나버리는 악순환이 발생한다.위의 기회들을 다시 세부적인 기회들로 나누어보면 다음과 같습니다.1. 인지도 부족1-1. 프로덕트의 노출 부족타겟을 설정했지만 실제로 제품을 볼 수 있도록 하는 지속적인 노출 창구가 부족1-2. 바이럴/소개 동기의 부족기존 유저가 친구를 초대하거나 다른 사람에게 소개할 만한 동기가 부족2. 가치 및 차별점 불분명2-1. 서비스의 대략적인 개요를 보여줄 수 있는 랜딩페이지의 부재웹 사이트 방문자들을 후킹할 수 있는 랜딩 페이지가 없음2-2. 신뢰도/레퍼런스의 부족이 서비스를 통해 성공적으로 팀을 만든 사람이나 실제 사례가 없어 보인다. 따라서 사용자 입장에서 서비스가 유용할지 확신하기 어려움2-3. 차별화 포인트 부각의 부족기존에도 다른 팀 빌딩 서비스, 커뮤니티 등이 많을 텐데, 우리는 무엇이 다르며 더 좋은가?3. 초기 네트워크 부족3-1. 초기 사용자(Seed) 풀 미비실제 등록된 프로필이 너무 적거나, 특정 분야에만 치우쳐 있어서 전체적인 팀 빌딩이 어려움3-2. 빈약한 첫 인상새로 들어온 사용자가 메인 페이지에 프로필이 거의 없음을 발견하고 이탈로 이어지는 문제3-3. 활동 지속/재방문의 문제초기 사용자가 들어와도 한 번 둘러보고 '아직 사용자가 없네' 하고 재방문을 안 하는 문제Solution각각의 하위 기회들에 대한 솔루션들을 다음과 같이 생각해보았다.1-1. 프로덕트 노출의 부족SNS 계정 운영 및 정기 콘텐츠 발행서비스 관련 팁, 사이드 프로젝트 성공 사례 인터뷰, 그 외의 IT 지식 정보 등을 게시하여 자연 유입 유도1-2. 바이럴/소개 동기의 부족초대 기능 제공초대를 통한 가입 시, 프로모션 제공팀 빌딩 성공 사례 공유 이벤트"우리 서비스로 팀을 결성함"을 보여주는 후기나 SNS 게시물 작성 시 소정의 베네핏 제공2-1. 서비스의 대략적인 개요를 보여줄 수 있는 랜딩페이지의 부재서비스의 가치를 한 눈에 전달할 수 있는 랜딩페이지를 제작2-2. 신뢰도/레퍼런스 부족베타 테스터를 통한 성공 사례 만들기 + 후기 작성실제로 서비스를 이용한 사용자가 어떤 결과물을 냈는지, 그 과정은 어떠했는지 보여줄 수 있는 사례를 소개'완료된 프로젝트' 갤러리 구축MVP 또는 간단한 결과물이라도 "이 팀이 여기서 만나 이런 것을 만들었다"를 보여줄 수 있는 창구 만들기2-3. 차별화 포인트 부각의 부족UX 편의성, 온보딩, 원하는 인재 직접 컨택 등 특장점 어필3-1. 초기 사용자(Seed) 풀 부족오픈 베타를 진행하여 한정된 그룹을 단체 등록초반에 최소 50~100명 정도는 프로필이 작성되어 있어야 새로 온 사람이 “오, 여긴 사람이 있네”하고 가입 유지3-2. 빈약한 첫 인상가상/샘플 프로필(“테스트 사용자”)로 최소한의 목록 확보실제 사람처럼 보이는 건 아닌지 윤리적 문제를 고려해야 하지만, 적어도 ‘보여줄 데이터’가 전혀 없진 않게끔 조정3-3. 활동 지속/재방문의 문제알림/카카오톡 등으로 재방문 유도“당신이 찾는 포지션의 인원이 들어왔습니다” 등 가입자 풀이 조금씩 늘어날 때마다 알려주어 복귀 유도.Opportunity Solution Tree 그리기위의 내용들을 바탕으로 다음과 같은 기회 솔루션 트리를 그릴 수 있습니다.

기획 · PM· PO

이희은

[인프런 워밍업 클럽 스터디 3기 프로덕트 디자인] 2주차 발자국

2주차 학습1) 아이콘 컴포넌트 만들기 본격적으로 컴포넌트를 만들기 전, 아이콘 컴포넌트를 만드는 방법에 대해 배웠습니다. 강의를 듣기 전에는 flattern을 해도 원하는대로 안깨져서 의문이었는데 꼭 유니온을 해준 후 flattern을 해야하는 것을 알게 되었습니다. 깨기 전에 아이콘을 확대 및 축소하고나서 선을 정리하는 과정이 재밌었습니다2) 입력 컴포넌트 & 디스플레이 컴포넌트 만들기 1주차 이론 부분을 배울 때 state 종류들이 많이 헷갈렸었는데 실제 여러가지 상태의 컴포넌트를 만들어보니 훨씬 익히기 쉬웠습니다. 많은 컴포넌트들을 배우면서 어려운 부분들도 있었지만 기초적인 부분이니 반드시 복습을 해야할 것 같습니다. 색상 배리어블을 등록할 때 warning error 등 status 색상이 과연 어떻게 쓰일까? 생각했었는데 컴포넌트를 만들면서 어떤 상황에 쓰이는지 알게된 점도 좋았습니다.  회고좋았던 점&잘한 점: 미션을 하기 전에 강의에서 본 그대로 한 번 따라 하고나서 다시 한번 미션에서 만들어보는 방식으로 진행하니까 머릿속에 훨씬 잘 들어왔다. 아쉬운 점 : 초반에는 생각을 하면서 만들어보다가 뒤에 체력이 떨어져 따라할려고만 했던 것 같아 다시 복습을 할 필요가 있었다.

인프런프로덕트디자이너피그마디자인시스템배리어블

채널톡 아이콘