블로그

솔 (Sol)

개발 기술 스택 심볼 & 마스코트 톺아보기

‘노트북 꾸미기’ 좋아하세요? 많은 개발자들이 노트북에 자기가 쓰고 있거나 좋아하는 기술 스택 로고 스티커를 붙이며 나만의 개성을 표현하곤 하는데요. 혹시 여러분의 노트북엔 어떤 스티커가 붙어 있나요?귀엽고 멋진 건 놓칠 수 없는 개발자라면 주목! 수많은 개발자들의 마음을 사로잡은 기술 스택에 숨은 아기자기한 심볼과 마스코트 몇 가지를 가볍게 소개할게요.썸네일 속 노트북은 인프런 백엔드 개발자 제이의 노트북!지금 쓰고 있는 스택(GraphQL 등...)이나 앞으로 배우고 싶은 스택(Go 등...), “Think Twice Code Once” 같은 개발자 밈 스티커까지 컨퍼런스나 주변 개발자 분들께 받은 스티커가 붙어 있어요. 🥰프로그래밍 언어 로고/심볼자바 (Java) 모락모락 김이 나는 귀여운 커피 컵! 자바 개발자들은 인도네시아 자바 섬에서 난 원두로 만든 커피를 마시곤 했대요. 몇 시간 동안 머리를 맞대고 토의한 끝에 정한 이름이라고 합니다.파이썬 (Python)‘비단뱀’이라는 뜻의 파이썬. 심볼 속 뱀 두 마리를 찾으셨나요? 파이썬을 만든 귀도 반 로섬(Guido van Rossum)이 영국 코미디 그룹 몬티 파이튼(Monty Python)에서 이름을 따왔다고 해요.스위프트 (Swift) iOS, macOS 개발에 쓰이는 스위프트는 ‘칼새’ 혹은 ‘신속한, 재빠른’이라는 뜻의 영단어 Swift에서 따온 이름이에요. 로고 모양도 날쌘 칼새를 닮았죠? 신속함을 강조하는 스위프트의 정체성을 잘 보여주네요.코틀린 (Kotlin) 자바와 비슷하면서도 간결한 문법으로 이목을 끄는 코틀린! 코틀린을 개발한 젯브레인(JetBrains) 사의 R&D 센터가 있는 러시아 코틀린(Ко́тлин) 섬에서 이름을 따왔는데요. 자바 역시 섬 이름인 걸 보면 두 언어의 관계가 재미있죠. 심볼 역시 머리글자 K를 간결하게 변형한 모양이에요.•••다양한 기술 스택 속 귀여운 마스코트깃허브 (Github) - 옥토캣 (Octocat) 복잡한 코드를 결합하고 관리하는 깃허브의 문어 다리 달린 고양이 마스코트 ‘옥토캣’. 3개 이상의 브랜치를 결합하는 작업을 가리키는 Octopus Merge에서 영감을 얻었다고 해요.리눅스 (Linux) - 턱스 (Tux) 믿거나 말거나! 리눅스를 만든 리누스 토르발스(Linus Torvalds)는 호주 캔버라 동물원에서 펭귄에게 물어뜯겨 펭귄염(?)에 걸린 적이 있다고 해요. 리눅스 마스코트로 삼을 정도면 그만큼 강렬한 경험이었던 모양이죠? 😅PHP (PHP: Hypertext Preprocessor) - 코끼리 (ElePHPant) 대문자로 쓴 PHP라는 글자를 옆에서 비스듬히 보면 코끼리처럼 보인다는 이유로 코끼리 마스코트를 갖게 된 PHP. elePHPant라는 말장난도 왠지 귀엽지 않나요?러스트 (Rust) - 페리스 (Ferris) 최근 개발자들 사이에 코어한 인기를 끄는 언어, 러스트의 비공식 마스코트는 주황색 게 모양이죠. 갑각류(Crustacean)에서 따온 듯한 요 마스코트 덕에 러스트 개발자들은 스스로를 Rustacean이라고 부른다고 하네요.고 (Golang) - 고 고퍼 (Go Gopher) 일러스트레이터 르네 프렌치(Renee French)가 그린 고퍼는 프로그래밍 언어 Go를 상징하는 주머니고퍼(흙파는쥐) 모양의 마스코트예요. 원래는 특별히 정해진 색이 없었다가 Google I/O 2011에서 Go App Engine 런타임을 출시하면서 파란색이 되었다고 해요.안드로이드 (Android) - 안드로보이 (Androboi) 단순한 듯 귀여운 녹색 로봇 마스코트 안드로보이! 안드로이드는 버전 1.1부터 OS 버전에 따라 디저트 이름을 붙이기로 유명한데 (컵케이크, 도넛, 오레오, 롤리팝…) 디저트 모양에 따라 달라지는 안드로보이의 모습을 보는 소소한 재미도 있죠.셀 수 없이 많은 기술 스택만큼, 매력적인 심볼과 마스코트도 무궁무진한데요. 여러분이 좋아하는 기술 심볼/마스코트는 어떻게 생겼나요? 댓글로 여러분의 최애 스킬(!)의 모습을 소개해주세요. 🥰

개발 · 프로그래밍 기타javapythonswiftkotlingithublinuxphpgoandroidrust

[프로그래밍 언어의 고민] JAVA와 Python중 언어 선택하기

개발자가 되기에 앞써  나는 비전공자이였기에, 혼자서하기에 많은 어려움이 있다. 처음 접하게되는 접근성의 어려움, 동기가 없이 혼자 시작해야함의 외로움, 남들보다 늦게 시작하는 불안감등 여러 어려움들이 있겠지만,  그중 내가 가장 크게 느끼는 어려운고민은  지금 내가 하고 공부하고 있는 개발이 옳은 길일까? 에 대한 의문점이 였다.  분명 이 의문점을 해결하기에는 온라인커뮤니티로도 한계가 있으며,  양산형적인(?) 학원 같은 곳도 형식적일것 같아,  최근에 알게된 개발자 훈련캠프를 알게되어 지원하였고 운이 좋게 최종테스트까지 다달았다.    하지만, 결국 시간이 턱없이 부족하여 떨어졌다.  떨어진 이유야 여러가지가 있겠지만,(+실력이 부족한것도) 익숙하지 않았던 JAVA 로 시험을 본게 아쉬웠다. 물론 최종테스트때 java언어만 국한되어 있다보니,  더 충분히 연습했어야 했는데, 그렇지 못한점도 있지만,  어쨌든 java라는 언어는 오래되기도 했고, 대기업 및 여러 국내기업에서 많이 사용하고 있는 언어다 보니,  지금이라도 익히면 도움이 될까 하고 공부하였었다.    하지만, 떨어지고 나서야 다시한번 내가 사용할 언어에 대해 되돌아보는 시간을 가지게 되었다. 나는 원래 Python언어로 개발공부를 시작했기에, 과연 JAVA로 바꾸는게 맞는지에 대한 의문이였다. (즉, 이후부터는 필자의 개인적인 의견이 많이 들어감을 참고바람)   가장 먼저 확인한 것은 전망이였다.  확인해본 방법은 아래와 같다.  1.티오베(프로그래밍순위사이트) 1위. Python,   2위. C언어   ,3위. Java 2. 구글트랜드검색 파란색: python , 빨간색 : java 3. 레드몽크(프로그래밍 순위사이트) 2위 : python,   3위 : java    등 그외에도 여러 사이트를 참조해봤지만, 그래도 윗내용은 믿고 맡길수 있는 사이트들이다. 물론, 티오베는 세계의 숙련된 엔지니어, 교육과정등 공급 업체의 수를 기반으로 프로그래밍 언어의 인기도 중심이고, 구글 트랜드검색은 경우의 수가 너무 많으며,  레드몽크도 GitHub와 Stack Overflow를 참고하여 데이터를 제공한다.    물론, 위자료는 세계적인 데이터로, 대한민국에서 개발자로 취업을 할려면 국내에서는 대부분의 대기업들은 Java언어를 사용하고 있어 지금 당장 대기업에 취업하고 싶다면 java의 언어를 선택하는게 좋다.  하지만, 좀더 멀리 보자면 전체적으로 비중이 커져가고 있는 python을 한번 봐보자.   이미 구글에서는 C++과 python을 백엔드로 사용하고 있고,  가장 대표적인 python어플로는 인스타그램이 있다.  그리고 OTT 시장의 (Netflix)넥플릭스도 파이썬으로 서비스를 관리하고 있으며,  클라우드 서비스 (Dropbox)드롭박스도 파이썬으로 개발하였다.  국내기업에서는 요기요 서비스가 파이썬으로 개발되는걸로 알고 있다.    게다가 국내 기업에서 개발자 채용테스트로  코딩테스트를 많이 보는데, python언어도 포함되어 점점 사용범위가 확대되어가고 있음을 알 수 있다. 현재는 AI(인공지능)와 데이터엔지니어부분에서 활용도가 점점 넓어지고 있는데,  좀더 직관적으로 보자면 자동차의 자율주행이나, 드론, 선박등 모빌리티 업계에 적용되고 있고,  또, 종종 보이는 서빙로봇과 같이 로봇에서도 많이 사용하는 언어이기에  이쪽으로 관심이 있다면, python언어  선택해볼만하다.    안드로이드때문에 앱부분은 java의 언어가 더 막강하지만,  안드로이드의 내장되어있는 기능을 사용하지 않는 플랫폼이나, 커뮤니티 앱일 경우  하이브리드로 만들기 때문에 다른 언어도 사용하여 만들기 가능하다. (웹도 마찬가지) --------------------------------------------------------------------------------------------------------------- 마지막으로 정리를 해보자면,  어느새부턴가 사람이름 세글자가 한자가 아닌 순 한글로된 이름으로  바뀌기 시작했다.  아직, 한자로된 이름을 가진 사람들이 더 많지만, 앞으로 태어날 아이들의 이름이 한자로된 이름이 계속 많을거라곤 장담하기 어렵다. 상대적으로 한자가 어렵다보니, 점점 아는 사람이 적어지고 한글이 편하기 때문일 것이다.  그렇다고 한자이름이 잘못되거나 없애야한다는 뜻은 아니다.  시대적흐름이 만들고 있을뿐..    java와 python도 비슷하다고 본다.  상대적으로 java보다는 python언어가 배우기 쉽다. 사용하기도 편리하다.  그리고 세계적으로 python을 선호하는 사람들이 많아지고 있다. 코딩언어도 결국 언어이다 보니  이건 소통하는 언어가 갖는 공통적인 습성이 아닐까싶다.    난 다시 python으로 돌아가 공부를 시작하고자 한다.                                

프로그래밍 언어진로javapython내생각언어공부고민

Rojojun

[워밍업 클럽 스터디 2기::백엔드] 후기

스터디 회고4주간 스터디를 쉼없이 달려왔다.여러가지 일이 있었고, 재미있는 지점도 지루한 지점도 존재하였다.하지만 중요한 건 포기하지 않고 계속 한다 라는 가장 원론적이고 근본적인 자세다! 이미 지나간 말인데 중요한 건 꺾이지 않는 마음이라는 것 같다! 감상적인 이야기는 여기서 끝내고, 회고답게 이 스터디에서 얻어간거 추천하는 것 등등 모든 것을 빠짐 없이 기록하여 3기를 참여하고자 하는 사람들에게 도움을 주고자한다. 스터디 추천도무조건 추천한다! 다만, 끝까지 완주할 의지가 있을 경우에만 추천한다.완주라는게 어떤 사람들은 4주의 진도를 막힘없이 따라가는 것이고, 어떤 사람들은 진도가 중요한게 아니라 4주안에 어떻게든 끝내는 것이 될 수 있다.인프런에서는 4주의 진도를 막힘없이 따라가면 완주러너, 그리고 거기서 더 잘하면 우수러너라는게 있다.즉, 동기부여가 될게 두 가지가 있다는 것이다. 완주러너 & 우수러너하지만 가장 큰 동기부여는 무언가를 뛰어넘어 성장한 자기자신이지 않을까?약간 나는 애니덕후 기질이 있어서 나의 히어로 아카데미아를 좋아하는데 한계를 뛰어넘어라는 이야기를 이야기를 좋아한다.각자 외부에서 주는 동기부여가 아닌 내부에서 주는 동기부여로 한계를 뛰어넘는데 의의가 있는 것이다. 커리큘럼의 난이도또 하나 중요한거 나는 클린코드 & 테스트코드 스터디를 진행하게 되었는데, 시원하게 오픈하면 나는 2년차 백엔드 개발자다 (이번주에 진짜 2년이 되요~~!! 🥳)혹자가 봤을 땐 아닐 수도 있는데, 아직 나는 응애 아가 개발자 중 하나라는 것이다.그런 내가 보았을 때 난이도는 적절한편이다. 중립적인 단어인거 같은데, 어려운 부분은 어려웠다.쉬운부분은 쉬웠고, 그니깐 난도 조절을 정말 잘했다는 것이다... 이것은 강사님의 강의의 퀄리티가 좋다! 라는 것과 일맥상통하는데, 나는 강의에 금액 투자를 신중하게 한다.강사님들에게는 죄송한 이야기지만 어찌되었든간에 나는 소비자니깐! 소비하려는 제품이 얼마나 좋은지 봐야하는데, 확실한 제품아니면 잘 안 구매한다ㅋㅋ...그렇지만! 이번 강의는 진짜 좋다! 더 나은 백엔드 개발자를 고민하였다면 구매를 추천한다! 정리하자면Readable Code 강의는 클린코드를 읽어만 본 사람들, 혹은 적용을 하는데 많이 못하는 사람들에게 추천하는 난이도다.근데, 기본적으로 자바에 대해서 혹은 OOP에 대해서 잘 모른다하면 권장하지 않는다.https://www.inflearn.com/course/practical-testing-%EC%8B%A4%EC%9A%A9%EC%A0%81%EC%9D%B8-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EA%B0%80%EC%9D%B4%EB%93%9C/dashboardTest Code 강의는 아이러니한 부분이긴 한데, 클린코드를 읽어 보거나 회사 실무내에서 테스트코드가 없이 테스트 하는 것에 대해 한계를 느낀 개발자들에게 추천하는 난이도이다.근데, 기본적으로 다양한 테스트를 경험해보지 않는다면... 테스트코드가 얼마나 좋은지 모를지도 모른다.그냥 내 발목을 붙잡는 쓸모없는 거라고 생각할 수도?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 이건 좋아요첫번째, 강사님의 빠른 피드백과 코드 리뷰 너무 좋았다.코드 리뷰도 신청하면 대부분 다 해줘서, 진짜 너무 좋았다.이게 참 강사님 입장에서도 시간적으로 비용일텐데 이렇게 우리 수강생들에게 엄청난 투자를 해줬다는 것에 대해 압도적으로 감사를 가진다!두번째, 전반적인 운영이 매끄러웠다.'인프런에서 진행해서...' 라는 이야기를 안하고, 여타 다른 운영과 비교해 보았을 때 꽤나 괜찮은 운영이라고 느껴졌다.특히나, 디스코드 내에서 직원분들이 이것저것 질문에 대해서 답변을 빠르게 해주거나 아니면 수강생들끼리 채널을 열 수 있게 하는 그런 것들을 하나의 시스템 제도로 만들어서 참 잘 활용하는 것 같다.세번째, 동료들이 자극을 준다.물론 나는 회사동료들하고 같이해서 서로가 서로에게 자극을 주었지만, 이 스터디는 디스코드로 진행되어 자유롭게 이야기를 할 수 있다.여기서 자유롭게 이야기를 할 때 많은 사람들이 스터디 관련해서 이야기 하고 어떤 분은 공부시간 체크, 오늘 한 것 체크 등등 엄청난 분들이 있다 (이름도 외웠다 ㅋㅋㅋㅋ)사실 그 분들을 보면서 엄청 자극이 되서 나도 열심히 공부하게 되는 경우가 있었다. 이건 나빠요좋은 말만 쓰는 것은 싫다 ㅋㅋ 억까라해도 스터디의 단점으로서 장점처럼 세가지를 정할 것이다.첫번째, 야생이다.자신이 진짜 누군가 케어를 해줘야만 공부를 하는 타입이라면, 중도 포기할 가능성이 높다.특히나, 이 스터디는 본인의 의지가 중요한 것이기 때문에, 중간에 '아 밀렸어 안해 포기!' 이렇게 되는 이상 돌이킬 수 없다...두번째, 짧은 네트워킹 타임일단 네트워킹 타임이 50분이라는게 좀 아쉽다... 사람에 따라 다를 수 있는데, 나는 좀 말이 많고 다른 사람들하고 이야기 하는 것을 좋아해서 다른 사람들 그리고 다른 회사에서 어떻게 일하는지 궁금하고 그게 나의 인사이트가 되고 싶은데... 뭔가 엔진이 과열될만 하면 끝나버린다!충분히 이해할 수 있는게 한정된 시간 속에서 진행하는 거고 다 나 같은 사람일거라 생각하지 않기 때문에 이해하는 부분이다.세번째, 낯가리는 우리들...문제는 우리다! 다들 낯을 너무 많이 가린다... 스터디를 함으로서 제2차 파생된 그룹이 나오거나 하는 선순환이 많이 나와야하는데 공개적으로는 두개? 밖에 못본거 같다! 물론, 나도 이건 할 말이 없는데!다음에 스터디를 하게 된다면, 나도 낯을 안가리고 조금 주도하는 역할로 롤을 변경해봐야하지 않나 싶다! 혼자 공부하는게 아니라 같이 공부해야만 내 공부와 내 가설이 맞는지 검증이 되기 때문이다. 진짜 마지막참 우여곡절이 많은 스터디다.뭐 잘하지도 않고, 글재주도 안좋고 마지막만 사진 좀 넣었는데 ㅋㅋㅋ 평소에는 사진도 안넣는다.비효율적인 것을 극도로 자제하는 스타일이라 이런 것을 싫어한다.그런 내게 우수러너라는 상을 준 것에 대해 진짜 너무 감사하고 함께 스터디를 한 내 동료들 진짜 항상 같이 스터디 하는 동료들을 보며 느낀게, 우리가 지금은 이 자리에 있지만 앞으로 더 나아가자는 이야기를 하는데 진짜 진심이다.믿고 의지할 수 있는 동료고 더 높은 자리에서 서로를 볼 수 있을거라고 확신한다. 마지막은 우수러너로 받은 잔, 근데 하이볼을 곁들인 ㅇ_< 

백엔드인프런인프런워밍업클럽스터디2기java자바스프링

대협

[인프런 워밍업 클럽 2기 - BE] 1주차 발자국

이 블로그는 정보근님의 입문자를 위한 Spring Boot with Kotlin - 나만의 포트폴리오 사이트 만들기 강의 기반으로 코드작성과 코드설명을 적었습니다 나의 첫 인프런 블로그가 이렇게 쓰여질 줄은 몰랐다.. 그동안 인프런 강의들을 많이 애용했지만, 이렇게 블로그를 작성하지는 않아서 낯설기도 하고, 설레기도 한다.발자국 내용은 딱히 형식이 정해져 있지 않아서 발자국 쓰기 전날까지 들었던 강의들 중, 모르는 내용들을 적어서 내가 다시 봤을 때, "아 맞다!" 라는 말이 나올 정도로만 적을 예정이다! 목차모르는 내용 정리 미션 해결 과정회고   1. 모르는 내용 정리 <Gradle>Gradle : Gradle은 Groovy를 기반한 빌드 관리 도구.빌드 관리 도구 : 프로젝트 내에서 다양하게 외부 라이브러리와 로컬 레포지토리에서도 라이브러리 별로 버전 관리를 해야할 때 용이Gradle이 왜 필요할까?Gradle과 Maven 차이를 알면 Gradle이 왜 필요한지 알 수 있다.Gradlegroovy 언어를 사용한 Domain-specific-language를 사용 ( 코드가 간결)어느 task가 업데이트 되었는지 체크이미 반영된 빌드 부분은 더이상 재 실행되지 않는다. -> 빌드 시간 단축Mavenjava8용 프로젝트 관리 도구 apache의 ant 대안외부 저장소에서 필요한 라이브러리, 플러그인들을 다운로드 한 후 , 로컬 시스템의 캐시에 모두 저장그래서 왜 Gradle인데!!!Gradle은 작업 의존성을 그래프, Maven은 고정적이고 선형적 모델을 기반Gralde은 어떤 task가 업데이트되었고 안되었는지를 체크Gradle은 이미 업데이트 된 task에 대해서는 작업이 실행되지 않으므로 빌드 시간 단축빌드 설정 규모가 작으면 큰 차이를 느끼지 못하지만 규모가 크면 훨씬 Gradle의 빌드 시간이 단축된다는걸 알 수 있다. <Dependencies>Spring Web : 웹 어플리케이션을 개발하기 위한 핵심 기능 제공Thymeleaf : View Template, 동적으로 화면을 구성할 수 있게 해줌Spring Data JPA : JPA를 이요한 구현체를 더 추상화시켜 더 쉽고 간편하게 JPA를 이용 가능mysql driver : mysql를 연동할 때 필요한 dependencyh2 database : RDBMS, 테스트 단계 또는 작은 규모의 프로젝트에서 사용validation : 데이터에 대한 유효성 검증 처리를 수행Spring Security : 홈페이지에 인증 및 권한 기능을 빠르게 부여해 인증 및 권한 보호 기능을 손쉽게 추가할 수 있음. <프로그램이 시작되는 시작되는 코드>src/main/kotlin/PortfolioApplicatioin.ktfun main(args: Array<String>) { runApplication<PortfolioApplication>(*args) } Whitelabel Error Page 오류가 뜨는 이유 : 어플리케이션이 뭘 해야 할지 모르기 때문에 Whitelabel Error Page를 보내줌.(정상) <Git 용어>Git : 분산 버전 관리 시스템 ⇒ 협업을 쉽게 해주는 툴 : GitHubCommit : git에 저장하는 단계Rollback : 이력 되돌리기Branch : branch 생성 및 제거, 확인등의 기능을 하는 명령어Merge : 브랜치 병합Conflict : 충돌Repository : 원격 저장소 , 인터넷이나 네트워크 어딘가에 있는 저장소Push : 로컬 브랜치를 원격 저장소로 푸시할 때 사용하는 기본 명령어 <Git 명령어>git init : git 공간으로 초기화git status 명령어 입력시 Untracked files 라는 게 있는데 이건 git에서 따로 설정을 안한다는 소리https://www.toptal.com/developers/gitignore/ : gitignore 파일을 자동으로 만들어줌 <github에 PUSH 방법>터미널에서 git initgit remote “git 저장소”→ 인텔리제이(GUI)로 할 시에는 git → Manage Remotecommitpush <application-default.yml , application-docker.yml>profile이 default 이면, application-default.yml 파일에서 환경변수를 가져오고profile이 docker 이면, application-docker.yml 파일에서 환경변수를 가져온다. application-default.yml 파일에서 spring:jpa:hibernate:ddl-auto:create 인데왜 application-docker.yml 파일에서는 spring:jpa:hibernamte:ddl-auto:none 일까?=> application-default.yml 에서는 개발 목적으로 데이터베이스 스키마를 매번 재생성할 필요가 있지만, application-docker.yml 에서는 베포 및 운영 환경에 적합하게 데이터베이스 구조가 변경되지 않도록 하기 위한 설정 <어노테이션 정리>@Id : 해당 테이블의 PK 필드를 의미@Entity : JPA를 사용해 테이블과 매핑할 클래스에 붙여주는 어노테이션@GeneratedValue : JPA에서 Entity의 PK를 생성하여 주는 기능-> @GeneratedValue(name="member_id") : PK로 사용될 Entity의 프로퍼티에 @Id 어노테이션 선언-> @GeneratedValue(strategy=GenerationType.IDENTITY) : 기본 키 생성을 데이터베이스에 위임한다.-> @GeneratedValue(strategy=GenerationType.AUTO) : 기본값으로 DB 방언에 맞춰 자동으로 설정하여 준다.@Column : 객체 필드와 DB 테이블 칼럼을 맵핑한다.@Component : 클래스를 자동으로 빈으로 등록하기 위해 클래스 레벨에서 사용@Profile : 빈이나, 컴퓨넌트에게 프로필을 정해줄 수 있음@PostConstruct : 객체의 생성이 일어난 직 후에 초기화를 수행하는 메서드에 부착한다.@ManyToOne : 단방향 관계이고 FK관리에 있어서 가장 자연스럽다. @JoinColumn 어노테이션과 같이 쓰인다.@JoinColumn : 엔티티 테이블에 FK 칼럼을 정의해준다. 자료형뒤에 ? 는 무슨 의미일까 ?ex ) Long?자료형 뒤에 ? 가 오는 것은 Kotlin에서 사용되는 문법이고 ?를 자료형 뒤에 붙이는 방식은 nullable 여부를 나타낸다. 예를 들면 var name: String? = null 이 코드는 해당 변수 name에 null 값이 올 수도 있다는 뜻이다.  <코드 분석>var type: SkillType = SkillType.valueOf(type) : SkillType.valueOf(type) 은 type이라는 문자열을 SkillType 열거형의 값으로 변환. 만약 type이 열거형에 없는 값이면 예외 발생var cookies: String? = httpServletRequest.cookies ?.map {"${it.name}:${it.value}"} ?.toString() : httpServletRequest에서 쿠키 정보를 가져오고, 쿠키 이름과 값을 "이름:값" 형식으로 변환하는 코드var referer: String? = httpServletRequest.getHeader("referer") : HTTP 요청에서 "Referer" 헤더 값을 가져온다. 이 코드는 사용자가 어떤 페이지에서 현재 페이지로 이동했는지 나타냄@OneToManyvar details: MutableList<ExperienceDetail> = mutableListOf() : JPA 관계를 나타내고, 엔티티 간의 일대다(One-to-Many) 관계를 나타냄2. 미션미션 1과 2를 제출하는건데, 미션1은 테이블 설계하기와 깃허브 리포지토리에 프로젝트 올리기이다. 미션 1 : https://github.com/HyupTech/LMS/commit/fa47b404d36b3ce418f16213e3bb30ca96b812ed미션 2 : https://github.com/HyupTech/LMS/commit/0993897036a0e17e7a366031b950235edd5d506e   3. 회고발자국을 작성하면서 나는 이제까지 강의를 보면서 공부를 했지만 다시 한번 이렇게 정리를 해가면서 강의를 보지 않았다. 왜냐하면 시간이 너무 아까웠고, 차라리 정리하는 시간에 강의를 하나 더 보자는 마인드였다. 하지만 발자국을 써보면서 왜 이렇게 좋은걸 내가 안했을까라는 후회가 들고, 이렇게 정리를 해가면서 했으면 아마 실력이 조금이라도 더 올랐지 않았나 라는 생각이 들었다. 앞으로 발자국도 쓰고, 내가 따로 공부하고 있는것도 정리해가면서 공부를 해야겠다. 3-1. 미션 회고 이번 미션에서 처음으로 ERD를 구성하고 어디에 PK를 주고 관계 설정을 어떻게 할지에 대한 고민이 많았던 것 같다. 현재 대학교 2-2에 재학중인데 데이터베이스 과목을 수강중인데 꽤 도움이 되었던 것 같고, 백엔드 개발자가 될려면 데이터베이스 공부도 놓지 말아야겠다고 생각이 들었다. 앞으로 더 많은 미션들이 기다리고 있는데 열심히 공부를 해야겠다!   

백엔드인프런워밍업클럽백엔드발자국javakotlin

대협

[인프런 워밍업 클럽 2기 - BE] 3주차 발자국

[인프런 워밍업 클럽 2기 - BE] 3주차 발자국이 블로그는 정보근님의 입문자를 위한 Spring Boot with Kotlin - 나만의 포트폴리오 사이트 만들기 강의 기반으로 코드작성과 코드설명을 적었습니다1. controller test 코드 분석애너테이션 조사@AutoConfigureMockMvcMockMvc를 자동으로 설정해 주는 애너테이션. 이 애너테이션을 통해 HTTP 요청을 수행하고 응답을 확인할 수 있다.MockMvc 란 ?실제로 서버를 띄우지 않고 컨트롤러를 테스트할 수 있는 도구@DisplayName("Test")테스트 클래스를 시작할 때 테스트 클래스의 이름을 지정해서 테스트 리포트에 표시된다.위 코드를 실행시키면 리포트에 TEST 라는 이름으로 테스트 성공유무가 표시됨.@Configuration : Spring에서 Bean을 수동으로 등록하기 위해서 사용메서드 분석 @Test @DisplayName("Introductions 조회") fun testGetIntroductions() { val uri = "/api/v1/introductions" val mvcResult = performGet(uri) val contentAsString = mvcResult.response.getContentAsString(StandardCharsets.UTF_8) val jsonArray = JSONArray(contentAsString) assertThat(jsonArray.length()).isPositive() }api/vi/introduction을 uri 변수에 넣음.HTTP GET 요청을 보낸후, 응답을 문자열로 변환한 후에 JSONArray로 변환JSONArray의 길이가 0보다 큰지 검증, 응답 데이터가 비어 있지 않음을 확인 @Test @DisplayName("Link 조회") fun testGetLinks() { val uri = "/api/v1/links" val mvcResult = performGet(uri) val contentAsString = mvcResult.response.getContentAsString(StandardCharsets.UTF_8) val jsonArray = JSONArray(contentAsString) assertThat(jsonArray.length()).isPositive() } api/vi/links을 uri 변수에 넣음HTTP GET 요청을 보낸후, 응답을 JSONArray로 변환배열의 크기와, 그 데이터가 존재하는지 검증@Test @DisplayName("Resume 조회") fun testGetResume() { val uri = "/api/v1/resume" val mvcResult = performGet(uri) val contentAsString = mvcResult.response.getContentAsString(StandardCharsets.UTF_8) val jsonObject = JSONObject(contentAsString) assertThat(jsonObject.optJSONArray("experiences").length()).isPositive() assertThat(jsonObject.optJSONArray("achievements").length()).isPositive() assertThat(jsonObject.optJSONArray("skills").length()).isPositive() } /api/vi/resume를 uri변수에 넣음GET요청을 보낸후, 응답을 JSONObject로 변환experiences, achievements,skills를 JSONArray로 변환 후 그 값이 양수인지와 데이터가 존재하는지 검증@Test @DisplayName("Projects 조회") fun testProjects() { val uri = "/api/v1/projects" val mvcResult = performGet(uri) val contentAsString = mvcResult.response.getContentAsString(StandardCharsets.UTF_8) val jsonArray = JSONArray(contentAsString) assertThat(jsonArray.length()).isPositive() } /api/vi/projects를 uri 변수에 넣음GET요청을 보낸후 응답 본문을 JSONArray로 변환하고, 배열의 길이가 양수인지와 데이터가 존재하는지 검증private fun performGet(uri: String): MvcResult { return mockMvc .perform(MockMvcRequestBuilders.get(uri)) .andDo(MockMvcResultHandlers.print()) .andReturn() } perform(MockMvcRequestBuilders.get(uri)) : 특정 uri에 GET 요청을 보내는 코드. 서버를 띄우지 않고 API 엔드포인트의 동작을 확인할 수 있음andDo(MockMvcResultHandlers.print()) : 요청과 응답을 콘솔에 출력andReturn() : MvcResult를 반환2. 부분 코드 분석<html *lang*="ko" *xmlns:th*="<http://www.thymeleaf.org>" *th:replace*="~{presentation/layouts/layout-main :: layout(~{::#content})}">Thymeleaf 템플릿 엔진에서 레이아웃을 정의하고 해당 레이아웃을 재사용하는 방식, 템플릿 코드의 중복을 줄이고, HTML 파일 간에 공통 요소를 재사용할 수 있게 하는 것. th:replace="~{presentation/layouts/layout-main :: layout(~{::#content})}"th:replace : 다른 파일을 가져와 현재 위치에 삽입하는 기능 수행~{presentation/layouts/layout-main :: layout(~{::#content})} :~{presentation/layouts/layout-main} : layout-main.html 파일 참조:: layout : layout 이라는 이름의 fragment를 사용하겠다는 의미, 위 코드에서는 layout fragment를 가져오겠다는 뜻(~{::#content}) : id="content" 로 지정된 부분을 layout fragment의 특정 위치에 대체할 것이라는 의미3. interceptor 코드 분석@Component class PresentationInterceptor( private val httpInterfaceRepository: HttpInterfaceRepository ) : HandlerInterceptor { override fun afterCompletion(request: HttpServletRequest, response: HttpServletResponse, handler: Any, ex: Exception?) { val httpInterface = HttpInterface(request) httpInterfaceRepository.save(httpInterface) } }private val httpInterfaceRepository: HttpInterfaceRepository의존성 주입을 통해서 Repository를 사용할 수 있다.override fun afterCompletion(request: HttpServletRequest, response: HttpServletResponse, handler: Any, ex: Exception?) {afterCompletion : HTTP 요청 처리 후에 호출되는 메서드val httpInterface = HttpInterface(request)httpInterfaceRepository.save(httpInterface)request 정보를 담고 있는 httpInterface 객체를 생성 후, httpInterfaceRepository에 저장. @Configuration class PresentationInterceptorConfiguration( private val presentationInterceptor: PresentationInterceptor ) : WebMvcConfigurer { override fun addInterceptors(registry: InterceptorRegistry) { registry.addInterceptor(presentationInterceptor) .addPathPatterns("/**") .excludePathPatterns("/assets/**", "/css/**", "/js/**", "/admin/**", "h2**", "/favicon.ico", "/error") } }addInterceptors인터셉터를 등록하는 메서드registry.addInterceptor(presentationInterceptor)addInterceptor 메서드를 통해 presentationInterceptor를 등록addPathPatterns("/**")모든 요청 경로에 대해 인터셉터 적용excludePathPatterns(...) : 인터셉터가 동작하지 않도록 설정/assets/**: 정적 자원(예: 이미지, 폰트 등)./css/**: CSS 파일./js/**: JavaScript 파일./admin/**: 관리 페이지.h2**: H2 데이터베이스 콘솔./favicon.ico: 사이트 아이콘./error: 오류 처리 경로.[미션4] 조회 REST API 만들기-회고이번 미션을 하면서 @GetMapping 어노테이션에 대해서는 어느정도 이해를 할 수 있었다. 저번 발자국에서 @Id, @GeneratedValue 어노테이션에 대해서 적었지만 아직 부족하다는 걸 알 수 있었고, @ManyToOne 어노테이션에 대해 더 깊이 공부해야겠다는걸 깨달았다. 아직 Spring에 본질적인걸 이해를 못한걸수도 있는거 같다. 코드를 작성하면 할수록 더 깊게 공부를 해야했고, JAVA 문법도 다시 해야겠다는걸 뼈저리게 느끼면서 한것 같다...3주차 회고Spring은 하면 할수록 재밌는건 맞다. Test 코드를 작성할 때도 이래서 이코드가 작동이 되는것도 알 수 있고, 부분적인 걸 따로 모듈화? 해서 만드는것도 재밌다. 이번 워밍업 클럽도 곧 종료가 되는데 java의 중요성도 깨달아서 java공부도 열심히 하고, Spring에 대해서 더 깊게 공부할거다!참고로 중간점검 때 정보근님께서 내가 작성한 질문에 대해 답변을 해주신거 같다. 나의 질문은 이번 워밍업 클럽이 종료가 되면 java의 정석, spring공부를 할건데 추천해줄 강의가 있냐 라는 질문이었다. 답변은 역시 김영한님의 강의였고 다른 강의도 추천해주셨는데 이거는 확인해보고 글을 수정해야겠다...! 무튼, spring을 선택한건 잘한 일 같다...!

백엔드워밍업클럽javakotlinspringTest코드미션4회고록코드설명백엔드

실무에서 주로 사용되는 정렬 알고리즘 종류 + 장단점

퀵 정렬 (Quick Sort)장점: 평균적으로 가장 빠른 속도를 보입니다.단점: 최악의 경우, O(n^2)의 성능을 보이며, pivot을 어떻게 선택하느냐에 따라 성능이 달라집니다.병합 정렬 (Merge Sort)장점: 입력 데이터의 상태에 상관없이 일정한 성능을 보이며, 안정적인 정렬을 보장합니다.단점: 공간 복잡도가 높아서, 메모리를 많이 사용합니다.힙 정렬 (Heap Sort)장점: 최악의 경우에도 O(n log n)의 성능을 보이며, 추가적인 메모리 공간을 사용하지 않습니다.단점: 구현이 복잡합니다.삽입 정렬 (Insertion Sort)장점: 구현이 쉽고, 데이터가 이미 정렬된 경우 빠르게 정렬합니다.단점: 입력 데이터가 역순으로 정렬되어 있을 때, 최악의 경우 O(n^2)의 성능을 보입니다.선택 정렬 (Selection Sort)장점: 구현이 쉽고, 정렬 중간 과정에서 리스트를 볼 수 있습니다.단점: 입력 데이터에 민감하여, 데이터 개수가 많아질수록 성능이 떨어집니다.따라서, 문제에 따라서 적합한 알고리즘을 선택하여 사용해야 합니다. 예를 들어, 데이터가 이미 정렬되어 있을 경우에는 삽입 정렬이나 선택 정렬을 사용하는 것이 더욱 효율적입니다. 데이터가 무작위로 섞여 있을 경우에는 퀵 정렬, 병합 정렬, 힙 정렬 중에서 선택할 수 있습니다.

java

고승조

java stream 간단한 사용법 정리

필터링(filtering)Stream은 컬렉션의 요소를 필터링하는 기능을 제공합니다. filter() 메서드를 사용하여 조건에 맞는 요소만 선택할 수 있습니다.// 예시 List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); List<Integer> evenNumbers = numbers.stream() .filter(n -> n % 2 == 0) .collect(Collectors.toList()); // evenNumbers: [2, 4]  매핑(mapping)Stream은 컬렉션의 요소를 다른 값으로 변환하는 매핑 기능을 제공합니다. map() 메서드를 사용하여 각 요소를 원하는 값으로 변환할 수 있습니다.// 예시 List<String> names = Arrays.asList("John", "Paul", "George", "Ringo"); List<Integer> nameLengths = names.stream() .map(String::length) .collect(Collectors.toList()); // nameLengths: [4, 4, 6, 5]  정렬(sorting)Stream은 컬렉션의 요소를 정렬하는 기능을 제공합니다. sorted() 메서드를 사용하여 요소를 정렬할 수 있습니다.// 예시 List<Integer> numbers = Arrays.asList(5, 2, 1, 4, 3); List<Integer> sortedNumbers = numbers.stream() .sorted() .collect(Collectors.toList()); // sortedNumbers: [1, 2, 3, 4, 5] 제한(limiting)Stream은 컬렉션의 요소를 제한하는 기능을 제공합니다. limit() 메서드를 사용하여 최대 요소 개수를 제한할 수 있습니다.// 예시 List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); List<Integer> limitedNumbers = numbers.stream() .limit(3) .collect(Collectors.toList()); // limitedNumbers: [1, 2, 3]  건너뛰기(skipping)Stream은 컬렉션의 요소를 건너뛰는 기능을 제공합니다. skip() 메서드를 사용하여 처음 몇 개의 요소를 건너뛸지 지정할 수 있습니다.// 예시 List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); List<Integer> skippedNumbers = numbers.stream() .skip(2) .collect(Collectors.toList()); // skippedNumbers: [3, 4, 5]  리듀싱(reducing)Stream은 컬렉션의 모든 요소를 하나로 리듀싱하는 기능을 제공합니다. reduce() 메서드를 사용하여 컬렉션의 모든 요소를 하나의 값으로 결합할 수 있습니다.// 예시 List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); int sum = numbers.stream() .reduce(0, Integer::sum); // sum: 15  수집(collecting)Stream은 컬렉션의 요소를 수집하는 기능을 제공합니다. collect() 메서드를 사용하여 원하는 형태로 요소를 수집할 수 있습니다. // 예시 List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); Set<Integer> numberSet = numbers.stream() .collect(Collectors.toSet()); // numberSet: [1, 2, 3, 4, 5]  그룹핑(grouping)Stream은 컬렉션의 요소를 그룹핑하는 기능을 제공합니다. groupingBy() 메서드를 사용하여 원하는 기준으로 요소를 그룹핑할 수 있습니다. // 예시 List<String> names = Arrays.asList("John", "Paul", "George", "Ringo"); Map<Character, List<String>> namesByFirstLetter = names.stream() .collect(Collectors.groupingBy(name -> name.charAt(0))); // namesByFirstLetter: {J=[John], P=[Paul], G=[George], R=[Ringo]}  병렬 처리(parallel processing)Stream은 병렬 처리를 지원하여 대용량 데이터를 처리할 때 유용합니다. parallel() 메서드를 사용하여 병렬 처리할 수 있습니다.// 예시 List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); int sum = numbers.parallelStream() .reduce(0, Integer::sum); // sum: 15  

java

대협

[인프런 워밍업 클럽 2기 - BE] 2주차 발자국

이 블로그는 정보근님의 입문자를 위한 Spring Boot with Kotlin - 나만의 포트폴리오 사이트 만들기 강의 기반으로 코드작성과 코드설명을 적었습니다 이번 2주차 발자국 내용은 spring 테스트 코드에 대한 내용이 대부분이다.아무래도 Spring에서 가장 중요한 요소는 테스트 코드라고 생각되어 강의를 들으면서 썼던 TEST 코드에 대해 하나하나씩 파헤쳐 볼 예정이다 !package com.hyup.portfolio.domain.repository import com.hyup.portfolio.domain.entity.Project import org.springframework.data.jpa.repository.JpaRepository import java.util.Optional interface ProjectRepository : JpaRepository<Project, Long> { fun findAllByIsActive(isActive: Boolean): List<Project> override fun findById(id: Long): Optional<Project> } 위 코드에서 궁금한 내용은 ?[ QUESTION ] findById를 왜 override를 해서 사용하는 이유 -> JpaRepository가 이미 제공하는 메서드를 다시 선언하기 때문에 오버라이드를 해야함-> override를 활용해서 재정의 하면 기능적으로 안좋다.[ WHY ?] override를 활용해서 재정의 하면 기능적으로 안좋은 이유1. 기본 동작의 일관성 문제JpaRepository에서 제공하는 findById는 기본적인 CRUD 동작을 안정적이고 효율적으로 처리하는데, 이를 재정의하면 예상치 못한 문제를 발생시킬 수 있음.다른 개발자들이 코드를 이해할 때, 어려움을 안겨줄 수 있음2. 유지보수성 저하JPA의 업데이트나 변경 사항이 발생했을 때 호환성 문제가 발생할 가능성이 높음기능적 안정성 감소 Spring Data Jpa는 트랜잭션 관리, 데이터베이스 연결 관리, 성능 최적화 등을 내부적으로 처리. 이를 재정의 하면 내부적으로 처리되던 여러 최적화나 기능이 무시될 수 있음 [ SOLVE ] 그럼 override를 활용하지 않고 어떤 방법을 사용할 수 있나?CUSTOM Repository 사용interface ProjectRepository : JpaRepository<Project, Long> { fun findAllByIsActive(isActive: Boolean): List<Project> override fun findById(id: Long): Optional<Project> }interface CustomProjectRepository { fun findByIdCustom(id: Long): Optional<Project> } 쿼리 메서드 활용interface ProjectRepository : JpaRepository<Project, Long> { fun findAllByIsActive(isActive: Boolean): List<Project> fun findByIdAndIsActive(id: Long, isActive: Boolean): Optional<Project> }@DataJpaTest 메서드@DataJpaTest 메서드를 타고 들어가면 @Transactional 이라는 어노테이션 존재@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @BootstrapWith(DataJpaTestContextBootstrapper.class) @ExtendWith(SpringExtension.class) @OverrideAutoConfiguration(enabled = false) @TypeExcludeFilters(DataJpaTypeExcludeFilter.class) @Transactional @AutoConfigureCache @AutoConfigureDataJpa @AutoConfigureTestDatabase @AutoConfigureTestEntityManager @ImportAutoConfiguration public @interface # DataJpaTest 어노테이션이 포함하고 있는 어노테이션 이중 @Transactional 이라는 어노테이션은 테스트 메소드 하나를 하나의 트랜잭션으로 보고 메소드가 종료될 때 그 트랜잭션에서 발생한 작업들을 모두 롤백해줌 [ QUESTION ] 트랜잭션에서 발생한 작업들을 모두롤백해야 하는 이유[ ANSWER ]테스트 간 독립성 보장테스트는 독립적으로 수행되어야 하고, 하나의 테스트가 다른 테스트에 영향을 주지 않아야 함. 트랜잭션을 롤백하면, 테스트 내에서 발생한 모든 데이터 변경이 원래 상태로 돌아가기 때문에 데이터베이스 상태가 항상 초기 상태로 유지데이터 일관성 유지테스트가 끝난 후에도 트랜잭션을 롤백하지 않으면, 테스트 중에 삽입되거나 수정된 데이터가 데이터베이스에 남아 있게 된다. 이렇게 되면 이후의 테스트나 실제 어플리케이션 실행에 영향을 미쳐, 데이터의 일관성이 깨질 수 있음테스트 성능 향상테스트 중 데이터베이스에 많은 데이터를 삽입하거나 수정하는 경우, 이를 실제로 영구 저장하는 것보다 트랜잭션을 롤백하는 것이 성능 면에서 유리.인스턴스 생명주기PER_METHOD (기본값)각 테스트 메서드마다 새로운 인스턴스가 생성각 테스트 메서드는 독립적인 상태 유지테스트마다 새로운 인스턴스가 생성되므로, 테스트 클래스의 상태를 공유할 수 없고 테스트 간의 의존성도 없어야 함.@TestInstance(TestInstance.Lifecycle.PER_METHOD) // 생략 가능 (기본 값) class ExampleTest { @BeforeEach void setUp() { // 테스트 메서드 실행 전 호출됨 } @Test void testA() { // testA 실행 시 새로운 인스턴스가 생성됨 } @Test void testB() { // testB 실행 시 또 다른 새로운 인스턴스가 생성됨 } }PER_METHOD는 각 테스트마다 독립적으로 실행되어서 서로의 상태에 영향을 주지 않지만 상태를 공유하는 것이 불가능하다. 2. PER_CLASS하나의 인스턴스만 생성되고, 모든 테스트 메서드에서 이 인스턴스가 재사용된다.@BeforeAll을 사용하면 클래스 전체에서 한 번만 실행되므로 성능을 향상시킬 수 있음@TestInstance(TestInstance.Lifecycle.PER_CLASS) class ExampleTest { @BeforeAll void initAll() { // 모든 테스트 메서드 실행 전 한 번만 호출됨 } @Test void testA() { // testA 실행 시 동일한 인스턴스가 사용됨 } @Test void testB() { // testB 실행 시에도 동일한 인스턴스가 사용됨 } }PER_CLASS는 상태를 공유할 수 있어 성능이 향상되지만 테스트 간 인스턴스 상태가 공유되므로, 테스트 간 의존성이 발생함.@BeforeAll, @AfterAll@BeforeAll : PER_CLASS에서만 사용되며, 모든 테스트 전에 한 번만 실행@AfterAll : PER_METHOD와 PER_CLASS 모두에 사용되고 모든 테스트 전에 한 번만 실행 됨[QUESTION] @BeforeAll 이 PER_CLASS에서만 사용되는 이유, @AfterAll은 PER_METHOD, PER_CLASS 모두 사용가능한 이유[ANSWER]@BeforeAll은 클래스 수준에서 한 번만 실행되는 메서드. 즉 테스트 클래스의 모든 테스트 메서드가 실행되기 전에 딱 한 번 실행됨PER_CLASS에서는 테스트 클래스에 대해 하나의 인스턴스만 생성되므로, @BeforeAll 메서드가 클래스 인스턴스에서 한 번 실행되고, 이후의 모든 테스트가 동일한 인스턴스를 사용@AfterAll 은 모든 테스트 메서드가 실행된 후에 한 번만 실행되는 메서드이다. 여기서 PER_CLASS에서는 클래스 인스턴스가 하나만 생성되므로, 모든 테스트가 끝나고 한번만 호출되면 된다.PER_METHOD에서는 각 테스트마다 새로운 인스턴스가 생성되지만, @AfterAll이 테스트 메서드가 모두 끝난 후에 한 번 호출되도록 관리할 수 있다.미션 - REST API 설계 이번 미션에서는 REST API 설계하는 미션이 주어졌다. HTTP 주요 메서드 정리 (GET / POST / PUT / PATCH / DELETE)GET : 리소스 조회POST : 요청 데이터 처리, 주로 등록에 사용PUT : 리소스를 대체, 즉 덮어쓰기 수행PATCH : 리소스 부분 변경DELETE : 리소스 삭제이번 미션과 발자국을 하면서 백엔드 개발자가 HTTP 주요 메서드에 대해 집중해야 된다는 것을 알 수 있었다. api를 설계할려면 어쩔수 없이 각 HTTP 메서드에 대해 알아야 URL을 설정할 때 어떻게 만들어야 되는지를 알 수 있기 때문이다. 이번주 는 개인 일정이 너무 많아서 아쉽게도 진도를 다 따라가지 못했다. 발자국은 만들어야 되기 때문에 여기서 내가 가장 공부해볼만한 것이 TEST 코드에 대해서 조사를 하는 것이기 때문에 열심히 하였다.GET, POST, PUT, PATCH, DELETE 메서드에 대해서 조금이라도 공부할 수 있어서 좋았고, 따로 공부해서 블로그에 올려야 겠다고 생각하였다!

백엔드백엔드인프런javakotlin발자국

V_브이_v

[인프런 워밍업 클럽 스터디 2기] : 웹 개발의 첫 발자국

안녕하세요!제 첫 블로그에서는 자바 스프링(Spring Framework)을 처음 배우면서 느꼈던 점과1주차에 배운 주요 개념들을 간단하게 정리해보려고 합니다.새로운 것을 배운다는 생각에 약간 신나기도 합니다 ㅎ이번 스프링 스터디를 통해 스프링을 배우며 얻은 지식을 꾸준히 정리해 블로그에 올리는 습관을 만들어보겠습니다. 간단한 웹 이론웹 서비스는 크게 세 가지 요소로 구성됩니다: 클라이언트, 서버, 데이터베이스.- 클라이언트: 요청을 보내는 주체로, 컴퓨터나 스마트폰의 브라우저 등 사용자가 접근하는 환경입니다.- 서버: 클라이언트의 요청을 받아 작업을 수행하는 주체입니다.- 데이터베이스(DB): 데이터의 집합으로, DBMS를 통해 데이터를 관리합니다.  웹 프레임워크와 라이브러리의 차이웹 프레임워크: 웹 개발을 편리하게 도와주는 도구로, 이미 정해진 틀이 있습니다.예를 들어 이케아의 가구처럼 정해진 틀과 구성이 있다고 생각할 수 있습니다.라이브러리: 정해진 틀이 없는 도구로, 필요에 따라 사용할 수 있는 철물점의 도구와 비슷합니다. 스프링 프레임워크스프링은 자바로 만들어진 웹 프레임워크로, 다양한 주요 개념이 있습니다.MVC 패턴MVC 패턴은 모델(Model), 뷰(View), 컨트롤러(Controller)로 이루어진 소프트웨어 아키텍처 디자인 패턴입니다.- 모델: 데이터를 담는 역할을 합니다.- 컨트롤러: 클라이언트의 요청을 받아 작업을 수행하고, 결과 데이터를 모델에 담습니다.- 뷰: 사용자에게 보여지는 화면으로, 모델에서 데이터를 가져와 표시합니다. 레이어드 아키텍처- 컨트롤러: 클라이언트의 요청을 받는 인터페이스로, 데이터를 검증하고 서비스의 메소드를 호출합니다.- 서비스: 데이터 처리 로직을 수행하고, 저장소(DB)에 대한 작업을 요청합니다.- 저장소: DB에 접근하여 데이터를 처리하며, 여러 서비스에서 공통적으로 사용할 수 있는 처리 방법을 제공합니다. 스프링 빈(Spring Bean)스프링에서 관리하는 자바 객체를 빈(Bean)이라고 합니다. 스프링 빈은 스프링 컨테이너에서 생성되고 관리되며, 다음과 같은 특징이 있습니다.- 관리되는 객체: 스프링 컨테이너에서 생성되고 관리됩니다.- 재사용 가능: 애플리케이션 전체에서 재사용이 가능합니다.- 의존성 주입: 스프링이 빈들 간의 관계를 자동으로 설정해줍니다. 스프링 부트에서의 의존성 주입- 생성자 주입: 클래스 생성자를 사용하는 방식으로 가장 안전합니다.- 수정자 주입: @Autowired 같은 어노테이션을 사용하여 필드를 주입하는 방식입니다.- 필드 주입: 수정자 주입과 비슷하게 동작하지만, 의존성을 바꿀 때 문제가 생길 수 있어 신중히 사용해야 합니다. HTTP와 REST APIHTTP 메소드- GET: 리소스를 가져오는 요청- POST: 리소스를 생성하는 요청- PUT/PATCH: 리소스를 업데이트하는 요청- DELETE: 리소스를 삭제하는 요청- 오류 코드: 400번대는 클라이언트의 문제, 500번대는 서버의 문제를 나타냅니다.REST API: HTTP 통신을 통해 애플리케이션 기능을 정의하는 규칙입니다.URL을 자원으로 활용하고, HTTP 메소드를 이용해 행위를 표현합니다. JPA (Java Persistence API)JPA는 자바 객체를 DB의 테이블로 매핑해주는 기술입니다. 이를 통해 개발자는 직접 쿼리를 작성하지 않고도 객체지향적인 접근이 가능합니다.- 장점: 생산성 증가, 객체지향적 접근, DBMS 의존성 감소- 단점: 충분한 학습이 필요하고, 복잡한 쿼리를 처리하는 데 한계가 있을 수 있습니다. 느낀 점과 회고스프링을 처음 배우며 새로운 개념들을 많이 접했습니다.특히 빈과 의존성 주입 개념이 이해되면서도 어려우면서도 아리까리?합니다.직접 프로젝트에 적용해보면서 개념을 익히는 것이 가장 좋겠다고 생각했습니다.기본적인 웹 이론에 대해 잘 모르고 있던 부분이 많아 부끄럽기도 했지만, 이번 기회를 통해 기초부터 다시 다질 수 있어서 좋았습니다.앞으로도 더 많은 기능을 학습하고 블로그에 정리하며 성장해 나가고자 합니다.오늘 남은 시간을 활용해서 섹션 3의 진도를 나가고 최종장에는 개인프로젝트를 실제로 동작하게끔 만들고 싶습니다!!

백엔드javaspring스터디미션발자국백엔드

최강현

[인프런 워밍업 스터디 클럽 1기] 백엔드 2주차 발자국

Day 7. 스프링 컨테이너의 의미와 사용 방법 이 날 강의를 통해서 드디어 베일에 쌓인 의존성을 공부하는 기회가 되었다.의존성이란다음 코드를 보면 UserController의 생성자는 JdbcTemplate이라는 클래스를 필요로 하고 있다. @RestController public class UserController { private final UserService userService; public UserController(JdbcTemplate jdbcTemplate) { this.userService = new UserService(jdbcTemplate); } }이것을 어려운 말로 '의존한다'라고 한다. 스프링 빈이란스프링부트 서버를 시작할 때 자동으로 해주는 것 중 하나가 거대한 컨테이너(실제 컨테이너를 떠올리면 된다)를 만드는 것이다.이 컨테이너 안에는 클래스가 들어가게 되는데 이렇게 들어간 클래스를 스프링 빈이라고 부른다.클래스가 들어갈 때는 이 빈을 식별 할 수 있는 이름 및 타입과 다양한 정보가 들어가고 인스턴스화도 이루어진다. Day8. Spring Data JPA를 사용한 데이터베이스 조작 8일차 강의를 통해 SQL을 통해서 접근했던 DB를 자바 객체를 DB와 매핑 시켜서 사용하는 JPA를 학습하였다. JPA란객체와 관계형 데이터베이스의 테이블을 짝지어 데이터를 영구적으로 저장할 수 있도록 정해진 Java 진영의 규칙JPA는 API이기 때문에 말 그대로 규칙이고 (자바의 인터페이스와 같다) 이 규칙을 누군가는 실제로 구현을 해야한다그 구현체가 바로 Hibernate이다. Day9. 트랜잭션과 영속성 컨텍스트 9일차 강의는 서비스 계층의 남은 중요한 역할인 트랜잭션에 대해 배웠다.트랜잭션이란 쪼갤 수 없는 업무의 최소단위이다.실제로 예를 들면 인터넷 결제를 진행할 때 1. 주문 기록을 저장하고 2. 포인트를 적립해주고 3. 구매 기록을 저장해준다이 3가지의 과정을 쪼갤 수 없는 하나의 최소단위로 묶고 하나가 실패하면 다른 모든 과정도 실패해버리게 만드는게 트랜잭션이다. Start transaction -> 성공하면 COMMIT -> 실패하면 ROLLBACK 또한 영속성 컨텍스트에 관해서도 학습했는데 조금 어려워서 꼭 기억해야하는것스프링에서는 트랜잭션을 사용하면 영속성 컨택스트가 생기고, 트랜잭션이 종료되면 영속성 컨텍스트가 종료된다. 영속성 컨텍스트의 특별한 능력변경 감지 : 영속성 컨텍스트 안에서 불러와진 Entity는 명시적으로 save를 해주지 않더라도 알아서 변경을 감지하여 저장할 수 있게 해준다.쓰기 지연 : 영속성 컨텍스트에 의해 트랜잭션이 Commit 되는 시점에 SQL을 모아서 한 번만 날리게 된다.1차 캐싱 : ID를 기준으로 Entity를 기억하는 기능이다. 조금 더 복잡한 기능을 API로 구성하기 10일차는 앞서 배운 것들로 JPA를 이용해서 책 생성, 대출, 반납 API를 개발해보았다. 과제 과제 4일차https://devnter.tistory.com/entry/%EC%9D%B8%ED%94%84%EB%9F%B0-%EC%9B%8C%EB%B0%8D%EC%97%85-%ED%81%B4%EB%9F%BD-1%EA%B8%B0BE-4%EC%9D%BC%EC%B0%A8-%EA%B3%BC%EC%A0%9CqueryForObject() 에 대한 학습이 필요. 과제 5일차https://devnter.tistory.com/entry/%EC%9D%B8%ED%94%84%EB%9F%B0-%EC%9B%8C%EB%B0%8D%EC%97%85-%ED%81%B4%EB%9F%BD-1%EA%B8%B0BE-5%EC%9D%BC%EC%B0%A8-%EA%B3%BC%EC%A0%9C주어진 코드를 클린코드로 리팩토링하는 과제를 수행하였다.클래스를 나누기에는 너무 작은 기능이라 생각해서 읽기 좋은 코드로만 수정한다는 생각으로 수정했는데나중에 금요일에 코치님이 따로 열어주신 특강에서 테스트를 하기 위해 역할 별로 클래스를 쪼개고 테스트를 하는 강의를 진행 해 주셔서 새로운 내용에 대해 학습하는 기회가 되었다리팩토링 전에는 테스트를 작성하자! (Junit5, assertj)given / when / then 패턴전략 패턴 (= NumberGenerator의 인터페이스화 + 구현체 갈아끼우기)일급컬렉션MVC 패턴출처 https://www.inflearn.com/course/%EC%9E%90%EB%B0%94-%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8-%EC%84%9C%EB%B2%84%EA%B0%9C%EB%B0%9C-%EC%98%AC%EC%9D%B8%EC%9B%90# 아쉬운점좀 더 추가적인 학습(모르는것에 대한 학습)을 하려고 했는데 나태해져서 진행하지 못했다. 다음 마지막 주차는 좀 더 내가 모르는 내용에 대해 민감하게 반응해서 학습 하거나 학습 하지 못한다면 따로 블로그나 노션에 기록해서 추후 공부할 수 있도록 하겠다. 

백엔드인프런워밍업클럽자바스프링javaspring

최강현

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

강의 수강,과제 수행하면서 생겼던 궁금증을 해결하는 과정을 위주로 블로그 글을 작성하려고 합니다. 강의 수강 1일차 - OT 인프런 워밍업 클럽 스터디 및 일정 소개 코치님과 구글 밋을 통해 온라인 OT를 진행하였습니다.간단한 스터디 과정 및 일정에 대해 소개 해줬고, 코치님이 이거까지 알아야하나? 라는 주제로 의견을 공유해주셨습니다. 2일차 - 서버 개발을 위한 환경 설정 및 네트워크 기초 (1강 ~ 5강)2일차에는 서버, 네트워크, HTTP, API를 배웠다.API가 무엇인지 잘 몰랐는데 Input을 주면 OutPut이 나오는 함수와 비슷하다는걸 알게 되었다. API가 무엇인지 와닿지 않았는데 감을 잡을 수 있었다3일차 - 첫 HTTP API 개발 (6강 ~ 10강)GET API와 POST API를 개발해봤다.GET 요청은 쿼리를 통해서 요청을 주고 POST 요청은 body를 통해 요청을 주는데@RequestParam을 통해 주어지는 쿼리를 함수 파라미터에 넣는다.파라미터 대신에 DTO 객체를 넣어서 쿼리를 받을 수 있다public class CalculatorAddRequest{ private final int number1; private final int number2; public CalculatorAddRequest(int number1, int number2) { this.number1 = number1; this.number2 = number2; } public int getNumber1() { return number1; } public int getNumber2() { return number2; } }  post 요청은 body로 들어오는 JSON을 DTO로 바꿔주기 위해 @RequestBody를 사용해야하는데@RequestBody를 사용하면 DTO 객체에 생성자를 만들지 않아도 괜찮은데 이 이유가 궁금했다public class CalculatorMultiplyRequest { private int number1; private int number2; public int getNUmber1(){ return number1 } public int getNumber2(){ return number2; } }다음과 같은 이유를 찾을 수 있었다.Spring의 동작 방식: @RequestBody 어노테이션이 적용된 메서드 파라미터에는 HTTP 요청의 본문을 기반으로 객체가 생성됩니다. Spring은 이를 위해 클래스의 기본 생성자를 호출하여 빈 객체를 생성하고, 요청의 본문에서 추출한 데이터를 객체에 설정합니다.4일차 - 기본적인 데이터베이스 사용법 (11강 ~ 13강) MySQL의 사용법을 배웠다DDL(데이터 정의어) - CREATE, ALTER, DROPDML(데이터 조작어) - INSERT, UPDATE, SELECT, DELETE이 2개를 사용해서 데이터를 DB에 생성, 조회, 갱신, 삭제하고5일차 - 데이터베이스를 사용해 만드는 API (14강 ~ 16강)이 강의를 통해 사람이 직접 DB에 접속해서 DB를 조작하는게 아닌 Spring 서버가 MySQL DB에 접근해서 DB를 조작하게 API를 만들었다. 6일차 - 클린코드의 개념과 첫 리팩토링(17강~ 18강) 이 강의를 통해 저번 강의를 통해 만든 컨트롤러 클래스를 3개의 클래스로 쪼개 보았다.Controller 클래스 - API의 진입 지점으로써 HTTP Body를 객체로 변환Service 클래스 - 분기처리 로직Repository 클래스 - SQL을 사용해 실제 DB와의 통신을 담당 컨트롤러 클래스 작성 시 JdbcTemplate 객체를 생성하는데 new 키워드를 사용하지 않고 생성했다이게 어떻게 가능한지 궁금해서 찾아보니스프링에서는 보통 dependency injection을 사용하여 객체를 주입합니다. 이 코드에서도 JdbcTemplate jdbcTemplate는 생성자를 통해 주입됩니다.생성자 public UserController(JdbcTemplate jdbcTemplate)에서 JdbcTemplate 객체가 주입됩니다. Spring이 UserController를 생성할 때, 필요한 JdbcTemplate 객체를 찾아서 자동으로 주입해줍니다. 이것이 Spring의 IoC (Inversion of Control) 컨셉입니다.따라서 new 키워드를 사용하여 직접 객체를 생성할 필요가 없고, Spring이 해당 객체를 관리하고 주입해줍니다.미션1일차어노테이션을 미리 정의 해두면 @RequestParam 같은 한 단어만 작성해주면 스프링이 알아서 GET 요청의 쿼리를 메서드의 파라미터로 바꿔준다.어노테이션은 이런 마법 같은 일을 해준다.  2일차문제1Controller에서 getter 메서드가 있는 객체를 반환하면 반환 값이 JSON으로 반환 한다! CalculatorResponse.java public class CalculatorResponse { private int add; private int minus; private int multiply; public CalculatorResponse(int num1, int num2) { this.add = num1 + num2; this.minus = num1 - num2; this.multiply = num1 * num2; } public int getAdd() { return add; } public int getMinus() { return minus; } public int getMultiply() { return multiply; } }  ExController.java@RestController public class ExController { @GetMapping("/api/v1/calc") public CalculatorResponse plusMinusMultiplyCalculator(@RequestParam int num1, int num2) { return new CalculatorResponse(num1, num2); } } Response문제2ExController.java@RestController public class ExController { @GetMapping("/api/v1/day-of-the-week") public DateResponse dayOfTheWeek(@RequestParam String date) { return new DateResponse(date); } } DataResponse.java public class DateResponse { private Enum<DayOfWeek> dayOfTheWeek; public DateResponse(String date) { LocalDate parsed = LocalDate.parse(date); this.dayOfTheWeek = parsed.getDayOfWeek(); } public Enum<DayOfWeek> getDayOfTheWeek() { return dayOfTheWeek; } }  GET 메서드에서 파라미터의 value의 타입은 문자열로 들어오므로 DateResponse의 생성자에서 LocalDate.parse()를 통해 문자열을 LocalDate로 바꿔주었다. 문제3 ExController.java@RestController public class ExController { @PostMapping("/api/v1/multi-number-sum") public int multiNumberSum(@RequestBody CalculatorMultiNumber request) { int[] numbers = request.getNumbers(); int sum = Arrays.stream(numbers).sum(); return sum; } } CalculatorMultiNumber.javapublic class CalculatorMultiNumber { int[] numbers = new int[5]; public int[] getNumbers() { return numbers; } } ResponseResponse크기가 5개인 배열을 선언 하고 body에 길이가 6개를 리스트 넣고 요청해도 6개의 값을 반환한 값을 돌려준다.왜 그런지 이유를 찾고 싶었는데 못찾았다 ㅠㅠ 3일차람다식은 익명 클래스를 좀 더 쉽게 쓸 수 있게 자바8부터 도입된 개념이다. OOP인 자바는 람다식의 도입으로 함수형 프로그래밍도 가능해졌다하루에 몰아서 적으려니까 너무 힘들었다 다음주 회고록은 따로 초고를 그날 그날 적어놔야겠다..이 블로그에 올린 코드와 문제의 출처는 https://www.inflearn.com/course/%EC%9E%90%EB%B0%94-%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8-%EC%84%9C%EB%B2%84%EA%B0%9C%EB%B0%9C-%EC%98%AC%EC%9D%B8%EC%9B%90입니다  

백엔드java인프런워밍업클럽스프링spring자바

[인프런 워밍업 클럽] 4일차 과제

진도표 4일차와 연결됩니다우리는 GET API와 POST API를 만드는 방법을 배웠습니다. 👍 추가적인 API 들을 만들어 보며 API 개발에 익숙해져 봅시다!CREATE TABLE fruits ( id INT AUTO_INCREMENT, name VARCHAR(255), warehousingDate DATE, price BIGINT, PRIMARY KEY (id) );import java.time.LocalDate; public class FruitCreateRequest { private String name; private LocalDate warehousingDate; private long price; public String getName() { return name; } public LocalDate getWarehousingDate() { return warehousingDate; } public long getPrice() { return price; } } import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import java.sql.Date; @RestController public class FruitController { private final JdbcTemplate jdbcTemplate; public FruitController(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } @PostMapping("/api/v1/fruit") public void saveFruit(@RequestBody FruitCreateRequest request) { String sql = "INSERT INTO fruit(name, warehousingDate, price) VALUES(?, ?, ?)"; jdbcTemplate.update(sql, request.getName(), Date.valueOf(request.getWarehousingDate()), request.getPrice()); } } long을 사용하는 이유는 큰 숫자 범위를 처리하기 위해서이다. @PutMapping("/api/v1/fruit") public ResponseEntity<String> markAsSoldOut(@RequestBody Map<String, Long> body) { Long id = body.get("id"); if (id == null) { return ResponseEntity.badRequest().body("id 누락"); } String sql = "UPDATE fruits SET status = 'soldout' WHERE id = ?"; jdbcTemplate.update(sql, id); return ResponseEntity.ok("'soldout'"); }   @GetMapping("/api/v1/fruit/stat") public Map<String, Long> getSalesStat() { String salesAmountSql = "SELECT SUM(price) FROM fruits WHERE status = 'soldout'"; String naoSalesAmountSql = "SELECT SUM(price) FROM fruits WHERE status IS NULL OR status != 'soldout'"; Long salesAmount = jdbcTemplate.queryForObject(salesAmountSql, Long.class); Long naoSalesAmount = jdbcTemplate.queryForObject(naoSalesAmountSql, Long.class); Map<String, Long> result = new HashMap<>(); result.put("salesAmount", salesAmount != null ? salesAmount : 0); result.put("naoSalesAmount", naoSalesAmount != null ? naoSalesAmount : 0); return result; }

백엔드java

[인프런워밍업클럽][BE] 과제 3 | Lambda 식

1. 람다식(Lambda Expression) 이란?: 익명함수를 생성하기 위한 식 (Annoymous Function, 익명함수)1.1 람다식의 등장 배경- 복잡한 요구사항을 처리하기 위해 기존 Java 문법으로는 Method 사용이 늘어나는 등 코드의 복잡도가 높아짐- 메소드의 제한적 사용 - 객체를 통한 접근만을 허용 - 메소드 자체를 변수로 사용 불가 1.2 람다식 특징- 익명 함수 : 식별자없이 실행가능한 함수 (메소드명이 없음)- 간결한 문법- 함수형 인터페이스 지원1.3 람다식의 장/단점(1) 장점- 코드의 간결성 : 불필요한 반복문의 삭제 가능- 지연연산 수행 : 불필요한 연산 최소화- 병렬처리 기능 : 멀티쓰레드 활용- 가독성 향상 : 코드가 실제로 수행하고자 하는 로직이 추상적으로 드러남(2) 단점- 호출을 위해 직접 메소드를 불러야 함 : 람다식 생성 및 전달이 간결한 것과는 달리, 람다식 실행 시 인터페이스에 선언된 메소드 호출이 필요- 재귀 람다식 호출의 어려움 2. 람다식의 사용2.1 람다식 기본기본 형태 : 인터페이스 객체 변수명 = (매개변수, ..., 매개변수) -> {함수몸체;}구성요소매개변수 : 메소드 매개변수(parameter)하나일 경우 매개변수 또는 매개변수를 감싸는 () 생략 가능 (둘 다 생략은 안됨)화살표 : 코드 블럭을 실행(호출)메소드 구현부 (함수몸체) : {}함수몸체가 단일 실행문이면 {} 생략 가능단, 함수몸체가 return 문으로만 구성되어 있으면 {} 생략 불가 2.2 람다식 예제(추가 필요) 2.3 람다식 해석(1) 13강. GET API 람다 식 적용 전RowMapper = PreparedStatement + ResultSetJdbcTemplate.query()와 연동하여 사용SQL문의 결과값 각 행을 원하는 자료형으로 변환 : 즉, 각 행의 각 열(column)과 java 코드의 변수를 매핑시켜 줌.아래 코드에서 함수의 흐름은 다음과 같다각각 다음의 형식으로 매핑시킴long id : id bigintString name : name varchar(20)int age : age intreturn 시에는 method에서 반환값을 List<UserResponse>로 정의했으므로 UserResponse 생성자를 이용하여 구성 @GetMapping("/user") public List<UserResponse> getUsers(){ //1. SQL 조회 String sql = "SELECT * FROM users"; //2. JDBC 연결, 처리 return jdbcTemplate.query(sql, new RowMapper<UserResponse>() { @Override public UserResponse mapRow(ResultSet rs, int rowNum) throws SQLException { long id = rs.getLong("id"); String name = rs.getString("name"); int age = rs.getInt("age"); return new UserResponse(id, name, age); } }); } (2) 13강. GET API 람다 식 적용 후람다식 적용전에 비해 짧아졌으며, 중요한 부분 (매핑되는 부분)이 강조되어 보임.람다식매개변수 : rs (=ResultSet), rowNum함수본체 : 각각 java 변수와 sql 결과를 매핑시킴그러나 여전히 rs = ResultSet 이고, RowMapper 인스턴스를 사용한다는 걸 어떻게 인지하는 건지 모르겠음. @GetMapping("/user") public List<UserResponse> getUsers(){ String sql = "SELECT * FROM user"; return jdbcTemplate.query(sql, (rs, rowNum) -> { long id = rs.getLong("id"); String name = rs.getString("name"); int age = rs.getInt("age"); return new UserResponse(id, name, age); }); } 참고자료Lambda https://blog.naver.com/hj_kim97/222318922263https://blog.naver.com/it_jh/223356024460https://blog.naver.com/krkarma777/223278551937RowMapperhttps://blog.naver.com/3723578/223258910909https://mincanit.tistory.com/13

인프런워밍업클럽인프런워밍업클럽BEjavalambda식

java 파일이 누워서 업로드 됨

우리 회사는 문자발송 시스템 회사다.포토문자를 보냈는데 문자가 누워서 발송된다고 문의가 들어왔다.확인해보니 진짜 누워있다.이미지 리사이징 하는 부분에서 에러가 나는것 같아서 확인해봤는데 자바에서 파일을 읽어올때부터 파일에 가로 세로 사이즈가 바뀌어서 들어왔다.모바일에서 찍은 이미지는 그럴수도 있다그런다.private BufferedImage makeThumbnail(MultipartFile mFile) throws Exception { File imageFile = multipartFileToFile(mFile); //multipartFile To File int orientation = 1; Metadata metadata; Directory directory; try { metadata = ImageMetadataReader.readMetadata(imageFile); directory = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class); if(directory != null){ orientation = directory.getInt(ExifIFD0Directory.TAG_ORIENTATION); } }catch (Exception e) { orientation=1; } BufferedImage bfImage = ImageIO.read(imageFile); switch (orientation) { case 1: break; case 3: bfImage = Scalr.rotate(srcImg, Scalr.Rotation.CW_180, null); break; case 6: bfImage = Scalr.rotate(srcImg, Scalr.Rotation.CW_90, null); break; case 8: bfImage = Scalr.rotate(srcImg, Scalr.Rotation.CW_270, null); break; default: orientation = 1; break; } if (imageFile.exists() && !imageFile.delete()) { throw new IOException("Failed to delete image file: " + imageFile.getAbsolutePath()); } return srcImg; }회전 정보를 가져와서 맞춰주는 방식으로 해결했다.3시간 정도 찾은것같다.재미있었다.-끝-

java

스프링 핵심원리 기본편(김영한) 1 - 객체지향 DIP와 스프링 DI, IoC

  객체는 객체와 끊임없이 상호작용한다. 그렇기에 유연한 변경이 가능해야한다. 예를 들어, 자동차라는 상위 클래스를 다양한 자동차 브랜드로 구현될 수 있고, 운전자가 변화해도 자동차는 영향을 받지 않는다. 사용자, 주문, 할인 등 여러 독립적인 특징을 가진 기능은 클래스로 분리하여 각 클래스에서만 수정 및 사용한다.   역할과 구현을 분리 - 인터페이스와 콘크리트 클래스 인터페이스는 안정적이게, 확장이 무한대로 가능하게 설계해야한다.   SOLID 객체지향 설계 원칙 1. SRP 단일책임원칙 - 변경이 용이한 단위적 책임인가2. OCP 개방폐쇄원칙 - 코드의 변경 없이 확장이 가능한가(조립만으로 변경)3. LSP 리스코프 치환 원칙 - 하위 클래스는 인터페이스(상위 클래스)를 위반하지 않아야한다4. ISP 인터페이스 분리 원칙 - 여러 개의 인터페이스를 통해 명확한 기능을 갖고 있고, 대체 가능성이 높은 환경을 구현할 것5. DIP 의존관계 역전 원칙 - 추상화에 의존할 것, 인터페이스(역할)가 중심이 되어야한다. 구현체에 의존하면 다형성을 잃는다(재활용성을 잃는다) 스프링 컨테이너에 객체 지향 적용 객체를 생성하는 역할과 객체를 실행하는 역할을 분리.의존은 인터페이스로 하고, 설정 파일을 통해 구체적인 구현체를 의존 주입구현체 변경 시 설정 파일만 변경하면 된다.(조립)=> 제어의 역전; 어떤 구현체를 사용할 것인지 AppConfig(Spring)가 결정한다. 동적인 인스턴스 의존관계    

객체지향javaSOLIDspringDIIoCDIP강의김영한

객체 지향 프로그래밍 입문(최범균) 2 - 다형성, 추상화, 조립

  다형성이란, 여러 모형으로 변화하는 것이다. 하나의 객체가 여러 타입을 갖는 것이다. 추상화란, 특정한 성질(interface) 또는 공통 성질(abstract, 일반화)을 뽑아내는 과정이다. 추상화를 통해 객체는 다형적인 모형을 변화 가능하다   <추상화 시점> 추상화는 의존 대상이 변경하는 시점에 추가한다. 실제 변경 및 확장이 일어날 때 공통점을 파악하고 뽑아낸다.   <추상화 예시> 클라우드 파일 관리 기능이 있고, 대상 클라우드의 종류가 n가지일 경우.클라우드 종류에 따라 if문으로 분기하는 로직이 아닌 공통기능인 클라우드 파일 시스템을 추상화한다.클라우드 파일 시스템에서는 파일 목록과 관련된 CRUD 기능을 추상화하고,클라우드 파일에서는 개별 파일의 CRUD 기능을 추상화한다. 특정 클라우드 구현체에서는 추상 클래스를 상속받아서 기능을 재정의한다. 추상화가 진행되면, 구현 클래스의 변경은 있더라도(조립) 서비스 로직은 바뀌지 않는다.   <상속보다는 조립> 상속을 통해서 재사용을 하게 된다면,1. 상위 클래스의 변경이 어렵고2. 기능과 확장이 필요한 만큼 클래스가 증가하고3. 상속을 오용하게 된다.(비슷한 메서드 착오) 상속은 하위타입일 경우에 진행하고, 보통의 경우 객체를 참조하는 방식으로 진행할 것.    

java객체지향최범균강의추상화다형성조립객체참조

객체 지향 프로그래밍 입문(최범균) 3 - 분리, 의존 주입, DIP

<역할과 기능 분리 방법> 1. 패턴 적용 전형적 분리(아키텍처, 디자인패턴) 2. 계산 분리 로직의 기능화 3. 연동 분리 클래스 분리 4. 연속적인 if-else는 추상화 고민할 것   적절한 역할 분리는 테스트도 용이하게 한다.사용자와 직접적으로 관련된 기능은 내부 메서드로, 간접적으로 관련있는 기능은 별도의 클래스로 분리한다.   <의존> 순환 의존은 변경이 연쇄적으로 전파된다. 기능 변경의 파장이 커지면 안 좋기 때문에 의존은 적을수록 좋다. 의존대상의 기능이 많은 경우 클래스로 분리하거나 단일 기능으로 묶을 수 있는지 확인하라. 예를 들어 민원팩토리, 민원리포지토리를 민원등록으로 묶기   <스프링 의존 주입> 추상적 인터페이스를 의존하고, 의존 주입은 보통 생성자 방식으로 외부(스프링)에서 진행한다. 내부에서 new()로 생성하는 것과 반대이다. 1. 의존 대상이 바뀌면 그 대상을 조립하는 부분만 수정하면 됨 2. 대역 객체를 통해 테스트가 가능하다   <DIP 의존 역전 원칙> 고수준 모듈(기대수준), 저수준 모듈(단위적 실제 행위) 고수준 모듈을 의존해야한다. 반대로 고수준 모듈이 저수준 모듈을 의존하는 경우, 저수준 모듈이 변화할 때 고수준 모듈에 영향을 끼침 (목표를 향해 개발하는 것이 아닌, 개발에 따라 목표가 변하는 현상)고수준 모듈을 구현한 추상타입(인터페이스)을 저수준 모듈이 의존하는 방식을 추구해야한다.    

java강의최범균DIPDIinterface분리객체지향

객체 지향 프로그래밍 입문(최범균) 1 - 객체지향, 캡슐화

좋은 코드란, 낮은 비용으로 변화할 수 있는 코드이다 이것은 1. 캡슐화 2. 추상화(다형성 지향)로 이루어낼 수 있다.   절차지향적 코드는 진행될수록 여러 조건문으로 복잡해질 수 있다. 객체지향적 코드는 객체가 제공하는 기능(메서드)이 중심이 되어 설계하는 것이다.  - 호출, 리턴, 익셉션 등의 메세지의 교환 - 데이터 클래스(VO, DTO)는 객체가 아니다. 객체의 기능이 없이 값에만 접근하기 때문이다.   캡슐화는 데이터와 관련된 기능을 묶는 것이다. 데이터의 상세 내용을 외부에 감추고, 외부와 무관하게 객체 내부의 구현 변경이 가능하다. 객체의 기능을 비즈니스 로직이 아닌 객체 내부의 메서드로 구현하면, 기능에 변화가 요구될 때 해당하는 내부 기능을 변경하면 캡슐화를 사용한 곳에 별도의 수정이 필요하지 않다.   캡슐화의 규칙 1. 데이터를 요구하는 것이 아닌 데이터의 처리를 요구할 것if(member.getAge() > 19) Xif(member.isAdult()) O 2. 메서드에서 생성한 객체의 메서드만 호출할 것파라미터로 받은 객체의 메서드만 호출할 것필드로 참조하는 객체의 메서드만 호출할 것 >> 연속적인 메서드 호출이 아닌 객체에 있는 하나의 메서드로 처리member.isAdult() + member.isVIP() + member.addCoupon()으로 하나씩 처리하는 것보다member.receiveBenefits()로 위 세 개 기능 묶기     객체는 속성과 기능으로 구성되어있다. 객체의 여러 기능을 참조하고 묶어서 새로운 기능에 사용하는 것은 객체 지향적인 방식이다.        

java객체지향최범균강의캡슐화DDD

대근

반려동물 시장 진출 웹&앱 스프링 개발자 모집

반려동물 시장 진출 웹&앱 스프링 개발자 모집   안녕하세요 현재 서로 믿을 수 있는 스타트업 멤버 구축 되었고 추가로 능력있고 참하신 스프링 개발자 팀원 찾습니다. 현재 모두 메인 잡은 있는 상황이고 사이드 프로젝트로 운영중이라 부담없이 참여 가능합니다. 관심있으신분 연락 부탁드립니다   1. 주제소개: 반려동물 서비스 중 현재 시장에 없는 서비스 2. 현재 진행 단계: 시장분석 및 명확한 주제와 컨텐츠 방향성까지 잡은 상태 3. 모집분야 및 주요업무: 앱 개발자-하이브리드 앱 (웹앱을 네이티브 형태로 감싼 형태) 유사사이트: https://www.pet-friends.co.kr/main/tab/2 4. 모집경력 및 필요스킬: 앱개발 관련하여 경력이 있거나, 최소 스프링을 자유롭게 다룰 수 있는 스킬 필요 vue.js 옵션,java 등 5. 참고기타사항: 기획/디자인/개발/마케팅 포지션 다 구성되어 있으나, 추가 개발자 필요한 상황 6. 문의/연락: 010-4590-4917 카카오: antoniobae1 참고url:IT 웹 앱 마케팅 개발 창업모임 파랑새(Since 2021.10.02 : 네이버 카페 https://cafe.naver.com/lastpick1004 https://lastpick.modoo.at/ https://www.youtube.com/channel/UCpLCToWUvdjsPqkLRZ-wpZA   이 외 어떤 직군이라도 관심있으신 분은 연락 바랍니다.

모바일 앱 개발springjavavuejs

채널톡 아이콘