-
Notifications
You must be signed in to change notification settings - Fork 0
/
content.json
1 lines (1 loc) · 458 KB
/
content.json
1
{"meta":{"title":"Seha's Devlog","subtitle":"Seha 개발 블로그","description":"Junior Developer","author":"Sehajyang","url":"https://sehajyang.github.io","root":"/"},"pages":[{"title":"","date":"2019-07-15T14:11:55.604Z","updated":"2019-07-15T14:11:55.604Z","comments":false,"path":"categories/index.html","permalink":"https://sehajyang.github.io/categories/index.html","excerpt":"","text":""},{"title":"about","date":"2019-09-29T08:29:11.000Z","updated":"2021-06-20T07:16:11.724Z","comments":false,"path":"about/index.html","permalink":"https://sehajyang.github.io/about/index.html","excerpt":"","text":"안녕하세요 저는 백엔드 개발자입니다.종종 세미나와 밋업등에 참가하고 있으며 토이프로젝트는 GitHub 에서 좀 더 자세하게 보실수 있습니다. Skill SetStack ShareJava / Python / ScalaSpringboot / Sanic / Flask / Akka HTTPJPA / QueryDSL / HibernateJunit 4,5 / Mockito / SpockMySQL / RedisMSA(Netflix OSS)AWS / DockerJenkinsLinuxGit Work Experience2021.02 ~ now / Market Kurly Backend Developer - 마켓컬리2019.02 ~ 2021.01 / PowCompany Backend Developer - 파우더룸2018.11 ~ 2019.02 / Herren Backend Developer - 공비서 ~ Side Project Resumers(java, springboot) 우리동네 소상공인 공동구매 플랫폼 : 사이 (python, django) sanic-chatting-project(python, sanic) realtime-ws-pubsub-baas-api(python, sanic) Prizes [2020.07] AngelHack Global Hackaton Series 2020 Seoul Common Computer 우승 [2019.06] AngelHack Global Hackaton Series 2019 Seoul 전체 우승 Translate Scala Exercises Tutorial 번역 SlideShare 클린코드와 TDD (1부) 클린코드와 테스트코드 (2부) Javascript 생태계 Activities2020 200121 AWS Community Day - re:Invent 2019 191127 우아한 테크 러닝 - DDD 세레나데 교육 191028 스포카 크리에이터 컨퍼런스: Hello World! 190926 우아한 테크 세미나 - 우아한 스프링배치 참가 190901 Amathon 2019 해커톤 참가 190824 뱅크샐러드 컨퍼런스 Con-Salad 05 190817 Pycon Korea 2019 양일 참석 190807 AWSKRUG GraphQL모임 190630 I/O Extended 2019 Seoul 190602 AngelHackaton Seoul 2019 해커톤 참가 190427 Spring camp 2019 190316 프론트엔드와 무관합니다만, 190223 KCD(Korea Community Day) 2019 2018 181006 Dev Django Korea 2018 180920 [T academy]스프링부트를 이용한 웹 서비스 개발하기 180919 [AUSG Seminar Series] 2018 F/W 초보자를 위한 AWS 뿌시기 180809 [OKKY 세미나] 오픈소스, 줘도 못 먹나 - 오픈소스로 팀의 개발 생산성 높이기 180728 Seoul.js Lightning Talk 180628 OpenInfra Days Korea 2018 Contactsehajyang@gmail.comGitHubLinkedIn"},{"title":"","date":"2019-07-15T14:11:55.651Z","updated":"2019-07-15T14:11:55.651Z","comments":false,"path":"tags/index.html","permalink":"https://sehajyang.github.io/tags/index.html","excerpt":"","text":""},{"title":"Kotlin 에서 Lombok을 사용할 수 없는 문제","date":"2019-03-06T15:00:00.000Z","updated":"2019-07-15T14:11:55.607Z","comments":true,"path":"etc/2019/03/07/kotlin-and-lombok.html/index.html","permalink":"https://sehajyang.github.io/etc/2019/03/07/kotlin-and-lombok.html/index.html","excerpt":"","text":"최근 자바 스프링부트로 되어있는 사내 프로젝트에 코틀린을 일부분 도입하려다 대차게 실패했다..사내 프로젝트에 Lombok을 사용하고 있었는데, 코틀린이 롬복을 사용한 Bean Class 에 접근하지 못하고 있었다. 당시 1Kotlin: Cannot access '가가' it is private member of '나나' 이런 에러 메세지를 띄우며 컴파일이 되지 않았다. 처음엔 자바로 짜여진 클래스의 private object에 접근을 못해서 나는 에러인 줄 알았으나 롬복 문제였다.kotlin-doesnt-see-java-lombok-accessors그리고 위 링크에서 이유를 알 수 있었다. 위 링크를 요약하자면 일반적으로 JVM 에선 코틀린이 먼저 컴파일 된 후 자바가 컴파일 된다.코틀린이 자바의 롬복으로 된 클래스에 접근하려 했으나 getter setter가 만들어지지 않아서 접근을 하지 못한다.롬복은 컴파일시 동작 하는 어노테이션이기 때문이다.강제로 컴파일러가 자바 먼저 컴파일하게 바꿀 순 있지만 그렇게 되면 자바에서 코틀린 코드를 사용할 수 없다. 코틀린과 자바가 100% 호환은 맞지만 자바로 만들어진 third-party 라이브러리 들과 호환 되는건 아닌 것 이다.롬복을 사용한 자바 파일들을 전부 코틀린으로 바꾸지 않는 한 코틀린을 현재 진행 중인 프로젝트에 적용 하긴 힘들 것 같다. 두줄요약 코틀린과 롬복을 같이 쓸 수 없다. 코틀린을 정말 쓰고싶다면 롬복을 사용한 자바 파일을 코틀린 파일로 바꿔야 된다. 19.06.26 기준 자세한 포스팅이 나왔습니다!Naver D2 Kotlin 도입 과정에서 만난 문제와 해결 방법 혹 궁금하거나 오류가 있다면 댓글 남겨주세요😄"},{"title":"mybatis association","date":"2019-02-17T15:00:00.000Z","updated":"2019-08-02T14:41:53.819Z","comments":true,"path":"java/2019/02/18/mybatis-association.html/index.html","permalink":"https://sehajyang.github.io/java/2019/02/18/mybatis-association.html/index.html","excerpt":"","text":"Lombok 사용Service 생략 File Shop.java ShopDetail.java ShopMapper.xml Shop.java 12345678@Datapublic class Shop { private String shopno; private String id; private String pwd; private ShopDetail shopDetail; //변수명 앞문자 capital 주면 안됨(getter, setter 때문)} ShopDetail.java 123456public class ShopDetail { private String shopno; private String name; private String price; private String count;} ShopMapper.xml 123456789101112131415161718<!-- 중략 --><mapper namespace=\"com.test.mapper.ShopMapper\"> <resultMap id=\"ShopMap\" type=\"com.test.domain.Shop\"> <result property=\"shopno\" column=\"shopno\" /> <result property=\"id\" column=\"id\" /> <result property=\"pwd\" column=\"pwd\" /> <association property=\"shopDetail\" javaType=\"com.test.domain.ShopDetail\"> <result property=\"shopno\" column=\"shopno\" /> <result property=\"name\" column=\"name\" /> <result property=\"price\" column=\"price\" /> <result property=\"count\" column=\"count\" /> </association> </resultMap> <select id = \"selectTestQuery\" resultMap = \"ShopMap\"> select s.*, sd.* from shop s join shopdetail sd on s.shopno = sd.shopno </select> Result1Shop[(shopno=1, id=aa, pwd=1234, shopDetail=shopDetail(shopno=1, name=김뭐뭐, price=1000, count=100))] association, result map collection 등으로 검색하면 더 자세히 알 수 있습니다."},{"title":"Springboot 에서 test code 작성하기 1편 - 통합테스트","date":"2019-04-04T15:00:00.000Z","updated":"2019-08-02T14:41:53.820Z","comments":true,"path":"java/2019/04/05/springboot-test-code-1.html/index.html","permalink":"https://sehajyang.github.io/java/2019/04/05/springboot-test-code-1.html/index.html","excerpt":"","text":"Springboot 에서 test code 작성하기 시리즈 Springboot 에서 test code 작성하기 1편 - 통합테스트(MVC) Springboot 에서 test code 작성하기 2편 - 단위테스트(Service) Springboot 에서 test code 작성하기 3편 - assetThat이 중복되는 테스트와 Spock 최근 사내 프로젝트에 테스트 코드를 작성할 기회가 있었다.컨트롤러는 운영 환경과 비슷하게 테스트 하기 위해 통합 테스트, 서비스는 의존성을 줄이고 해당 서비스의 목표에만 집중하기 위해 단위테스트를 하기로 결정했다.목표는 해당 컨트롤러의 메소드가 잘 동작하는지(요청을 잘 보내고 예상한 응답을 잘 받는지), 서비스가 개별적으로 잘 동작하는지 확인하는 것 이다. 테스트에 관한 글을 찾아보던 중 우아한형제들 기술블로그에서 테스트 메소드의 이름을 한글로 짓는다는 것을 알게 되었다.테스트가 실패했을 때 어느 기능에서 오류가 났는지 직관적으로 알 수 있어 좋은 것 같아서 테스트 메소드 명을 한글로 작성했다. 1. MVC 컨트롤러 통합 테스트목표는 고객 정보를 조회 및 등록하는 메소드를 통합테스트 하는 것 이다.컨트롤러 통합 테스트는 클래스 상단에 @SpringbootTest 을 선언한다.모든 Bean을 올리는 것으로 다른 테스트에 비해 테스트 시간이 오래 소요되지만 운영환경과 비슷하게 테스트 할 수 있다.따라서 클래스에 선언한 어노테이션은 다음과 같다. 어노테이션 설명 @RunWith(SpringRunner.class) 테스트를 실행하기 위해 참조하는 클래스(SpringRunner) @AutoConfigureWebMvc MVC와 관련된 Bean을 올린다 @Transactional 테스트 후 DB 롤백 @Ignore 실제로 실행할 필요가 없기 때문에 Ignore를 선언 @SpringBootTest 모든 Bean을 올리는 통합 테스트 123456789101112131415161718192021222324252627/** * @author sehajyang * @date 2019-04-05 */@RunWith(SpringRunner.class) @AutoConfigureWebMvc @Transactional @Ignore @SpringBootTest public class CustomerControllerTest { @Autowired private MockMvc mvc; @Autowired private WebApplicationContext webApplicationContext; @SpyBean private CustomerService customerService; @Autowired private ObjectMapper objectMapper; private MockHttpSession session = new MockHttpSession(); private MockHttpServletRequest request = new MockHttpServletRequest(); @SpyBean은 해당 객체를 주입받아 사용하다 given을 주면 선언한 해당 기능으로 동작하는 Bean 이다. 고객정보를 조회 및 등록하는 메소드가 있는 도메인 인 CustomerController 가 있다.아래 코드는 예시입니다. 12345678910111213141516171819202122232425262728293031@Controller@RequestMapping(\"customer\")public class CustomerController { @Autowired CustomerService customerService; @GetMapping(\"\") public ModelAndView getCustomerList(HttpSession session, HttpServletRequest request){ ModelAndView mav = new ModelAndView(\"customerListPage\"); List<Customer> customerList = customerService.getCustomerList(); mav.addObject(\"customerList\", customerList); return mav; } @PostMapping(\"\") public Object regCustomerData(@RequestBody Customer customer, HttpSession session, HttpServletRequest request){ // 기존에 해당 유저가 있는지 확인후 등록하는 메소드 (이렇게 하면 안됩니다(예시일뿐!)) int result; int userExist = shopService.getCustomerByCustno(customer.getCustno(1)); if(userExist < 1){ return Constant.RESULT_FAIL; }else{ result = shopService.regCustomerData(customer); } return (result > 0) ? Constant.RESULT_SUCCESS : Constant.RESULT_FAIL; }} 코드상엔 없지만 CustomerController의 모든 메소드의 session과 header에는 특정 값이 셋팅되어 있어야 한다고 가정한다.따라서 위 getCustomerList 를 테스트 하는 코드는 다음과 같다. 123456789101112131415161718192021222324252627282930313233343536373839404142434445@Before //테스트 수행시 실행 public void setUp() { //Integration Test this.mvc = MockMvcBuilders.webAppContextSetup(webApplicationContext) .dispatchOptions(true) //HTTP TRACE 요청을 디스패치할지 여부를 설정 (default는 false) .alwaysDo(print()) .build(); session.setAttribute(\"Id\", \"셋팅 값\"); request.addHeader(\"X-FORWARDED-FOR\", \"셋팅 값\"); } @Test public void 고객리스트_조회가_정상적으로_되어야한다() throws Exception { List<Customer> customerList = customerService.getCustomerList(); this.mvc.perform(get(\"/customer\") .session(session) .header(\"X-FORWARDED-FOR\", request.getHeader(\"X-FORWARDED-FOR\")) ) .andExpect(status().isOk()) // 200 return .andExpect(view().name(\"customerListPage\")) // 리턴할 view page name .andExpect(model().attribute(\"customerList\", customerList)); // 리턴할 model attribute name // redirect 리턴일 경우 //.andExpect(redirectedUrl(\"/\")) //.andExpect(status().is3xxRedirection()) } @Test public void 고객정보_등록이_예외없이_되어야한다() throws Exception { Customer customer = new Customer(\"1\",\"sehajyang\"); // Customer(custno, custname) given(customerService.getCustomerByCustno(customer.getCustno())).willReturn(1); // getCustomerByCustno 의 result는 1을 리턴 this.mvc.perform(post(\"/customer\") .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(customer)) // JSON으로 만들어준다 .session(session) .header(\"X-FORWARDED-FOR\", request.getHeader(\"X-FORWARDED-FOR\")) ) .andExpect(status().isOk()) .andExpect(content().string(\"SUCCESS\")) .andReturn() .getResponse(); } 그 밖에도 param() 등 으로 파라미터를 넘길수도 있다.이렇게 Controller를 통합테스트 를 실행해 전체 플로우를 테스트 할 수 있다. @SessionAttributes를 사용하는 방법도 있는데 이 경우엔 테스트 코드에서 requestAttr() 대신 sessionAttr()을 사용할 수 있다.이 방법은 이곳의 예제로 확인할 수 있다. 만약 123@PostMapping(\"\")public Object regCustomerData(Customer customer, HttpSession session, HttpServletRequest request){ 이렇게 DTO에 @RequestBody가 없는 도메인을 테스트하려면 조금 복잡해진다.나는 회사 코드의 POST 도메인 파라미터 DTO에 일부 @RequestBody가 없었고, @RequestBody를 추가 할 경우 문제가 생길 수 있었기 때문에기존 코드를 변경하지 않고 테스트 하는 방법을 찾아보았다. 우선 Spring에서는 권장하지 않는다 그 이유는 아래와 같다.대략 이렇게 이해할 수 있다. 통합 테스트의 주 목적 중 하나는 MockMvc 모델 객체가 Object 데이터로 바뀌었는지 확인하는 것 이다.NewObject(DTO)를 자동으로 변환하면 NewObject(DTO)가 실제 form과 호환되지 않는 문제가 있는데, 이러한 문제가 있는 파라미터는 테스트에서 제외되기 때문이다. 그래서 @RequestBody가 없는 도메인의 DTO 파라미터는 십중팔구 넘어가지 않으며 null이된다.이것을 해결하기 위한 방법은 두가지 정도가 있다. HttpClient 사용1234567891011121314151617@Test public void 고객정보_등록이_예외없이_되어야한다() throws Exception { Customer customer = new Customer(\"1\",\"sehajyang\"); // Customer(custno, custname) given(customerService.getCustomerByCustno(customer.getCustno())).willReturn(1); // getCustomerByCustno 의 result는 1을 리턴 this.mvc.perform(post(\"/customer\") .contentType(MediaType.APPLICATION_FORM_URLENCODED) .content(EntityUtils.toString(new UrlEncodedFormEntity(Arrays.asList( new BasicNameValuePair(\"custno\", \"1\"), new BasicNameValuePair(\"custname\", \"sehajyang\") ))))) .andExpect(status().isOk()) .andExpect(content().string(\"SUCCESS\")) .andReturn() .getResponse(); } buildUrlEncodedFormEntity() 이용1234567891011121314151617181920212223242526272829303132333435363738394041@Test public void 고객정보_등록이_예외없이_되어야한다() throws Exception { Customer customer = new Customer(\"1\",\"sehajyang\"); // Customer(custno, custname) given(customerService.getCustomerByCustno(customer.getCustno())).willReturn(1); // getCustomerByCustno 의 result는 1을 리턴 this.mvc.perform(post(\"/customer\") .contentType(MediaType.APPLICATION_FORM_URLENCODED) .contentType(MediaType.APPLICATION_FORM_URLENCODED) .content(buildUrlEncodedFormEntity( \"custno\",\"1\", \"custname\",\"sehajyang\" )))) .andExpect(status().isOk()) .andExpect(content().string(\"SUCCESS\")) .andReturn() .getResponse(); }private String buildUrlEncodedFormEntity(String... params) { if( (params.length % 2) > 0 ) { throw new IllegalArgumentException(\"Need to give an even number of parameters\"); } StringBuilder result = new StringBuilder(); for (int i=0; i<params.length; i+=2) { if( i > 0 ) { result.append('&'); } try { result. append(URLEncoder.encode(params[i], StandardCharsets.UTF_8.name())). append('='). append(URLEncoder.encode(params[i+1], StandardCharsets.UTF_8.name())); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } } return result.toString(); } Testing Form posts through MockMVC에서 더 알아볼 수 있다. 위 시리즈는 3부로 나뉘어 통합테스트, 단위테스트, spock를 사용한 테스트로 작성 될 예정입니다.많이 미숙하지만 지속적으로 알아가고 있습니다.혹 틀린 부분 혹은 궁금한 점이 있다면 댓글 부탁드리겠습니다 읽어주셔서 감사합니다!🙏 참고자료 Mokito 공식 문서 Mokito github wiki Yun 님의 Test Guide"},{"title":"Kakao Geocode API, 주소로 위도 경도 java로 파싱하기","date":"2019-04-16T15:00:00.000Z","updated":"2019-08-02T14:41:53.822Z","comments":true,"path":"java/2019/04/17/kakao-api-geocode-parsing.html/index.html","permalink":"https://sehajyang.github.io/java/2019/04/17/kakao-api-geocode-parsing.html/index.html","excerpt":"","text":"Kakao Geocode API로 부터 받은 데이터를 직렬화 하고 JSON객체로 바꾸고 특정 데이터를 얻어오는 작업을 할 것입니다.Kakao API를 이용하기 위해선 API Key가 필요한데, 이곳 에서 얻을 수 있습니다. 카카오 지도 API로부터 주소로 위도 경도를 받아오기 위해선 이곳에 공식 예제가 있습니다. 받아온 주소 데이터를 JSON으로헤더에 발급받은 API키를 등록 후 POSTMAN으로 요청을 날려보겠습니다. https://dapi.kakao.com/v2/local/search/address.json?query=판교역로 235 응답받은 데이터는 이러합니다. 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647{ \"meta\": { \"is_end\": true, \"total_count\": 1, \"pageable_count\": 1 }, \"documents\": [ { \"road_address\": { \"undergroun_yn\": \"N\", \"road_name\": \"판교역로\", \"underground_yn\": \"N\", \"region_2depth_name\": \"성남시 분당구\", \"zone_no\": \"13494\", \"sub_building_no\": \"\", \"region_3depth_name\": \"삼평동\", \"main_building_no\": \"235\", \"address_name\": \"경기 성남시 분당구 판교역로 235\", \"y\": \"37.40209529907863\", \"x\": \"127.10863694633468\", \"region_1depth_name\": \"경기\", \"building_name\": \"에이치스퀘어 엔동\" }, \"address_name\": \"경기 성남시 분당구 판교역로 235\", \"address\": { \"b_code\": \"4113510900\", \"region_3depth_h_name\": \"삼평동\", \"main_address_no\": \"681\", \"h_code\": \"4113565500\", \"region_2depth_name\": \"성남시 분당구\", \"main_adderss_no\": \"681\", \"sub_address_no\": \"\", \"region_3depth_name\": \"삼평동\", \"address_name\": \"경기 성남시 분당구 삼평동 681\", \"y\": \"37.40206645815382\", \"x\": \"127.10864594007738\", \"mountain_yn\": \"N\", \"zip_code\": \"463400\", \"region_1depth_name\": \"경기\", \"sub_adderss_no\": \"\" }, \"y\": \"37.40209529907863\", \"x\": \"127.10863694633468\", \"address_type\": \"ROAD_ADDR\" } ]} 위의 데이터에서 Y 좌표 값과 X 좌표값이 필요하기 때문에 해당 데이터만 가져오도록 하겠습니다. 우선 KAKAO 지도 API로 요청을 보내고 응답을 받습니다. 1234567891011String APIKey = \"발급받은 API 키\"; HashMap<String, Object> map = new HashMap<>(); //결과를 담을 maptry { String apiURL = \"https://dapi.kakao.com/v2/local/search/address.json?query=\" + URLEncoder.encode(address, \"UTF-8\"); HttpResponse<JsonNode> response = Unirest.get(apiURL) .header(\"Authorization\", APIKey) .asJson(); 받아온 데이터를 JSON 객체로 변환하기 위해 ObjectMapper를 사용합니다. 12ObjectMapper objectMapper = new ObjectMapper();objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true); 위의 objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true); 는단일 리스트 객체를 싱글 값과 같게 인식합니다.ex) "fruits" : ["apple"] 를 "fruits" : "apple" 로 인식 지정된 VO에 응답받은 데이터를 셋팅지정된 형식에 잘 셋팅하기 위해 1KakaoGeoRes bodyJson = objectMapper.readValue(response.getBody().toString(), KakaoGeoRes.class); KakaoGeoRes에 응답받은 데이터를 잘 셋팅하도록 합니다. 123456789101112131415@Datapublic class KakaoGeoRes { private HashMap<String, Object> meta; private List<Documents> documents;}@Dataclass Documents { private HashMap<String, Object> address; private String address_type; private Double x; private Double y; private String address_name; private HashMap<String, Object> road_address;} X, Y값만 필요했기 때문에 위와 같이 작성했습니다.key가 응답받은 데이터와 다르면 에러가 나기 때문에 사용하지 않는 key 도 선언합니다. X,Y 값에 접근그 후 12bodyJson.getDocuments().get(0).getX()bodyJson.getDocuments().get(0).getY() 위와같이 접근할 수 있습니다. 읽어주셔서 감사합니다.혹 오류나 질문이 있다면 편하게 코멘트 부탁드리겠습니다!🙆♂️"},{"title":"gitlab에 이미 push된 commit 삭제","date":"2019-03-10T15:00:00.000Z","updated":"2019-08-02T14:41:53.829Z","comments":true,"path":"tip/2019/03/11/git-reset-push.html/index.html","permalink":"https://sehajyang.github.io/tip/2019/03/11/git-reset-push.html/index.html","excerpt":"","text":"gitlab, github등에 취소해야 되는 commit이 있는데 이미 push 해버렸을 때git bash에서 1git reset --hard 되돌아가고자 하는 커밋주소 커밋 주소는 git log 로 알 수 있다 reset 옵션으론 hard, soft, mixed 가 있다 링크 그 후 1git push origin +브랜치명 브랜치 명 앞에 +를 붙여야 한다(덮어씌운다는 의미)+ 없이 push 해버리면 최근 커밋을 pull 하라며 에러가 난다. 만약 1! [remote rejected] master -> master (pre-receive hook declined) 이런 에러가 났다면 해당 project settings > Repository > Protected Branches에서 unprotected로 해당 브랜치를 설정해주면 된다 (보통 master에 걸려있음)"},{"title":"springboot migration","date":"2019-05-06T15:00:00.000Z","updated":"2019-08-02T14:41:53.824Z","comments":true,"path":"java/2019/05/07/springboot-migration-1.5to2.0.html/index.html","permalink":"https://sehajyang.github.io/java/2019/05/07/springboot-migration-1.5to2.0.html/index.html","excerpt":"","text":"공식 가이드대로 했을때 몇가지 오류때문에 버전 업그레이드가 잘 되지 않았었기 때문에 삽질을 줄이고자 이 포스팅을 작성하게 되었습니다 😊필수 사항 : JDK 8 이상 우선, 버전을 마이그레이션 할 때몇가지 라이브러리들은 버전을 업그레이드 해주지 않으면 에러가 납니다.그리고 한방에 버전을 쭉 올려버리면 오류를 잡았음에도 불구하고 자꾸 알수 없는 오류가 발생하며 빌드가 되지 않습니다(혹 이유를 아신다면 코멘트 부탁드리겠습니다 🙇)따라서 1.5 -> 2.0 -> 2.1 순서로 버전을 업그레이드 했습니다. 순서1. gradle 버전이 4.4 가 아닐경우 4.4-all 로 변경gradle > wrapper > gradle-wrapper.properties 에서 아래와 같이 gradle 버전을 수정합니다. 1distributionUrl=https\\://services.gradle.org/distributions/gradle-4.4-all.zip 2. build.gradle에 dependency-management를 추가12apply plugin: 'io.spring.dependency-management'runtime(\"org.springframework.boot:spring-boot-properties-migrator\") 3. springboot 버전 바꾸기1springBootVersion = '2.0.5.RELEASE' 아래부턴 쓰는 라이브러리가 다양하기 때문에버전 업그레이드로 인한 특정 라이브러리 설정의 변화로 발생하는 오류를 고치는 방법을 작성할 수 없었습니다. 대신 어떻게 고쳐야 하는지에 대한 문서는 common-application-properties 공식문서 링크 위 링크를 참고하시면 될 것 같습니다. 4. 빌드만약 컴파일 오류가 난다면 해당되는 오류를 고칩니다.(ex: log4j 오류가 나서 log4j2로 고쳤습니다) 5. application.properties 수정빌드 깨진 것을 확인 후 해당 설정을 application.properties에서 적절하게 고칩니다.(여담으로 datasource 쪽에서 자꾸 오류가 났습니다) 6. bean overridingorg.springframework.beans.factory.support.Bean Definition Override Exception위의 오류가 발생하면 application.properties 에 아래 코드를 추가합니다.spring.main.allow-bean-definition-overriding=true이것은 bean overriding을 허용한다는 것 입니다. 12The server time zone value ‘KST’ is unrecognized or represents more than one time zone : mysql-connector-java 위의 오류가 발생하면 아래와 같이 DB url의 DB명 뒤에 ?characterEncoding=UTF-8&serverTimezone=Asia/Seoul 를 추가합니다 1jdbc:mysql://아이피:포트/DB명?characterEncoding=UTF-8&serverTimezone=Asia/Seoul 7. 버전 업그레이드 2.0 -> 2.1빌드 및 run이 성공적으로 되면 build.gradle에서 2.1.3.RELEASE 로 springboot 버전을 변경합니다. 1springBootVersion = '2.1.3.RELEASE' 그 후 위의 작업을 반복하며 오류를 잡으면 됩니다.2.1 버전 부턴 mysql 드라이버 명이 변경되었습니다. 12기존 : com.mysql.jdbc.Driver바뀐것 : com.mysql.cj.jdbc.Driver 8. properties-migrator 제거빌드 및 run이 성공적으로 되면 build.gradle 에서 추가해뒀던 아래 코드를 제거 합니다. 1runtime(\"org.springframework.boot:spring-boot-properties-migrator\") 혹 내용이 잘못되었거나 보충해야 될 부분이 있다면 코멘트 남겨주세요 🙏읽어주셔서 감사합니다 :) 추가(19.5월 기준) 만약 swagger를 쓰는데 마이그레이션 시 오류 날 경우 2.9.1로 올려주셔야 됩니다 :) 참고자료 spring-boot-migration-java 공식문서"},{"title":"spring camp 2019 참석 후기 (1부)","date":"2019-04-28T15:00:00.000Z","updated":"2019-08-02T14:41:53.826Z","comments":true,"path":"seminar/2019/04/29/springcamp-2019-review.html/index.html","permalink":"https://sehajyang.github.io/seminar/2019/04/29/springcamp-2019-review.html/index.html","excerpt":"","text":"spring camp 2019를 다녀왔다!티켓팅이 정말 어려웠기 때문에, 지인이나 회사의 다른 개발자분이 티켓팅에 실패해서 혼자 다녀왔다.공개된 세션들은 지금 내가 개발하고 있는 프로젝트에 많은 도움이 될 것 같아서 정말 기대를 많이 했다.특히 실전에 써먹는 스프링부트 나 Monitoring With Actuator, 무엇을 테스트할 것인가? 어떻게 테스트할 것인가?, Kotlin 프로젝트를 피할 수 없을 때 라는 세션이 그러했다.최근 테스트를 내가 제대로 하고 있는지에 대한 의문이 있었고, 모니터링에 대한 필요성을 느끼고 있어서였다.Kotlin은 저번에 Springboot에 붙이려다 실패했었기 때문에 위의 세션이 기대가 됐다.세션은 오전 10:40 분 부터 시작했는데 가는길에 시간이 조금 걸려 조금 지각을 해버렸다.로비에 들어가니 팔찌와 스티커 그리고 휴대용 선풍기를 줬다(왜인지는 모르겠는데 많은 개발세미나에선 휴대용 선풍기를 준다)굿즈를 받아들고 Track 1의 실전에 써먹는 스프링부트를 들었다.중후반에 들어왔기 때문에 아쉽게 기록을 하지 못했다. 정말 아쉬웠다. Monitoring With Actuator두번째로 들은 세션은 Monitoring With Actuator 였다.보안에 대한 의문이 있었기 때문에 예전에 한번 도입하려다 그냥 포기했었는데, 이 세션에서 어떻게 사용해야 하며 모니터링을 도와주는 도구 및 팁과룰에 대한 다양한 설명을 들을 수 있었다.Actuator는 springboot 2.0 부터 사용할 수 있는데, 다행히 저번에 버전업을 해서 도입한다면 바로 도입할 수 있을 것 같았다. 1.5에서도 사용할 수 있지만 제약사항이 많았다. Spring Actuator 란? 장애 예방, 원인파악 및 조치, 상태확인, 성능개선, 서비스상태분석을 위함 제어 도구 = endpoint 지표 제공 = metrics 사용중인 라이브러리 탐지도 한다 default endpoint default 는 health, info 만 제공 properties에서 설정할 수 있다. Enabling Endpoints web > rest(health,info)로 보여줌 jmx > 셧다운 제외한 모든 정보를 보여줌 spring boot 2.0 부터 spring security에 통합 혹은 따로 서버에 띄우는 방법(총 두개)으로 사용 가능 접근 가능 ip 설정 가능 Metrics 2.0 부터 특정 지표상의 key value 쌍의 지표 tag로 검색 가능 반드시 측정해야 할 지표 (RED Method) (Request)Rate (Request)Error (Request)Duration outcome code => status 간단히 잘 볼수있음 Micrometer Registry, Meter, Tag spring boot 2.0부터 지원 meterregistry cloudwatch도 있음! 자바에서 null을 안전하게 다루는 방법세번째로 들은 세션은 자바에서 null을 안전하게 다루는 방법 이었다. 내 생각에, 자바에서 가장 많이 일어나는 Exception은 nullPointer exception이 아닐까 싶다.인기가 정말 많았던 세션이라 아쉽게도 좌석 부족으로 서서 들어 기록을 하진 못했지만 ppt가 공개되었다! ppt 링크너무 너무 유익한 세션이었다. 만약 해당 강연을 듣지 못한 분은 ppt를 보고 이 강연이 얼마나 유익했을지 알 수 있을거라 생각한다.해당 세션이 끝난 후 한시즈음 점심을 먹었다. 배달의 민족 측에서 준비한 도시락이었다. 보통 세미나에선 샌드위치를 주는데 한식을 줘서 좋았다 :D 무엇을 테스트할 것인가? 어떻게 테스트할 것인가?네번째 세션은 정말 기대하던 TDD 세션이었다. TDD라기보단 테스트 세션이었지만 그래서 더 좋았다.그간 인터넷을 찾아보며 나름대로 테스트코드를 작성해오고 있었는데, 맞게 작성하고 있는지, 이건 테스트해야되는지 이건 아닌지, 이걸 테스트하기엔 너무 어려운데 과연 의미가 있는지이건 불가능한 테스트인데 어떻게 해야 하는지에 대한 고민이 많았다.그래서 Udemy에서 Master Java Unit Testing with Spring Boot & Mockito 강의라도 들을까 하고 있던 차에, 한국에서! 그것도 실무자가 하고있는 스프링부트 테스트코드 강의라서 많은 기대가 됐다.그리고 이 세션은 그러한 내 많은 고민을 한번에 해결해 주었다! 그리고 나는 테스트코드를 맞게 짜고 있었다. 안도감이 들었다.강연 중간에 spock에 대한 언급이 있었는데, 생각보다 많은 분들이 사용하고 있어서 왠지 든든했다(?)spock는 정말 좋다. 처음엔 groovy가 낯설었지만 조금 적응이 되니 너무 편리했다. 테스트로부터 얻을 수 있는 것 안정감과 자신감 (정말 그렇다!) 대상은 나와 동료 무엇을 테스트 할 것인가 기존 플로우 안까지 할 필요없음 만약 걔를 테스트해야되면 걔를 빼는게 맞는거임 설계사항 그대로 테스트 코드로 옮기는게 좋음 테스트 가능한 것 불가능한 것 외부 API 테스트안됨(그렇다) 항상 성공할 수 있는것 동일한 결과가 나올 수 있는것을 테스트 어떻게 테스트 할 것 인가 바운더리 레이어까지 테스트안되는걸 끌어올려서 테스트 바운더리 레이어 = > 한 모듈로서의 의미를 지니는 가장 바깥쪽 springcontext의 오용은 언어의 본질을 망각하게 될 수 있다. Context, framework 종속적이지 않은 테스트를 우선 Test double 테스트 할 수 없는 영역을 주입해서 테스트할 수 있게 해줌 무엇을 test double로 처리해야할까 H2 뭐 그런거 써서 enbedded 활용 => 제어할 수 없던 그 영역을 제어할 수 있다! Endpoint Test Spring contract test tip 테스트는 상호 독립적으로 작성 공유되는 데이터는 꼭 초기화를 한다(테스트간 서로 영향을 끼치지않도록) => Dynamic Test (Junit5) 테스트 에서 의도와 목적이 드러나도록 테스트 코드도 리펙토링 대상 앞으로 테스트코드를 더 즐겁고 확신있게(?) 짤 수 있을 것 같다. 이후에 들은 세션은 당신도 할 수 있는 레거시 프로젝트 개선 이야기, Kotlin 프로젝트 적응하기 이다.Kotlin + Spring Data JPA 세션을 듣고싶었는데, 중간에 일이 생겨 아쉽게 마지막 세션을 들을 수 없었다.이전에 kotlin 프로젝트에 자바 라이브러리를 사용하려다 대차게 실패한 적이 있기 때문에 꼭 듣고 싶었다.해당글 : Kotlin 에서 Lombok을 사용할 수 없는 문제강연 영상이나 ppt가 공개되면 봐야겠다."}],"posts":[{"title":"개발 요구사항을 분석하는 방법","slug":"how-to-analyze-work","date":"2022-05-06T04:00:00.000Z","updated":"2022-05-06T04:13:53.315Z","comments":true,"path":"2022/05/06/how-to-analyze-work/","link":"","permalink":"https://sehajyang.github.io/2022/05/06/how-to-analyze-work/","excerpt":"","text":"들어가며사실 기술에 대한 글은 많지만, 개발자가 어떻게 업무를 분석하고 작게 나눠야 하는지에 대한 글은 상대적으로 적다.이 글은 업무 분석에 어려움을 겪는 주니어 개발자분들을 위해 작성됐다. 신입 땐 업무를 어떻게 분석하고 파악하고 구현해야 하는지를 잘 알지 못했다.무작정 만들어본 뒤 빠진 케이스를 뒤늦게 추가하거나 요구사항 분석을 잘못해 구현 방향이 잘못되어 구현 자체를 다시 한 적도 있었다.재작업을 하게 됨에 따라 시간도 오래 걸렸고, 급하게 구현하면서 품질을 어느 정도 포기하기도 했다.이러한 일련의 과정에서 어떻게 하면 이러한 비효율을 줄이고 올바른 기능을 제대로 만들 수 있는지 고민해왔었는데, 답을 내기가 쉽지 않았다.그도 그럴게, 구현하기전에 모든 문제를 정의하고 설계하는건 굉장히 어렵다. 불투명한 요구사항을 구체화하며 모든 케이스를 정의하는건 어려운 일이다.그렇다고 해서, 대략적으로 파악하고 구현을 시작하면 종종 예상치 못한 문제에 맞닥뜨리게 된다.그러한 고민 과정에서 동료의 피드백이 있었고 이를 바탕으로 업무 분석하는 방법을 정의하게 됐다.지금은 주어진 요구사항이 복잡한 경우 이 포스팅에서 설명할 방법을 사용하여 해결하고 있으며, 이러한 노력으로 시간의 손실은 줄이며 어느 정도 내가 원하는 ‘올바른 기능을 제대로’ 만들 수 있게 됐다. 요구사항을 분석하고 설계하는 방법처음에 기능 구현 요구사항을 받으면 문제가 하나의 큰 덩어리처럼 느껴지고 어느 부분부터 어떻게 접근해야 할지 감이 잘 오지 않는다.숙련도가 높은 시니어라면, 보자마자 어떤 지뢰가 있고 어떻게 해결해야 목적을 달성할 수 있는지 알 것이다.하지만 나는 어디에 어떤 지뢰가 있고, 어떻게 해결해야 하는지 하나하나 고민하고 확인해봐야 했다.다음은 내가 사전 분석과 설계 구현 정의를 위해 나에게 던지는 질문이다.(사용자는 포괄적인 의미로 API 혹은 모듈에서 공개한 기능을 사용하는 클라이언트를 의미한다) 1234567891011121314151617181920212223242526272829303132333435363738- 요구사항 분석 - 요구사항 정의는 어떤가? - 요구사항에 누락된 부분은 없는가? - 현재 시스템이 요구사항을 수용할 수 있는가? - 요구사항의 전제조건은 어떻게 되는가? - 시간 비용은 어떤가?- 설계 할 때 - 사용자 예상 시나리오는 어떻게 되는가? - 동시성 문제가 있는가? - 사용자는 어떤 데이터를 기대하고, 어떻게 사용할까? - 이 정보가 정말 사용자에게 필요한 정보인가? - 이 정보에 커플링이 생기면 미래에 어떤 일이 생길까? - 시스템 내부 리펙토링시 발목을 잡지는 않을까?- 인터페이스 - 사용자를 생각해서 최대한 알기쉽게, 간결하고 깔끔하게 만들어졌는가? - 작업하기 전에 인터페이스는 설계해야한다 - 만약 인터페이스가 어그러지면 다시 고민하고 리팩토링 해야된다- 구현할 때 - 이 데이터의 속성은 어떤가? 어떤 특성을 갖고 있는가? - 어떻게 해야 이 데이터를 적절히 제공할 수 있는가? - 이 데이터를 사용하는 클라이언트는 누구인가? 클라이언트에게 어떤 데이터를 제공해야 하는가 - 이 API를 사용하는 사용자는 이 API를 보고 어떤 역할과 행동을 하는지 예측하기가 쉬운가? - 불필요한 정보를 외부에 공개하지 않았나? - 너무 많은 책임을 갖고 있진 않은가? - 적절한 예외를 주는가? - 이 기능은 어떤 행동을 하고 어떤 책임이 있는가? - 어떤 데이터가 주어지고 어떻게 처리하며 어떤 결과를 줘야 하는가? - 참조 기능은 어떤 스펙을 갖고 있는가, 만약 예외를 던진다면 이 기능내에선 그 에러를 어떻게 처리해야하는가? - 이 기능 요구사항과 전제 조건(accaptance criteria) 는 뭔가? - 요구사항을 명확하게 이해했는가? - 이 기능의 시나리오가 어떤가? - 클라이언트에 의존성을 갖고있는가? - 이 기능의 요구사항과 예외가 인터페이스에 잘 표현이 되었는가? - 다른 프로그래머도 유지보수 할 수 있도록 이해하기 쉬운 코드를 작성했는가?- 작업 계획은 어떤가? - 기존 구조를 파악했는가? - 작업 개요를 식별하고 작성했는가 - 작업은 충분히 적절하게 쪼개졌는가? 위 질문에 맞춰 요구사항에 대한 분석과 설계가 끝났다면 설계에 맞춰 작업계획을 아주 작게 나눈다.보통 작업 계획 항목대로 PR을 나누게 된다. 참고 (PR이 너무 클 경우 리뷰어에게 피로감을 줄 수 있으므로 PR 사이즈는 4~500줄이 넘지 않는 선으로 유지하는 게 좋다) 작업 계획까지 다 정의했다면 동료와 이러한 컨텍스트를 공유한다. 이 크로스 체킹 과정에서 잘못된 방향 혹은 누락된 부분, 더 좋은 방법등에 관해 얘기를 나눌 수 있고 올바른 구현을 할 수 있게 된다. 하지만 이 모든 원칙이 늘 지켜져야만 하는 건 아니다.원칙이 지금 상황과 맞지 않는다 판단되면 원칙을 무시할 수도 있다. 가장 중요한건 현재 상황에 가장 적합한 해결책이다.","categories":[{"name":"etc","slug":"etc","permalink":"https://sehajyang.github.io/categories/etc/"}],"tags":[{"name":"work","slug":"work","permalink":"https://sehajyang.github.io/tags/work/"}]},{"title":"2021년 상반기 회고","slug":"2021-postmortem-half-of-year","date":"2021-06-20T05:21:00.000Z","updated":"2021-06-20T07:29:01.108Z","comments":true,"path":"2021/06/20/2021-postmortem-half-of-year/","link":"","permalink":"https://sehajyang.github.io/2021/06/20/2021-postmortem-half-of-year/","excerpt":"","text":"서론올해 초의 이직 이후 조금 바빴고 최근엔 개인적인 학습에 대한 정리는 노션에 하고 있었기 때문에 블로그 글을 작성하지 않았었다.지금은 조금 여유가 생겼고 오랜만에 상반기 회고를 작성하게 되었다. 상반기에 있었던 일이직이직을 했다!그간 함께 성장할 동료가 있었으면 좋겠다는 아쉬움이 있었고, 그것은 이직을 결정하는데에 어느정도 영향을 줬다.회사를 고르는 기준은 사람마다 다르겠지만 나에겐 성장할 수 있는 동료가 가장 중요했다.한 두달 준비를 했고 지원할 회사 리스트를 정리한 뒤 코딩테스트와 기술 면접 준비를 했다.준비 과정은 다음과 같다. 지원할 회사 리스트 정리 지원할 회사에서 중요하게 보는 부분을 파악했다. 이력서 작성 이력서는 기술 중심으로 깔끔하게 작성하고 성장과정 등 불필요한 내용은 포함하지 않았다. 코딩테스트 준비 알고리즘 준비를 혼자 하는것이 정신적으로 지쳐서 지인들과 함께 알고리즘 스터디를 했다. 백준 강의를 보고 여러가지 문제를 풀며 준비했다. 국내 회사의 코딩테스트 통과를 위한 준비는 대체로 이 정도면 충분하다. 백준 : 실버~골드 프로그래머스 : lv2~lv3 codility 기술면접주니어의 경우 보통 경험이나 이력서 기반 질문 혹은 cs 질문이 들어오며, 자바 개발자의 경우 자바, 스프링과 관련된 질문을 받게 될 확률이 높다.회사마다 중요하다 생각하는게 다르기 때문에 JD를 보며 예상 면접 질문을 준비하는게 좋다.면접을 몇번 진행하다 보면 회사마다 어느정도 공통적으로 하는 질문이 있는데 이 부분은 자바 개발자 기술면접 등으로 검색해보면 많이 나온다. 합격감사하게도 가고싶었던 회사중 하나였던 마켓컬리에 백엔드 개발자로 합류하게 됐다 😊 상반기에 학습한 것책 이펙티브 자바 3/e 필독서 과거에 읽다 말았었는데 이번에 처음부터 끝까지 정리하며 읽었다. 이펙티브 자바 정리 오브젝트 필독서 이것도 읽다 말았었는데, 입사 후 프로젝트를 파악하는데에 필요해서 급하게 읽었다. 오브젝트 정리 클린 아키텍쳐 컴포넌트 설계랑 패키지 설계 부분이 가장 인상깊었다. 다시 봐도 좋을 책이다. 클린 코더 선배 개발자가 썰 풀어주는 느낌을 받았다. 앞선 책에 비해 가볍게 읽을 수 있어서 좋았다. 모던 자바 인 액션 반정도 봤다. 자바 8이상을 사용하는 자바 개발자라면 꼭 읽어봐야 할 책이다. head first 디자인 패턴 gof랑 같이 봤다. 자바 네트워크 프로그래밍 이 책은 절반정도 봤다. 프로그래밍 수련법 예제가 대체로 c, c++라서 조금 어렵지만 설계나 디버깅, 테스트에 대한 내용이 예제 기반으로 꼼꼼하게 쓰여져있다. 상반기에 아쉬웠던 일블로그학습한 것에 대해 블로그에 정리할 만큼 정리하지 못했기 때문에 기술 포스팅을 하지 않았다.하반기엔 블로그에 포스팅으로 작성할 수 있을 만큼 학습한걸 다듬고 싶다. 일어나지도 않은 일 걱정하기내 기대치와 나의 능력 사이에 갭 때문에 괴로워하며 일어나지도 않은 일을 꽤 최근까지도 걱정했다.주위로부터 일어나지 않은 일에 대해 걱정하지 말고 해결 방법을 고민하라던가 강박을 가지면 쉽게 지치니 천천히 여유를 갖고 학습 하라는 조언을 들었었는데 조언을 들을 당시엔 머리로는 알겠는데 어떻게 해야할지를 몰랐다.그러다가 최근에는 지금 상태를 인정하고, 걱정하고 있기보단 걱정하는 일이 일어날 가능성을 줄이는 방법을 알게 됐다.당연히, 걱정만 하기보단 대책을 세우고 움직이는 게 합리적인데 그걸 제대로 받아들이고 실천하기까지의 시간이 좀 걸렸다. 총평이직 이후 상반기동안 내가 우물 안의 개구리였다는걸 매일 깨닫곤 급하게 이것저것 많이 학습했다.그 과정이 좋기도 하고 힘들기도 했지만, 동료분들께 좋은 영향이나 도움을 받으며 성장할 수 있어서 정말 감사하고 즐거웠다.많이 배우고 받은 만큼 하반기엔 받은 걸 돌려줄 수 있는 동료가 되고 싶다! “하기 싫어도 해라 감정은 사라지고 결과는 남는다”라는 말이 있는데, 나에겐 맞지 않았다.나의 경우엔 강박을 낮추고 하고 싶은 일을 적절히 섞어 즐거운 감정을 잃지 않으며 학습하는 게 효율이 높았다.그러니 하반기엔 강박에서 벗어나서 좀 더 여유를 갖고 야크 셰이빙을 하며 실무 기술뿐만 아니라 개인적으로 좋아하는 기술들에 대해 학습을 해야겠다.","categories":[{"name":"Logs","slug":"Logs","permalink":"https://sehajyang.github.io/categories/Logs/"}],"tags":[{"name":"weekly","slug":"weekly","permalink":"https://sehajyang.github.io/tags/weekly/"}]},{"title":"2020년 회고","slug":"2020-review","date":"2020-12-27T03:27:59.000Z","updated":"2021-02-09T15:14:45.559Z","comments":true,"path":"2020/12/27/2020-review/","link":"","permalink":"https://sehajyang.github.io/2020/12/27/2020-review/","excerpt":"","text":"올해로 세번째 연간회고를 쓰게되었다.작년에 비해 개인공부는 적었지만 실무에서 배운게 굉장히 많은 해 였다.한가지 꼽으라면 역시 서비스 리뉴얼 오픈이다. 서비스 리뉴얼 오픈기존의 node + mongodb + k8s 로 되어있던 서비스를 spring + rdb + netflix oss + ecs 기반으로 바꾸는아에 프로젝트를 새로 만드는 수준의 리뉴얼이었다. 하지만 마이그레이션 해야할 데이터가 있고, 그 데이터는 nosql db에 있었고 rdb에 맞게끔모델링을 짜야했고..기존 서비스는 정상적으로 운영되고있었으며 리뉴얼 한 서비스로 교체되어야했다. 그야말로 달리는 차의 바퀴를 갈아끼우는 작업이었다.정신차리고 보니 2020년 하반기였다. 오픈하기 며칠 전 동료님께서 평생 오픈을 겪지 못하는 개발자도 있으며, 오픈을 겪는건 중요한 경험이라고 하셨다. 힘들었지만 돌이켜보면 많은걸 배운 경험이었다. MSA실무 프로젝트는 Netflix OSS로 되어있고, 도메인을 나눴다.하지만 AWS의 managed service들과 함께 쓰기엔 여러가지 문제가 있었다. 그래서 상반기엔 MSA관련해서 공부를 많이 했다.그 과정에서 ECS도 써보고 로깅서버를 만든느라 ELK도 살짝 사용해보고 하는 등 여러모로 넓게 학습하고 구축했었다.구축도 해보고 잘못 됐다는걸 깨닫고 여러 시도도 해보는등 시행착오가 많았다. 레퍼런스도 부족했다.나중에 알고보니 우리 서비스 뿐만 아니라 다른 서비스에서도 똑같이 겪고 있는 문제였다.아무래도 이 시행착오는 포스팅으로 써두는게 좋겠다. 토이프로젝트올해 작업한 토이프로젝트는 엔젤핵 2020에서 수상한 지역기반 공동구매 플랫폼이 있고그 외엔 이력서 공개 서비스인 토이프로젝트를 만들고있다. 지금은 잠시 중단했는데, 2021년 상반기에는 어느정도 완성하고싶다. 운영체제운영체제를 공부했다. 개발을 모르는 상태로 배웠었을땐 지루하고 재미없었지만 이래서 그랬구나! 라는 생각이 드는 부분이있어 굉장히 재미있었다.언젠간 꼭 운영체제를 만들어보고싶다. 이건 내 개발 인생 목표다ㅎㅎ 읽은 책이펙티브 자바를 읽고 오브젝트를 조금 읽었다.주위에 이 책을 좋아하는 분이 있어 종종 이에 대해 얘기도 나누고 했는데, 이 책들은 실무에 직접적으로 도움이 된 부분이 많아서 좋았다.그외엔 JVM 책을 읽었다. 중간에 내용이 딥해지긴 했지만 대략적으로 크게 설명하고있어서 올해 가장 잘 읽은 책이다. 알고리즘연초~중반엔 지인들과 알고리즘 스터디를 했고 종종 몇문제씩 풀어왔다. 확실히 과거보단 잘 풀게 됐지만 아직 부족하다.. 학습한 강의 더 자바, 코드를 조작하는 다양한 방법 스프링 데이터 JPA 실전! 스프링 데이터 JPA 실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화 자바 ORM 표준 JPA 프로그래밍 - 기본편 스프링 시큐리티 스프링 핵심 원리 - 기본편실무에서 내가 담당한 서비스는 100% JPA + QueryDSL었고 쿼리 최적화나 도메인간의 연관관계매핑이 중요했기 때문에 JPA강의를 많이 들었다.강의 외에 InfoQ 유투브에서 MSA 관련된 영상을 좀 봤는데 그것도 굉장히 좋았다. 비동기파이썬으로 프로덕션일부에 돌아가는 비동기 서버를 만들었다. 연초에 만들었는데, 비동기로 바꾼 뒤 성능이 굉장히 좋아져서 뿌듯했다.예외처리 하는게 좀 힘들었다. 당시엔 어렵고 힘들었고 시행착오를 많이해서 전체 리팩토링을 굉장히 많이 했었는데 기록해둘걸 하는 아쉬움이 있다. 총평이직 후 오픈과 운영하느라 정신없는 해를 보냈다.코로나로 인해 오프라인 세미나를 못가면서 점점 쳐진것도 있고 전체적으로 좀 지쳐서 개인공부에 게으른 해 였다.다만 실무에서 배운게 굉장히 많았고 새로운 경험도 많이 해봤다.팀에 백엔드 개발자는 대체로 나 포함 1~2명이었어서 아무래도 담당하게 되는 일이 많았고 그로 인해 다양한 작업을 접할수있어서 좋았다.다만 실무에서 새로운걸 많이 해보는 만큼 개인공부는 기존에 학습한것에 대해 깊이있는 공부를 했어야했는데 소흘했다.2021년엔 부지런히 학습하고 새로운거보단 깊이있는 학습을 하고싶다.","categories":[{"name":"Logs","slug":"Logs","permalink":"https://sehajyang.github.io/categories/Logs/"}],"tags":[{"name":"weekly","slug":"weekly","permalink":"https://sehajyang.github.io/tags/weekly/"}]},{"title":"2020년 하반기 회고","slug":"20200801-20201025","date":"2020-10-25T14:30:00.000Z","updated":"2021-06-20T04:25:47.784Z","comments":true,"path":"2020/10/25/20200801-20201025/","link":"","permalink":"https://sehajyang.github.io/2020/10/25/20200801-20201025/","excerpt":"","text":"그간 회고를 작성하지 않았는데, 회고를 작성하지 않으니 뭘 했는지 도무지 기억이 나지 않았다. 그래서 오랜만에 회고를 작성해본다.요즘은 JVM책을 읽고 있다. [JVM성능튜닝이야기]라는 책인데 어려울거란 걱정이 무색하게 책은 정말 이해하기 쉽게 쓰여져있다. 더 자바 강의도 완강했다. JVM 책 읽기 전에 들었는데 그 덕에 JVM 책 읽기가 한층 수월했다.중간에 해커톤도 나가서 상을 타왔다. 올해는 코로나때문에 해커톤을 못할 줄 알았는데 온라인 해커톤을 할 수 있어서 좋았다.요즘은 지인들이랑 릴리즈를 목표로 한 토이프로젝트를 만들고있다. 오랜만에 여러 사람들과 하는 토이프로젝트고 토이프로젝트인만큼 자유도도 높고 즐겁게 하고있다.알고리즘 스터디를 8월 초 부터 시작했다. 중간에 한계를 느끼고 프로그래머를 위한 기초 수학이라는 책을 샀다. 하반기에 한 학습 및 개발 ELK 구축 ECS with Netflix OSS to EB 이팩티브 자바, 오브젝트 더 자바 강의 완강 스프링 핵심원리 강의 JVM 성능튜닝 이야기 엔젤핵 해커톤 토이프로젝트 알고리즘 스터디 ELK 구축회사에서 ELK 로 로깅 시스템을 구축했다.우리 서비스들은 ecs + fargate로 되어있으며 ec2처럼 직접 접근할수 없었기 때문에 그간 papertrail 라는 cloud 로깅 서비스를 이용하고있었는데 한달 200기가에 160만원정도로 굉장히 비쌌다.물론 EFS를 사용하면 컨테이너 내부의 스토리지에도 접근할수 있지만 이 또한 100기가에 30달러로 굉장히 비싸다.우리 서비스는 한달에 약 400GB 정도 로그가 쌓이기 때문에 비용적인 측면에선 적절하지 않았다.그리고 ELK도 managed 로 구축하면 비쌌기때문에 ec2에 직접구축했다(사이즈는 t3 xlarge로 했는데 널널했다)구글링해보면 구축하는 방법에 대한 내용은 많지만 구축한 뒤 최적화 하는 내용은 별로 없었다.우선 우리 서비스 컨테이너 내부에서 로그를 파일로 쌓도록 했다. 처음엔 tcp 포트를 열어서 웹서버에서 tcp 스트림으로 logstash 로 로그를 보내주는 방법을 하려고 했으나 그렇게 구성하면 웹서버가 받는 부하가 크기때문에 파일로 쌓고 filebeat가 중앙 수집기(logstash)로 보내도록 했다.로그는 logstash 에서 정규식으로 메세지를 분석해서 필드화 하는 방법이 있는데, 정규식은 비용이 비싸기 때문에 logstash 가 받는 부하를 줄이고자 웹서버에서 파일로 쌓을때 json 형식으로 쌓도록 하고 logstash 에선 간단한 데이터 후처리나 필드 제외 작업만 하도록 구성했다.이렇게 하니 logstash가 처리해야할 연산이 복잡하지도 않았고 작업량도 아주 많진 않았기 때문에 logstash가 받는 부하가 적었다. 그리고 filebeat에서 send 딜레이를 줬기 때문에 중간에 redis같은 버퍼를 둘 필요도 없었다.es에도 부하가 크진 않았기 때문에 굳이 es 노드를 3개 둘 필요는 없어서 한개만 사용하도록 했는데, 나중에 인덱싱 부하가 커지면 세개로 늘릴 예정이다.웹 서비스 특성상 request response를 다 남기게 되는데 단순 get 요청같은 경우 es에 넣을만큼 중요한 데이터는 아니기 때문에 그러한 full log 는 일정 주기로 s3로 보내고, 중요한 데이터만 es로 보내고 시각화를 했다.처음엔 팀원의 요청으로 request, response를 다 es로 보내고 kibana에서 시각화했는데 es에서 인덱싱은 문제가 없었으나 kibana로 보려고 하니 웹 브라우저가 뻗어버렸다.당시 로그가 1 row 당 50만 byte 그러니까 50kb였고 브라우저에선 한번에 몇백개씩 로그를 렌더링해야했기 때문에 브라우저가 뻗는건 당연한것이었다.이쯤되면 최초 구축할땐 보이지 않았던것들이 보였다. 가령 웹서버에 aws log agent를 붙이고 cloudwatch로 로그를 받아서 es로 로그를 보내줄수도 있고, efs를 쓰고 그 로그를 s3 + lambda => es 로 보내줄수도 있다.전자는 fargate 를 사용할시 log agent 에 직접 configuration 을 적용할수없어서 못했으며(ec2에선 직접 log agent를 설치하고 설정을 할 수 있었다. 만약 fargate에 log agent 사용시 설정을 하는 방법을 아는 분은 댓글로 알려주시면 감사합니다) efs + s3 + lambda 방법은 비싸다.여러가지 시도와 고민끝에 나는 logstash multi pipeline communication 을 하기로 결정했다.웹서버와 filebeat의 부하가 최대한 적어야했기 때문에 logstash 쪽에 부하를 주는 방법을 선택했다.파이프는 총 세개로 구성했다. 로그를 수신받아 두 가상주소에 나눠주는 메인 파이프, 가상 주소로부터 받은 로그를 주기적으로 s3로 전송하는 파이프, logstash 필터를 거쳐 es에 인덱싱하기 좋게 가공해 es로 보내주는 파이프 이렇게 세개로 구성했다.그렇게 최종적으로 filebeat + logstash + elasticsearch + kibana + s3 로 로깅 시스템을 구축할수 있었다.웹서버에서 로깅을 위해 logging filter 를 만들고 리팩토링하고 로깅 전략을 세우기도 했는데 많은 삽질을 하긴 했지만 재미있었다.시행착오를 많이 겪었기 때문에 최소한의 최적화나 고생했던 부분등을 포스팅할 생각을 하고있다. 이팩티브 자바, 오브젝트이팩티브 자바를 2/3정도, 오브젝트를 반정도 읽었다.오브젝트는 도메인 설계하는데에 아주 좋았다. 책임을 나누고 응집도 높고 유연한 아키텍쳐를 설계하는데에 도움이 됐다.특히 객체를 의인화해서 본다는 부분에서 충격을 받았고, 객체와 행위의 주체를 생각하며 도메인을 설계할수 있었다.웹 서비스 특성상 변경이나 기능 추가가 잦은데, 이렇게 책임과 역할을 나누면서 설계하니 도메인이 꽤 깔끔하고 유연해졌었다. 더 자바 강의 완강백기선님의 [더 자바] 강의를 완강했다. 목차에 JVM 내용이 있어서 JVM 책 읽기 전에 수강했는데, JVM 동작원리와 함께 간단한 예제가 있어서 좋았다. 엔젤핵 해커톤작년에 이어 올해도 엔젤핵 해커톤을 나갔었다. [후기 글] JVM 성능튜닝 이야기올해 읽은 책중 가장 좋았다. 이 책은 올해의 책이다. 토이프로젝트지인들끼리 일반 유저에게 서비스 할 목적으로 만들고있다. 처음엔 MSA로 설계했는데 비용때문에 모노레포가 되어버렸다.도메인 지식이 있는 상태에서 설계하니 확실히 과거에 하던 개인 프로젝트와는 다르다는 생각이 들었다.나는 유저 및 인증쪽을 전부 담당했다. 인증전략을 직접 세우고 플로우를 짰다. 처음부터 설계하면서 구현하는데 요 일년간 꽤 배운게 많았었다는 생각이 들었다.빨리 완성해서 서비스해보고싶다. 다음달에 할 학습 알고리즘 토이프로젝트 웹서버 로깅 포스팅 총평올해가 2개월밖에 남지 않았다. 신입땐 난 이런것도 할수있어요 였다면 지금은 당연하고 능숙하게 해야한다는 느낌이다.그래서 요즘 내가 너무 서툴고 모르는게 많은것 같다는 생각도 들었다.과거엔 그래도 다 할수있다는 근거없는 자신감이 있었는데 요즘 없어진걸 보면 더닝크루거 곡선의 우매함 꼭대기에 있다가 뚝 떨어진게 아닐까 싶기도하다.그래도 막상 토이프로젝트를 밑바닥부터 만들어보니 요 일년간 배운게 꽤 많았었다는 생각이 들었다.아무튼, 남은 2개월은 밀린 기술 포스팅도 하고 알고리즘하고 토이프로젝트도 하면서 보낼 예정이다.","categories":[{"name":"Logs","slug":"Logs","permalink":"https://sehajyang.github.io/categories/Logs/"}],"tags":[{"name":"weekly","slug":"weekly","permalink":"https://sehajyang.github.io/tags/weekly/"}]},{"title":"AngelHack 2020 서울 우승 후기","slug":"20200726-angelhack-2020-seoul-review","date":"2020-07-26T08:24:48.000Z","updated":"2020-07-28T04:15:27.370Z","comments":true,"path":"2020/07/26/20200726-angelhack-2020-seoul-review/","link":"","permalink":"https://sehajyang.github.io/2020/07/26/20200726-angelhack-2020-seoul-review/","excerpt":"","text":"작년에 나갔었던 엔젤핵 해커톤을 올해도 한다는 소식을 듣고 지인들과 함께 지원했다. 다시보면 부끄럽지만, 당시에 작성했던 후기는 이렇다.AngelHack 2019 서울 참석 및 우승 후기 작년엔 직접 현장에 도착해서 팀을 구했는데, 올해는 지인분들과 함께 팀을 구성하게 되었고 어쩌다 보니 우리 팀은 개발자 5명인 팀이었다.코로나로 인해 모든 진행은 슬랙을 이용한 온라인으로 이루어졌다.온라인인 만큼 기간은 일주일이었으며, 올해 주제는 코로나였다. 작년과는 달리 이번엔 기업에서 주제를 정해주고 원하는 주제에 지원하는 방식이었다. 주제는 UN이 제안하는 17가지의 지속 가능한 개발 목표(UN-SDGs)을 바탕으로 선정되었으며 최소 1개, 최대 2개이하로 주제를 선택할 수 있다. 우리 팀은 처음엔 커먼컴퓨터, 우아한형제들 주제에 지원했었다.당시 아이디어는 코로나로 인해 기업에서 수급받아야 할 자원을 수급받지 못해 생기는 문제가 많으니 국제 자원 중개 서비스를 해서 그런 부분을 해결 해보자는 것이었지만, 국가 간의 규제가 천차만별이었으므로 문제가 많았다. 그렇게 아이디어 고민만 금요일 저녁까지 했다.금요일 저녁까지 고민한 끝에 우리는 기존의 국제 자원 중개 서비스를 버리고 지역 기반 소상공인 공동구매 서비스를 하기로했다. 우리 서비스는 코로나 때문에 어려움을 겪고 있는 많은 소상공인이 젓가락, 봉투 등의 부자재 혹은 재료 등을 공동구매 하거나 사용하지 않는 물건을 자유롭게 사고팔 수 있는 지역 기반 서비스이다.아이디어가 바뀜에 따라 지원하는 주제도 커먼컴퓨터와 테이블매니저 과제로 변경했다.엔젤핵은 다른 해커톤과는 다르게 평가 기준에 BM이 있다.그래서 우린 기존의 성공한 서비스들을 벤치마킹해 수익은 지역광고와 공동구매 중간유통 수수료로 결정했다. 커먼컴퓨터 주제는 커먼컴퓨터의 Ainize 란 서비스를 사용해 배포하면 되는 것이었다.Ainize는 깃허브에 올라와 있는 오픈소스 프로젝트를 무료로 쉽게 실행하고 배포할 수 있도록 도와주는 서비스이다.우리 팀은 프론트 서버와 백엔드 서버 둘 다 Ainize 통해 배포하기로 했다. 월요일부터 일요일까지 하는 해커톤이지만 금요일 저녁에 아이디어가 나와서 개발할 시간이 적었다.하지만 다행스럽게도(?) 개발자 5명인 팀이라 기능 완성을 못하는 것에 대한 걱정은 없어 다행이었다.그렇지만 늦게 시작한 만큼 포기할 수밖에 없는 기능도 있어서 조금 아쉬웠다.사실 채팅을 넣고 싶었다. 하지만 시간상으로 힘들 것 같아 포기했다. 주제가 명확해졌으니 다 같이 모여서 금요일 밤~ 일요일 제출 전까지 달렸다.웹 프레임워크는 장고가 선택되었는데, 장고로 개발하면 사용자 인증 및 CRUD를 빠르게 개발할 수 있어 해커톤에 적합했으며, 우리가 만들어야 할 서비스는 정확히 사용자 인증 및 CRUD API만 구현하면 되기 때문이었다. 그리고 날 제외한 백엔드 개발자는 장고에 익숙했다.나는 스프링부트를 주로 사용하긴 하지만 플라스크로도 개발한 경험이 있었으므로 이 김에 장고를 써보자는 생각으로 장고 선택에 찬성했는데, 장고를 하루 만에 배워서 API 만들기는 생각보다 어려웠다.우선 스프링과 장고는 많은 차이점이 있었는데, 스프링과 달리 장고는 기본적으로 여러 가지 기능을 자동으로 만들어주는 많은 클래스와 함수 등이 있었고 이걸 기존에 알고 있어야 쓸 수 있었다.반면 스프링은 대체로 직접 구현해서 개발한다. 그런 나에게 있어 장고는 매직박스 같았다.게다가 장고로 개발을 하더라도 사람마다 구현하는 방법은 천차만별이었다. 백엔드 팀원끼리도 방식이 완전히 달랐으며 서치해서 나오는 방식도 다 달랐다.중간에 난 차라리 SpringBoot + RPC 로 개발하겠다 했지만 기각됐다.그렇게 혼란 속에서 나는 두 파이썬 개발자의 속성 장고 강의를 받으며 API 몇 개와 DB 모델링을 했다.장고는 모든 개발자가 다 할 줄 알아야 선택할 수 있을 것 같다. 그래도 이번 기회에 장고를 해볼 수 있어서 좋았다. 일요일 오전부터 크리티컬한 CORS 문제가 터졌다.설정도 다시 해보고 장고 CORS 라이브러리 문제인 줄 알고 찾아보기도 하는 등 많은 시도를 해봤지만, 원인은 의외로 Ainize의 istio 설정문제였다.정확히는 Ainize 측에서 CORS 헤더를 열어줘야하는데 몇 가지 헤더가 누락되어있어 발생 한 문제였다.커먼 컴퓨터측에 문의 하니 신속하게 대처해주셔서 성공적으로 배포할 수 있었으며 이 이슈는 이번 해커톤 이후에 핫픽스 할 예정이라 하셨다. 마감은 23시 59분이었고 우리 팀은 시간 부족으로 인해 시연 영상을 일부 올리지 못해 아쉬웠으나 23시 56분에 아슬아슬하게 제출했다. 그리고 대망의 22일 수요일에 수상자가 발표되었다. 우리 팀은 커먼컴퓨터 부문에 수상하게 되었다!사실 우리 팀은 딱히 수상 기대를 하지 않고 있었다. 그도 그럴 게 굉장한 팀들이 많았기 때문이다.심지어 화상 채팅을 구현한 엄청난 팀도 있었다(그 팀은 코드스테이츠 부문을 수상하셨다)우리 팀이 기술적으로 엄청난 건 없지만 아마 준수한 코드 퀄리티와 BM 덕에 수상할 수 있지 않았을까 라고 생각한다. 다들 잠도 못 자고 고생을 많이 했지만, 우리 팀은 프론트(풀스택) 1, 백엔드 3, 앱 1로 구성된 팀이라 특히 프론트엔드 개발자분과 기획, 디자인, PPT, 영상까지 하신 앱 개발자분이 고생을 많이 하셨다.특성상 프론트엔드 이슈가 많을 수밖에 없는데 프론트엔드 개발자 팀원님이 혼자 프론트 이슈를 다 처리하셨으며, 앱개발자님은 본인의 전문 분야가 아님에도 불구하고 좋은 디자인과 엄청난 발표자료 및 영상을 만들어주셨다. 그렇게 7월 13일(월) ~ 7월 22일(수)까지 진행된 2020 엔젤핵은 막을 내렸다. 원활한 운영에 힘써주신 운영진분들, 멘토분들, Ainize분들, 팀원분들 모두 감사합니다 🙇🏼♂️ 소스는 GitHub에 공개되어 있습니다 => [AngelHack LiBi Repository]피칭영상 => AngelhackSeoul 2020 - Team LiBi, ‘사이’ Pitching읽어주셔서 감사합니다. #엔젤핵서울 #AngelhackSeoul2020Online #해커톤 #hackathon #개발자 #기획자 #디자이너 #코로나19 #함께이겨내요","categories":[{"name":"Seminar","slug":"Seminar","permalink":"https://sehajyang.github.io/categories/Seminar/"}],"tags":[{"name":"hackaton","slug":"hackaton","permalink":"https://sehajyang.github.io/tags/hackaton/"}]},{"title":"2020년 4월~5월 회고","slug":"202004-202005","date":"2020-05-30T14:50:00.000Z","updated":"2020-05-30T14:47:08.088Z","comments":true,"path":"2020/05/30/202004-202005/","link":"","permalink":"https://sehajyang.github.io/2020/05/30/202004-202005/","excerpt":"","text":"입사한 뒤 오픈 준비하느라 3달간 바빠서 스터디도 주간회고도 못썼다.길었던 3개월이 끝나고 이제 오픈했으니 다시 회고를 적어본다!두달만에 회고를 적는만큼 두달간 한 학습 및 개발이 꽤 다양하다. 두달간 한 학습 및 개발 Neflix OSS Spring Cloud Config Spring Data Envers AWS ECS QueryDSL Neflix OSSMSA에 대해 막연하게 알기만 하고 해본적은 없었는데, 아키텍쳐가 MSA로 되어있어 우선 MSA에 대해 공부를 했었다.서비스는 Neflix OSS 중 Eureka, Zuul, Ribbon, Feign, Hystrics 등을 쓰고 있었는데 다음과 같은 역할을 하는 넷플릭스의 오픈소스이다.간단하게 정리하자면 다음과 같다. Eureka: 서비스 디스커버리Zuul: jvm 기반의 라우터, 쉽게말해 api gateway, 서버측 부하 분산이나 일부 필터링을 수행Ribbon: 부하 분산 및 서비스 디스커버리, 캐싱, 일괄처리, 장애내성과 통합가능Feign : 선언적인 REST ClientHystrics : circuit breaker 예전엔 Elastic Beanstalk이 로드 밸런싱이나 Auto Scaling을 알아서 해줬지만, Netflix OSS를 쓰니 하나하나 설정해줘야 해서 이해하는 것 부터가 어려웠다.무엇보다 내가 지금 Netflix OSS에 대한 이해도가 높지 않다.. 관련된 포스팅을 하며 공부를 해볼까 했는데 이래저래 바쁘다보니 미뤄졌다.Netflix OSS에 관련된 자료도 적고, 사례도 많이 적었다. 관련된 세미나나 자료가 좀 더 늘었음 좋겠다. Spring Cloud ConfigMSA에선 모든 서비스의 설정을 관리하는 환경 설정 중앙 관리 서버가 필요하다.Spring Cloud Config는 서비스의 모든 환경설정 속성 정보를 저장하고, 조회하고 관리할 수 있게 해주는 외부화된 환경설정 서버다.이 cloud config 서버를 만들었는데, 구현자체는 어렵지 않았지만 자료가 정말 적어 커스텀하게 만드는게 정말 굉장히 어려웠었다.특히 서비스 디스커버리에 대해 의존성이 생길것이냐, 서비스 디스커버리가 config 서버에 의존성이 생기게 할 것이냐는 문제가 있었는데, 처음엔 이해를 못해서 데드락 같은 상황이 벌어지기도 했다.cloud config 에 관련된 포스팅은 조만간 작성할 예정이다. Spring Data Envers사내 서비스들에 적용하기 위해 공부했었다.spring data envers 로 데이터 변경 로깅하기 라는 포스팅을 작성했다.data envers는 여러 장단점이 있지만, 개발자가 백업 테이블을 만드는 노가다를 하지 않아도 된다는 강력한 장점이 있으므로 굉장히 추천하고싶다. AWS ECSAWS ECS를 처음 써봤다. 정확힌 회사 서비스가 ECS로 배포되고, 관리되고 있다. 코로나가 아니었다면 컨테이너 소모임에 갔을텐데 아쉽다. QueryDSL프로젝트가 QueryDSL을 사용하고 있었기 때문에 입사 초기에 공부했었다.그때 김영한님의 실전 Querydsl 강의를 다 봤다.생각보다 어렵지 않았고 별 거 없었다. 쿼리 최적화 부분이 인상깊었다.JPA + QueryDSL은 정말 최고다. 가끔 좀 답답할 때가 있지만 MyBatis 보단 훨씬 좋다.xml을 쓰지 않아도 되고, 쿼리를 하나하나 작성하며 관리해야하지 않아도 된다는게 정말 좋다.테이블간의 관계에 집중하고 객체로 보는점도 자바의 컨셉과 딱 맞는다. 더 이상 MyBatis를 쓸 이유가 없다!JPA 공부도 같이 했다. JPA 강의 두개를 봤고 책은 자바 ORM 표준 JPA 프로그래밍 과 회사 코드를 보며 학습했다. 다음달에 할 학습 spring security 강의 수강 이펙티브 자바 오브젝트 스터디 총평오픈을 앞두고 급하게 많은 기술을 빨리 배워 빨리 적용해야했는데, 당시엔 힘들었지만 돌이켜보니 짧은시간에 배우고 적용한게 많았다.아직 해야할 건 많다. 당장 spring security 도 공부해야하고 얕게 공부한 것들을 좀 더 심도있게 공부해야하지만, 꾸준히 공부한다면 내년즈음엔 나름대로 잘하고 있지 않을까 싶다.","categories":[{"name":"Logs","slug":"Logs","permalink":"https://sehajyang.github.io/categories/Logs/"}],"tags":[{"name":"weekly","slug":"weekly","permalink":"https://sehajyang.github.io/tags/weekly/"}]},{"title":"spring data envers 로 데이터 변경 로깅하기","slug":"springboot-envers-logging-for-revision","date":"2020-04-15T08:57:00.000Z","updated":"2020-04-15T08:55:54.807Z","comments":true,"path":"2020/04/15/springboot-envers-logging-for-revision/","link":"","permalink":"https://sehajyang.github.io/2020/04/15/springboot-envers-logging-for-revision/","excerpt":"","text":"이 글은 이력 생성까지 다루고 있으며 이력 조회까지 다루고 있지 않습니다. envers 란envers는 hibernate 에서 만든 데이터 변경 이력을 로깅하기 위한 라이브러리입니다.과거엔 로깅을 위해 customer_hist 와 같은 엔티티를 정의하고 customer 에 insert, update, delete 등의 작업이 발생하면,history 테이블에도 같은 작업을 해줘야 했으며, 이력을 쌓아야 하는 테이블이 늘어날 수록 이러한 번거로운 반복작업을 계속해야했습니다.그러나 envers를 사용하면 이러한 번거로운 작업을 대폭 줄일 수 있습니다.기본적으로 jpa로 구현되어있으며 후에 spring에도 spring data envers 프로젝트로 추가되었습니다.spring data envers 역시 hibernate에서 관리하기 때문에 큰 차이는 없습니다. 의존성 추가2020.4월 기준 recent stable version인 hibernate-envers 라이브러리를 build.gradle에 추가해줍니다. 1compile group: 'org.hibernate', name: 'hibernate-envers', version: '5.4.14.Final' @Audited로 변경이력 저장할 테이블 생성변경이력을 추적할 엔티티에 @Audited 어노테이션을 추가해줍니다.만약 extends 한 엔티티의 이력도 추가되길 원한다면 @AuditOverride(forClass=BaseEntity.class) 도 추가합니다.그러면 기본적으로 총 두개의 테이블이 생성되게 됩니다.예를들어 customer 엔티티의 상단에 @Audited를 추가하면 다음과 같은 customer_aud, revinfo 테이블이 생성됩니다. 123@Entity@Auditedpublic class Customer {... } 이미지출처 : Hibernate Envers - History Data and Versioning 이 revinfo는 central revision table 로, 최초 1회만 생성되며, 이 revinfo 테이블을 삭제하거나 disable 할 순 없습니다.네이밍 및 필드 변경은 가능합니다.또한 rev 필드의 네이밍 변경을 각 테이블마다 다르게 줄 수 없습니다.customer_aud 테이블의 rev_type 은 int타입으로 생성, 수정, 삭제를 구분하는 컬럼입니다.값은 다음과 같습니다: 1230 : insert1 : update2 : delete 아쉽게도 타입, 필드명, 값을 변경할 순 없습니다. 테이블 변경이력 로깅에 대한 몇가지 디자인이 있지만, 이렇게 중앙에서 관리하는 테이블이 있는 방식은 createAt, createUser 등을 각 테이블마다 생성하지 않고 중앙 테이블에서 한번만 생성하면 된다는 장점이 있습니다.이렇게 revision 관리를 하는 테이블이 왜 필요한지에 대한 stackoverflow 글이 몇개 있으니 궁금하신 분은 읽어보시는걸 추천드립니다 database-design-for-audit-logging database-design-for-revisions store-all-data-changes-with-every-details property config 설정12345678spring: jpa: org: hibernate: envers: audit_table_suffix: _history revision_field_name: rev_id store_data_at_delete: true audit_table_suffix, audit_table_suffix 등으로 auditing table의 prefix, suffix를 수정할 수 있습니다.또한 revision_field_name 로 revision fk 로 쓰는 테이블들의 revid 바꾸고 싶은 경우 설정할 수 있지만 테이블마다 각각 rev_id를 따로 설정하는 것은 불가능합니다. (order_rev_id, product_rev_id 이렇게 개별로 설정 불가능)delete 시 aud 테이블에서 타겟 테이블의 pk 만 쌓을뿐 다른 필드의 값은 기본적으로 null 입니다.null이 아니라 delete 직전의 모든 필드의 값을 쌓고 싶다면 store_data_at_delete: true 를 설정합니다.더 많은 property config는 Envers Configuration Properties에서 확인해주세요. 필수 설정central revision table인 revinfo의 pk인 rev 컬럼의 타입은 기본적으로 int 로 되어있습니다. 데이터가 20억개 이상 넘어가면 오류가 발생하므로, 권남님 포스팅의 [REV 를 long 으로 변경해야한다]처럼 int 타입을 long 타입으로 변경해줘야 합니다. 그 외테이블이 서로 연관관계인 경우추적 테이블을 만들지 않을 경우연관관계 추적 테이블 생성은 되지만 추적하진 않을거라면 엔티티 내 필드에 다음과 같이 어노테이션을 추가합니다. 12345678@Entity@Auditedpublic class Customer { ... @OneToOne @Audited(targetAuditMode = NOT_AUDITED) private CustomerDetail customerDetail;} 연관관계 테이블 생성도 하지 않고 추적하지도 않을거라면 엔티티 필드에 다음과 같은 어노테이션을 추가합니다 12345678@Entity@Auditedpublic class Customer { ... @NotAudited @OneToOne private CustomerDetail customerDetail;} 양방향관계에선 AuditMappedBy로 관계 명시를 해줘야 합니다. @AuditMappedBy(mappedBy = “name”) @OneToMany + @JoinCoulmn 인 경우 @AuditJoinTable 123456789@Entity@Auditedpublic class Customer { ... @OneToMany @JoinColumn(name=\"customer_id\") @AuditJoinTable private Set<CustomerDetail> customerDetail = new LinkedHashSet<>();} 참고 : onetomany_code_with_code_joincolumn_code 상속관계에 있는 테이블도 audit 하고싶은 경우클래스 상단에 @AuditOverride(forClass=BaseEntity.class) 추가합니다.BaseEntity에 굳이 @Audited 추가해주지 않아도 됩니다. 그 외의 문제queryDSL과 함께 쓰면 조회시 호환이 되지 않는 문제가 발생합니다 [해당 이슈]다음과 같이 EnversQueryDslRepositoryImpl.java를 수정하여 해결할 수 있습니다.[EnversQueryDslRepositoryImpl.java gist] 혹 글의 내용이 잘못되었거나, 추가하실 부분 또한 궁금한 부분이 있다면 편하게 코멘트 남겨주세요.읽어주셔서 감사합니다. 참고 Hibernate ORM 5.4.14.Final User Guide Hibernate Envers - Easy Entity Auditing 권남-Hibernate Envers Spring Boot + Envers로 엔티티 이력관리하기 JPA에 audit 적용하기 스프링캠프 2017 [Day2 A5] : 엔티티 히스토리를 편리하게 관리해주는 스프링 데이터 Envers(영상)","categories":[{"name":"Springboot","slug":"Springboot","permalink":"https://sehajyang.github.io/categories/Springboot/"}],"tags":[{"name":"Springboot","slug":"Springboot","permalink":"https://sehajyang.github.io/tags/Springboot/"},{"name":"envers","slug":"envers","permalink":"https://sehajyang.github.io/tags/envers/"},{"name":"JPA","slug":"JPA","permalink":"https://sehajyang.github.io/tags/JPA/"}]},{"title":"2020년 3월 중간 회고","slug":"200217-200313","date":"2020-03-15T14:36:00.000Z","updated":"2020-03-15T14:35:11.572Z","comments":true,"path":"2020/03/15/200217-200313/","link":"","permalink":"https://sehajyang.github.io/2020/03/15/200217-200313/","excerpt":"","text":"3월 중순이 됐고 이번 월간회고는 패스하려다 그냥 작성하기로 했다.작성하지 않으려 했던 이유는 여러가지인데 코로나로 인한 세미나취소, 체력문제로 인해 한달동안 한게 별로 없었기 때문이다.이직으로 출퇴근 거리가 길어져 퇴근하면 지쳐서 아무것도 할 수 없었으며 그렇게 한달간 쉬었다.회고 작성을 본래 꾸준하게 해보자 라는 취지로 시작했었기 때문에 이번 회고를 작성하게 되었다. 나는 세미나를 꽤 자주 참석한다. 많게는 한달에 두번이상 참가하며 월 1회는 꼭 참가하는 편이다.세션을 보고 재밌겠다 내지는 괜찮을 거 같다 싶으면 가는데, 그 밖에도 열정이 좀 빠졌을때 참가하려는 경향이 있다.가서 이것저것 흥미로운 걸 보고 오면 열정도 채워지고 의욕도 생겼다.하지만 이번 코로나로 기대했던 aws summit, kcd2020, awskrug 소모임등이 취소되었다. 애널리틱스를 봤는데 많은 분들이 sqs lambda 글을 보는 것 같았다. 최근들어 주위에서 sqs에 대한 얘기가 들려온다.sqs 자료는 진짜 적기 때문에 이번달 안에는 반드시 2부를 써야겠다. 한달간 한 학습 및 개발 비동기 프로젝트 Fluent Python 읽기 알고리즘 스터디 1부 종료 비동기 프로젝트입사 후 처음 받은 일을 파이썬 비동기로 만들었다.짧은 시간내에 많은 작업(특히 네트워크 IO 작업)을 처리해야 했으므로 비동기로 만들었다.cpu bound 하지만 시간이 꽤 오래 걸리는 문자열 연산등의 작업은 run_in_executor 함수로 따로 쓰레드풀에서 돌게 하는둥 최대한 병목을 줄이고 blocking 함수를 루프안에 넣지 않기 위한 노력을 했다.클린하고 readablity 높게 만들고 싶은 욕심이 많았기 때문에 전체 구조를 뒤엎는 리팩토링만 수십번은 했다.하지만 그 덕분에 나중에 유지보수하기가 너무나 편했다.취소 및 재시도 처리 때문에 고생을 많이 했다. 비동기가 아니면 쉽게 에러처리를 할텐데 비동기라서 쉬운것도 어려워지는 부분이 많았다.비동기로 짜는 동안 정말 정말 힘들었는데 작업이 마무리되니 힘든건 다 까먹었다.결과적으로 기존엔 12800sec 걸리던 작업을 400sec 로 단축시켰다.빠르게 잘 돌아가는 프로젝트를 보니 뿌듯하고, 다음에도 이렇게 만들어야지 라는 생각이 들었다.이것저것 찾아보며 느낀건데, 한글로 된 파이썬 비동기 자료가 굉장히 적어 이번에 비동기 포스팅을 해봐야겠다.파이썬 동시성 프로그래밍 책도 샀다. 이 책을 선택한 이유는 단순한데, 번역된 파이썬 동시성 프로그래밍 책이 이 책 밖에 없었다. 다행히 내용은 탄탄하고 알차다! Fluent Pythonfluent python 책을 계속 보고있다. 사실 많이 보지는 못했다.두고두고 보려고 오랜만에 til에 정리한걸 조금 올렸는데, 아직 한 챕터밖에 올리지 못했다. 알고리즘 스터디알고리즘 스터디 1부가 끝이 났다! 거의 마지막엔 난이도도 올라가고 시간도 없어 제대로 풀지 못했다.2부는 아마 다음달중순 쯤에 시작할것으로 생각하고 있다. 도움이 많이 됐는데 마지막에 놔 버려서 슬프다..멘탈 회복되면 마지막에 못 푼 문제들 좀 풀어봐야겠다. 다음달 중순까지 할 학습 및 개발 JPA 강의 수강 Fluent Python 읽기 파이썬 동시성 프로그래밍 읽기 총평왜인지 모르겠지만 요즈음 의욕도 의지도 사라졌다.몇가지 이유가 있겠지만 코로나로 인해 세미나가 취소된 것도 큰 것 같다.어쨌든 의지도 없고 그래서 한달정도 놀았는데 딱히 할게 없어서 이제는 노는것도 스트레스가 됐다.해야할 공부는 많은데.. 큰일이다. 우선 해야할 공부부터 조금씩 해야겠다.","categories":[{"name":"Logs","slug":"Logs","permalink":"https://sehajyang.github.io/categories/Logs/"}],"tags":[{"name":"weekly","slug":"weekly","permalink":"https://sehajyang.github.io/tags/weekly/"}]},{"title":"2020년 2월 중간 회고","slug":"200113-200216","date":"2020-02-16T07:56:00.000Z","updated":"2020-03-15T14:21:37.978Z","comments":true,"path":"2020/02/16/200113-200216/","link":"","permalink":"https://sehajyang.github.io/2020/02/16/200113-200216/","excerpt":"","text":"저번 회고를 1월 중순에 작성한 탓에 2월도 애매하게 2월 중간에 작성하게 되었다.1월 중순과 2월 중순 사이에는 정들었던 첫 직장을 떠나 새로운 직장으로 옮기게 되었다.나는 best practice를 배울 수 있으면 좋겠지만 만약 그러지 못해도 좀 더 나은 코드 퀄리티나 최적화를 함께 고민할 수 있는 조직에 들어가고 싶어 이직을 결심하게 되었다.그렇게 한달정도 준비해 여러가지 배울수도 고민을 함께할 수도 있는 조직에 들어갈 수 있었다.이직 준비를 했다는건 굉장히 애매한데, 나는 평소에 기술 혹은 이렇게 회고 포스팅을 작성하거나 토이프로젝트를 하거나 세미나를 다니거나 했다.알고리즘 스터디도 하고 있었고.. 이러한 활동들은 이직할때 제출하는 자료들이 되었다.딱히 이직을 목표로 준비했다기보단 꾸준히 로그를 남겨보자는 생각으로 이것저것 해왔는데, 뭔가 여러모로 도움이 되었다. 한달간 한 학습 및 개발 알고리즘 문제 풀이(알고리즘 스터디) JPA 강의 수강 fluent python 이펙티브 자바 알고리즘 문제 풀이(알고리즘 스터디)한달간 무엇을 했는지 딱히 기억이 나지 않아 커밋로그를 보니 우선 깃허브엔 알고리즘 문제 푼 커밋밖에 없었다.알고리즘 스터디는 다행히 파토나지 않고 한달넘게 계속되고 있다.일주일에 한번 모여 코드 리뷰를 하고 강의 듣고 문제 다섯개를 풀면 되는데, 이게 회사를 다니면서 하려니 정말 어려웠다.특히 문제 다섯개 풀이는 처음엔 괜찮았으나 뒤로 갈수록 빡세지고있다.그래도 혼자 했으면 금방 포기했을텐데 여럿이 해서 다른 사람 코드도 볼 수 있고 아직 즐겁게 하고있다.알고리즘 풀다 운적도 있었다. 자괴감도 들고 분하기도 했다. 그렇지만 힘든만큼 얻는것도 많았다.전보다 사고력이 좋아졌음을 느끼고있으며, 한걸음 더 나아가 생각할 수 있게 되었다. 복잡한 로직을 짤 때도 선택지가 늘었음을 느낀다.결론적으로 알고리즘 스터디 정말 최고야! JPA 강의 수강주변 지인의 추천을 받기도 했고 이직한 곳에서도 JPA를 사용하기 때문에 JPA강의를 보기 시작했다.강의는 인프런의 김영한 님의 JPA강의를 듣고있으며 다 수강한 뒤엔 Query DSL을 수강할 예정이다.JPA를 사용할 줄은 알지만 잘 하지는 못했기 때문에 아직 배울게 많다.4월즈음에 스프링부트를 사용한 지인 두분과 Query DSL 스터디를 하기로 했다. fluent python드디어 fluent python을 보게 됐다. 한국에서는 전문가를 위한 파이썬 으로 알려져 있다.대체로 프로그래밍 언어의 문법을 익히긴 쉽지만, 그 언어의 특성에 맞게 잘 사용하긴 어렵다.fluent python은 파이썬을 pythonic하게 잘 사용하기 위한 책이다.이 책은 파이썬 초보에겐 적합하지 않다. 그래서 작년엔 보지 못했다.여담으로 출퇴근길에 읽기 위해 예사에서 ebook으로 샀는데 그냥 종이책으로 살걸 절절히 후회하고있다.앱은 더할나위없이 구리고 한번 다운받은터라 환불도 되지 않는다.만약 사실분은 ebook 리더기나 태블릿이 없다면 종이책으로 사는걸 강력히 추천합니다. 이펙티브 자바이직은 파이썬을 사용하는 곳으로 가려고 했으나 어쩌다보니 계속 자바를 하게 되었다.그래서 이펙티브 자바를 구매했다. 목차부터 좋은 책이라는 느낌이 들었다.아직 초장을 읽고 있다. 클린코드를 읽었을 때 처럼 많은걸 배우게 될 것 같다. 다음달에 할 학습 알고리즘 스터디 계속 실전! 스프링 데이터 JPA fluent python 읽기 이펙티브 자바 읽기 총평알고리즘을 꾸준히 해서 뿌듯했고, 과거에 개인적으로 공부했던 것 들을 뭔가 써먹을 수(?) 있었다.새 조직에 적응하느라 정신이 없지만 기대도 된다.지금은 어쩌다보니 이직한 곳에서 파이썬으로 코드를 작성하고 있는데 즐겁다. fluent python 도 재밌다.spring cloud 관련 업무를 받게돼서 조만간 관련 공부를 시작할 것 같다.","categories":[{"name":"Logs","slug":"Logs","permalink":"https://sehajyang.github.io/categories/Logs/"}],"tags":[{"name":"weekly","slug":"weekly","permalink":"https://sehajyang.github.io/tags/weekly/"}]},{"title":"2020년 1월 중간 회고","slug":"200101-200112","date":"2020-01-22T05:36:00.000Z","updated":"2020-02-16T07:42:20.388Z","comments":true,"path":"2020/01/22/200101-200112/","link":"","permalink":"https://sehajyang.github.io/2020/01/22/200101-200112/","excerpt":"","text":"2019년 연간회고 이후 올해의 첫 회고를 작성하게 되었다.이번달은 설 연휴가 껴서 그냥 1월 중순 회고를 작성하기로 했다.3주간 주로 알고리즘 스터디를 중점적으로 했다. 알고리즘은 시간 있을때 틈틈히 해두는게 재밌고 좋은 것 같다.그 밖엔 AWS re:invent 컨퍼런스에 갔다왔다. 3주간 한 학습 및 개발 알고리즘 스터디 7가지 동시성모델 AWS korea community day re:invent 컨퍼런스 참석 알고리즘 스터디요즘 친한 동료분들과 알고리즘 스터디를 하고 있고 시작한지는 2주 조금 넘었다.강의는 저번에 완강하지 못한 SW 역량 테스트 준비 - 기초 로 하고 있다.과거에 여러가지 스터디를 만들어도 보고 참여도 해봤는데 가장 효율이 좋았고 참여율이 높았던건 매 주 과제 + 발표 였다.그래서 알고리즘 스터디는 다음과 같이 진행하고 있다. 저번주에 선정한 문제(5개, 백준 실버 중위 ~ 골드 상위) 코드리뷰 및 문제 해결방법 설명 이번주 강의 수강 다음주에 풀 문제 선정 알고리즘 레포에 다음주 스터디 전 까지 푼 문제에 대한 소스코드 푸쉬 문제 난이도가 점점 올라가고 있어 평일에도 성실히 풀어야 모든 문제를 다 풀 수 있다(더 이상은 몰아서 푸는게 안된다..)1주차 문제중 골드바흐의 추측 문제의 시간초과 때문에 조금 고생하고 있었는데, 같이 스터디하시는분이 알고리즘 문제는 보통 시간 제한은 빡빡한데 공간제약은 굉장히 널널하다는 얘길 해주셨고 그말에 힌트를 얻어 쉽게 해결할 수 있었다. 앞으로 이 꿀팁을 자주 써먹어야겠다.2주차 문제중엔 게임 이라는 문제가 있었는데, 후에 할 게임을 모두 이겼다고 가정했을시, 몇판을 이겨야 승률이 변하는지를 출력하면 되는 문제였다.문제를 처음봤을땐 쉬울 것 같고, 제한이 10억이라 바이너리 서치로 풀어야겠다 라고 생각했는데 내가 뭘 잘못했는지 모르겠지만 잘 되지 않았다(지금 생각해보면 아마 부동소수점 오차 문제 떄문이었을 것이라 생각된다)당황해서 수학으로 풀어야지 하면서 식을 세웠는데 식을 잘못 세워서 고생을 좀 했다.3주차는 2주차에 못푼 문제와 3주차에 선정한 문제들을 설 연휴동안 풀 예정이다. 알고리즘 혼자할땐 힘들고 어려웠는데, 다같이 하니까 너무 재밌다. 특히 서로서로 어떻게 짰고 어떻게 접근했나를 얘기하며 코드를 보는게 재밌었다.다들 너무 잘하시고, 나한텐 난이도가 조금 높은 것 같지만 그래도 지금 이정도 난이도가 딱 좋은 것 같다. 7가지 동시성모델과거에 보다 만 책을 다시 폈다. 그때는 그냥 보기만 하고 예제를 직접 쳐보진 않았었는데 역시 이런 책은 직접 코드를 쳐봐야 하는 것 같다.저번 akka 프로젝트는 너무 별로였던지라 제대로 akka로 토이프로젝트 하나 만들고 싶어서 액터모델부터 다시 보려고 폈다가 그냥 처음부터 보고 있다.옛날에 나온 책이지만 정말 내용이 괜찮다. 중간에 알고리즘 문제 때문에 일시중지 되었지만 연휴에 바짝 볼 생각을 하고있다. AWS re:invent 컨퍼런스 참석가장 처음 세션 C 트랙 beNX에서 발표한 전 세계 팬들이 모일 수 있는 플랫폼 만들기 라는 세션이 정말 좋았다.평소에 분당 2.7만회 정도의 요청이 들어오다 특정 아티스트가 글을 쓰는 순간 분당 270만회로 요청이 뛰어버리는데, 아티스트가 글을 쓰는 시간이 정해져 있지 않다보니 이 이벤트는 불규칙하게 낮에도 새벽에도 발생할 수 있었다.그러한 과정에서 어떻게 하면 효율적이고 빠르고 안정적으로 트래픽을 핸들링할 수 있는지, 그렇게 하려면 어떻게 아키텍쳐를 설계해야 하는지, 서버최적화 설정은 어떻게 해야하는지 등의 아키텍쳐 설계 및 서버 튜닝에 대한 내용이었다. 정말 굉장하고, 유익했다.나는 그간 계속 beNX의 해당 서비스를 사용해왔고 트래픽이 한꺼번에 몰릴때에도 거의 안정적으로 서버가 살아있는 것을 보며 감탄했었다.급격한 트래픽을 대비하는 scalable 아키텍쳐를 어떻게 설계했을지 궁금했었는데 이번에 속 시원히 알 수 있었다. 이 세션에 대해서는 후기 포스팅을 따로 작성할 생각이다. 다음달에 할 학습 알고리즘 스터디 계속 7가지 동시성 모델 실전! 스프링 데이터 JPA 총평알고리즘을 즐겁게 할 수 있어서 알고리즘을 푸는데에 집중한 주 였다.확실히 작년보다 알고리즘을 더 잘 풀수 있게 되었다. 아직 많이 부족하지만 이렇게 일주일에 5문제씩 꾸준히 풀면 연말 즈음에는 정말 알고리즘을 잘 풀수 있게 되지 않을까 싶다.AWS 컨퍼런스는 정말 좋았다. 발표자분들이 준비를 많이 한 티가 많이 났던 것 같다 그만큼 내용도 정말 좋아서 새롭게 알게된것도 많았다.그리고 나는 1년 2개월간의 즐거웠던 헤렌에서의 회사생활을 마치고 다른 회사로 가게 되었다. 그간 또래분들이 많아 즐겁게 게임모임도 하고 개발 얘기도 할 수 있었는데 이젠 못 하게 되어 아쉽다..이직을 결정하게 된 이유는 더 깊게 배울 수 있는 기회가 왔다고 생각했기 때문이었다. 이직하는 곳은 지금까지와 마찬가지로 JAVA 및 스프링부트 스택이라, 올해안엔 토비의 스프링을 볼 생각을 하고있다. 하지만 파이썬도 포기할 수 없으니 fluent python도 볼 것이다.","categories":[{"name":"Logs","slug":"Logs","permalink":"https://sehajyang.github.io/categories/Logs/"}],"tags":[{"name":"weekly","slug":"weekly","permalink":"https://sehajyang.github.io/tags/weekly/"}]},{"title":"2019년 연간회고","slug":"2019-review","date":"2019-12-31T02:48:00.000Z","updated":"2020-02-03T12:04:36.730Z","comments":true,"path":"2019/12/31/2019-review/","link":"","permalink":"https://sehajyang.github.io/2019/12/31/2019-review/","excerpt":"","text":"2018 연간회고를 쓴지가 엊그제 같은데 벌써 2019가 끝나가면서 연간회고를 쓰게 되었다.올해 뭐 했지 싶다가도 2018년부터 지금까지 작성해온 회고들을 보니 저때 저런것도 했었지 싶어 꾸준히 회고쓰기 참 잘했다는 생각이 들었다.1년간 중단하지 않고 느리게나마 꾸준히 주간 회고를 작성해왔는데 올해 잘한일 중 하나이다.이번 연간 회고는 2018년에 비해 얼마나 성장했는지, 2019년엔 어떤 기술을 배웠으며 어떤 토이프로젝트를 만들었는지를 작성하려한다. 2018년에 배운 기술과 지금을 비교해보자 Git, GitHub 작년엔 Git, Github를 처음 접했었다. 작년엔 토이프로젝트에서 revert 사고도 치고, conflict도 잘 해결하지 못해 끙끙댔는데 이젠 능숙하게 깃을 다룰 줄 알게되었다. 이젠 동료분들에게 깃 관련 문제가 생길때 마다 용병(?)갈 정도로 능숙해져 뿌듯하다. GitHub Blog 작년엔 jekyll을 이용해 깃허브 블로그를 처음 만들었었고 그로인한 많은 시행착오와 삽질이 있었다. 특히 jekyll theme를 포크떠서 시작하는경우 기존의 디자인을 깨트리지 않으면서 원하는 기능(사이드 바 등)을 넣기가 어려웠다.그러던 차에 우연히 hexo를 발견하게 되었다. 지금은 hexo로 갈아탔다. 지금 블로그는 마음에 들며, 앞으로 딱히 바꾸지 않을 것 같다. 올해 회사 기술블로그를 만들었다. jekyll로 깃허브 블로그를 만들었는데 오픈까지 대략 하루~이틀정도 걸렸던 것 같다.과거에 해뒀던 삽질들 덕분에 이번엔 빠르고 쉽게 구축할 수 있었다. React 난 더이상 리액트 공부를 하지 않는다. 프론트에 별 관심이 없어졌기 때문이다. 프론트가 나와 맞는지 아닌지 알아내기 위해 조금이나마 Vue도 해보고 리액트도 해보고 심지어 리액트 네이티브도 하는 등 조금씩 공부해봤지만 나와는 별로 맞지 않았던 것 같다. 나는 백엔드가 재밌다. 그래서 리액트는 더이상 하지 않는다. CI/CD 작년엔 jenkins로 처음으로 CI/CD를 구축했었다. 자동배포라니! 올해는 회사에 Jenkins로 자동배포환경을 만들었다. 작년의 경험이 있어 올해는 회사에서 쉽게 구축할 수 있었다. 또한 TravisCI, Gitlab CI, AWS CI/CD(aws code commit부터 deploy까지)를 이용한 자동배포 구축등 이제 왠만한 CI/CD 구축 및 설정을 무리없이 할수있게 되었다. 2018년에 배웠던 기술들은 올해 더욱 능숙해졌다. 1년뒤 2020년 회고를 쓸때 2019년에 배운 기술에 비해 더 많이 발전했다고 쓸 수 있으면 좋겠다. 2019년에 배운 기술클린코드클린코드를 읽었다. 그간 구현에 급급했는데. 이 책을 읽고 더 나은 네이밍, 아키텍쳐, 가독성을 고려하게 되었으며 테스트코드를 작성하기 시작했다.이 책은 내 코딩스타일을 완전히 바꿔놓았다. 그 이후로 나는 주위 동료 개발자들에게 이 책을 추천하고 다녔다.약간 책 홍보같은데.. 그정도로 나한텐 좋은 책이었다. 이 주제로 사내 스터디에서 발표도 했다 [클린코드와 TDD] TDD와 테스트코드막연하게나마 느껴졌던 TDD를 클린코드를 읽고 시작하게 되었었다.처음엔 자료가 적어 구글링을 하거나 책을 보며 서툴게나마 시작했는데 지금은 능숙 까진 아니여도 무리없이 테스트코드를 짤수 있게 되었다.그 과정에서 groovy의 테스트 프레임워크인 spock로 BDD를 해보기도 하고 테스트코드 작성에 관한 포스팅을 작성하기도 했다.처음엔 어떻게 짜야할지 몰라서 무작정 작성했다. 애초에 테스트를 하려면 테스트대상을 리팩토링해야 하는데 그래야하는 줄 몰라서 엄청 고생했었다.레거시를 리팩토링해 나가면서 기능별로 테스트코드를 작성하다보니 지금은 어떤 기능을 어떻게 테스트할건지, 이 기능을 테스트하려면 어느부분을 mocking하고 어느부분을 assert 해야되는지를 조금 알게 되었다. 그렇게 프로덕션에 테스트코드 통합 커버리지 80퍼센트를 달성하게 되었다.우아한형제들에서 진행한 DDD교육에선 기능 구현을 위해 무조건 테스트코드를 짜야 했는데 다른 사람이 짠 테스트코드를 보면서 많이 배울수 있었다. 서버리스사내 레거시 문자시스템을 서버리스로 분리 및 구축했다. 어떻게 하면 정확한시간에 병목없이 대량 문자를 발송할수 있는지에 대한 고민을 많이 했는데, 그 과정에서 고려한게 MQ, SQS와 람다였다.그 당시에 나는 MQ를 이용한 개발도, 서버리스 환경도 경험이 많지 않았는데 설상가상으로 구글링해봐도 관련 자료가 많지 않았다.그래서 구축할때 굉장히 힘들었었다. [그때 당시의 포스팅1] [포스팅2]그 뒤에도 운영단계에서 몇번 터졌지만 지금은 안정적으로 처리할 수 있도록 구축해뒀다.구축하느라 정말 힘들었지만 안정화가 되면서 터지지도 병목이 생기지도 않아서 지금은 서버리스로 바꾸길 잘했다는 생각을 하고있다.이후에 이 구축기를 get started 격의 포스팅으로 만들었다 [SQS, Lambda를 이용해 문자전송하기(1부)] Scala스칼라를 배웠다. 그냥 함수형 해보고싶어서 언어를 고르는데 스칼라가 좋았다. 그 과정에서 Scala vs Kotlin 같은 포스팅을 작성하기도 했다.학습은 마틴오더스키-Programming in Scala 책과 코세라 강의 그리고 scala-exercise 사이트로 했다. scala-exercise 의 튜토리얼은 마틴오더스키님의 강의자료인데 번역이 되어있지 않아 겸사겸사 번역을 했다.[번역 리스트]총 15개의 챕터중 8개를 번역해뒀으며 나머지는 내년 상반기안에 끝낼 생각을 하고있다.스칼라는 듣던대로 어려웠다. 문법익히는 것 부터 어려워서 code wars등을 풀거나 자바코드를 스칼라 코드로 포팅하는 식으로 문법을 익혔다.사내에서 쓸 환경변수를 관리하는 S3 파일 서빙 서버도 만들었는데 그땐 akka-http로 만들었다(그리고 어려웠다) 아직 미숙하지만 2020년엔 좀 더 능숙해졌으면 좋겠다. 비동기올해초에 비동기를 접하게 됐다. 비동기 기초 정리파이썬 asyncio등의 공식문서를 보며 공부했는데 도움이 많이 됐다. 특히 7가지 동시성 모델 이란 책이 좋았다.그렇게 회사에서 오래걸리는 작업들을 처리하던 파이썬 스크립트들을 asyncio로 리팩토링하면서 소요시간을 대폭 줄일 수 있었다.비동기 프레임워크를 사용해 [sanic-chatting-project][real-time-ws-pubsub-baas-api] 등의 토이프로젝트를 하기도 했다. 오픈소스 컨트리뷰트hexo 프레임워크의 rss 관련해 첫 컨트리뷰트를 했다 [fix : add feed icon to rss2.xml #102]그냥 rss에 이미지를 넣고싶어서 해당 파일 수정 후 풀리퀘를 날렸는데 해당 부분을 수정하면서 발생하는 문제들이 있어 생각보다 신경써야할 부분이 많았다. 그러나 엄격한(?) 스택오버플로우와는 달리 깃허브는 조금 더 친절한 분위기였다. 나는 JS를 잘 못하지만 친절한 hexo 컨트리뷰터 및 오거나이져분들의 도움으로 무사히 작성 후 merge 될 수 있었다. 크롤링크롤링 고수이신 지인분께 크롤링 과외를 받았다. 특히 패킷까보면서 하니 신세계였다. 그렇게 크롤링을 할 수 있게 됨에 따라 회사에서도 크롤링을 참 많이 하게되었다.. 직접적으로 일상생활에(나에게) 도움이 되는 것들을 많이 만들었는데, 대략 세미나나 콘서트 자리나면 알려줌 이라던가 무료게임이나 날씨정보를 주기적으로 보내준다거나 비행기등의 최저가가 뜨면 알려준다거나하는 것들을 만들었다. 내년에도 이것저것 크롤링해서 소소하게 도움이되는 것들을 만들 것 같다. 2019년에 진행한 토이프로젝트sanic chatting projectpython의 sanic 프레임워크로 만든 채팅 서버이다. 비동기 학습 후 처음 만든 비동기 채팅서버인데 채팅서버다 보니 DB부터 신중하게 찾아보며 골랐다.asyncio-redis 라이브러리의 문서가 빈약해 고생하긴 했지만 여차저차 구축할 수 있었다.api document도 만들고.. 여러모로 신경을 좀 쓴 프로젝트였다. real time ws pubsub baas apiAmazon에서 주최한 Amathon에서 python으로 만들었던 프로젝트이다. Amathon 참가 포스팅우리조 주제는 websocket 기반의 스케일아웃 고려한 real time Pub/Sub Baas였고 python asyncio + sanic + redis + zeroMQ 등을 썼었다.구조는 이러했다. 내 생각엔 beanstalk 같은 scalable 한 서비스를 만들어 beanstalk을 대체했어야 할 것 같았는데 시간이 촉박해 그러진 못했다(그리고 그부분이 가장 어렵다) 다른 조 주제도 재미있는게 많았고 내년에 또 열린다면 참가할 것 같다. racoon man너굴맨 이라는 슬랙봇 이다. python 으로 만들었으며 심심할때마다 기능을 조금씩 붙여 지금은 굉장히 거대해졌다.9XD의 유이 라는 슬랙봇에서 아이디어를 얻었으며 회사 개발자들의 소소한 유희(?)을 위해 만들었다.지금은 동료분들의 많은 사랑을 받고 있다. 너굴맨에는 다음과 같은 기능이 있다. 날씨 및 미세먼지, 한강수온, 현재 비 오는지 여부 알림 랜덤 골라줌, 로또 번호 골라줌, 점심 및 저녁추천 한영 번역 기능 festa 세미나, 오늘의 운세 알림 기능 일정 기억 기능 소라고동 기능 pingpong 챗봇 api를 붙여 사람같이 대답하는 기능 기타등등 등록해둔 대답 셋 simple anonymous boardjava의 springboot로 사내 익명게시판을 만들었었다.github project로 일정관리부터 문서까지 만들었으며, 사용하고 싶은 기술을 많이 사용해서 재밌었다.특히 프론트는 handlebars 를 사용했는데, 어려웠지만 커스텀 함수를 쉽게 만들 수 있어 개인적으로 thymeleaf 보다 좋았다. angelcell admin이 프로젝트는 AngelHack 2019 Seoul 해커톤 에서 만든 커넥터스라는 서비스의 모니터링 서버인데, springboot로 만들었다.후기 포스팅을 작성했었다.해커톤에서 스프링부트로 개발하는건 좀 아닌것 같다는 생각이 들었었다. 설정잡는데에 꽤 시간이 걸렸으며 자바 자체도 보일러플레이트가 많은 언어라 짧은 시간에 많은 코드를 작성하느라 많이 힘들었었다.역시 해커톤은 파이썬인 것 같다. 올해는 토이프로젝트를 하기보단 그냥 자잘한 스크립트나 학습위주로 해서 만든 토이프로젝트가 적을 줄 알았는데, 모아보니 생각보다 많은 것 같다.내년엔 보안관련 C 오픈소스 프로젝트를 만들 생각을 하고 있다. 아마 내가 여지껏 한 프로젝트중 가장 어렵고 가장 괜찮은 프로젝트가 될 것이다. 2019년에 참석한 세미나 및 해커톤다음은 2019년도에 참석한 세미나 및 해커톤 리스트이다. 191127 우아한 테크 러닝 - DDD 세레나데 교육 191028 스포카 크리에이터 컨퍼런스: Hello World! 190926 우아한 테크 세미나 - 우아한 스프링배치 참가 190901 Amathon 2019 참가 190824 뱅크샐러드 컨퍼런스 Con-Salad 05 190817 Pycon Korea 2019 양일 참석 190807 AWSKRUG GraphQL모임 190630 I/O Extended 2019 Seoul 190602 AngelHackaton Seoul 2019 190427 Spring camp 2019 190316 코무-프론트엔드와 무관합니다만, 190223 KCD(Korea Community Day) 2019 하나하나 정리를 하려 했지만 내용이 너무 많아지며, 주간회고에서 한차례 정리를 했었기 때문에 연간회고에서 따로 정리하진 않으려 한다.주로 페스타나 밋업 혹은 동료분들의 영업 으로 종종 세미나나 밋업에 참석하는데 올해 가장 기억에 남는 세미나는 KCD와 파이콘이었다.KCD는 스칼라를 시작하게되는 계기가 되었으며 파이콘은 즐거웠어서 기억에 남는다. 2019 총평올해는 꾸준히 주간회고를 쓰며 많은 학습을 한 해였다 포스팅은 올해 45개를 작성했다. 이 부분이 가장 뿌듯하다.퇴근 후 나태해지거나 슬럼프가 오기도 했는데, 그럼에도 불구하고 모아보니 한게 꽤 돼서 놀랐다.내년엔 좀더 C, 리버싱 등의 로우레벨을 공부할 것이고 파이썬으로 비동기로 짜는것에 좀 더 익숙해질 생각이다.스칼라는 계속 할 것이고 프로덕션의 몇몇 서비스들을 계속 서버리스로 분리해나갈 생각을 하고 있다.실무 기간만 보자면 1년 좀 넘었고 그냥 개발 한 기간은 2년정도 됐는데, 아직까지도 개발은 재밌고 직업 잘 선택한 것 같다는 생각이 든다.내년은 올해보다 더 부지런한 한해가 됐으면 좋겠다.","categories":[{"name":"Logs","slug":"Logs","permalink":"https://sehajyang.github.io/categories/Logs/"}],"tags":[{"name":"weekly","slug":"weekly","permalink":"https://sehajyang.github.io/tags/weekly/"}]},{"title":"11~12월 회고","slug":"191125-191215","date":"2019-12-16T01:11:00.000Z","updated":"2019-12-28T08:36:46.206Z","comments":true,"path":"2019/12/16/191125-191215/","link":"","permalink":"https://sehajyang.github.io/2019/12/16/191125-191215/","excerpt":"","text":"11월 24일부터 12월15일까지의 3주간 회고가 됐다.3주간 많은 변화가 있었는데 그 중 가장 큰 이슈는 C를 다시 시작하게 된 것이다. 3주간 한 학습 및 개발 Amazon CodeGuru 삽질 C 공부 다시시작 우아한 테크 러닝 - DDD 세레나데 교육 객체지향의 사실과 오해 2019 공개SW 컨트리뷰션 페스티벌 저번 회고때 설정한 목표 달성을 얼마나 했나 우아한 테크 러닝 - DDD 세레나데 교육 계속 바빠서 한번 빠졌었지만 계속 하고 있다. 종강은 12월 17일 이다. 객체지향의 사실과 오해 책 읽기 다 읽었다. 객체지향을 처음 배우는 사람이 보면 좋을 책인 것 같다. 자바 ORM 표준 JPA 프로그래밍 이건 읽다가 직접 해보는게 좋을 것 같다고 생각했다. Amazon CodeGuru 적용[Amazon CodeGuru]는 이번 2019 AWS re:invent에서 처음 공개된 AI 코드리뷰 서비스이다. 지금은 자바만 가능하다.AWS 내부에선 이걸 주욱 사용하고 있었던 것 같다. 우리 프로젝트에 한번 붙여보라는 팀장님의 말에 붙이려는 시도를 했지만 실패했다.코드그루를 프로젝트에 붙이는 방법은 총 세가지가 있다. 깃허브에 공개된 프로젝트를 코드그루에 추가해 풀리퀘 후 해당 쓰레드에서 간편하게 리뷰를 받는다 코드가 분석됐다고 콘솔에선 뜨는데 아무런 액션이 발생하지 않았다. EC2에 올라간 프로젝트를 코드그루와 연결해 코드그루 콘솔내에서 리뷰를 받아본다 IAM에 관련 권한 다 추가했음에도 불구하고 EC2에서 해당 프로젝트를 실행하면, 권한 및 인증이 계속 실패했다는 오류가 발생했다. aws code commit, code deploy등과 연동해 코드그루 리뷰를 받는다 권한 설정하고 쓰레기 코드 추가해서 풀리퀘 보내봤으나 코드그루가 라인 분석만 하고 리뷰를 하진 않았다. awskrug의 다른 분들도 코드그루가 분석은 하나 리뷰를 달아주지 않는 문제를 겪고계신 것 같다.아직 해외 블로그에도 적용한 사례가 없고 오직 aws 문서밖에 없는 상황인데 여러가지 방법을 시도해봐도 코드리뷰가 달리진 않아서 일단 코드그루를 붙이는 작업은 보류해야할 것 같다. C 공부 다시시작나는 고등학생때부터 보안에 관심이 있어서 이것저것 했었다(그렇다고 잘하진 못했다) 어쨌든 C를 못하고, 프로그래밍을 못하는 상태로 계속하기엔 한계가 있었다. 학부생 시절엔 전필이라 C강의를 들었지만 지금은 좀 까먹었다. 그래서 C 공부를 다시 하기로 했다.레딧에선 C언어 창시자인 데니스리치가 쓴 The C Programming Language(K&R 라고 부른다)를 바이블로 여기지만 추천은 K.N. King’s C Programming: A Modern Approach을 한다. 평을 보니 K&R은 꼭 한번 읽어봐야 하지만 초심자에겐 추천하지 않는다. 초심자에겐 C Programming: A Modern Approach 와 Head First in C 를 추천하는 것 같다. 나는 프로그래밍을 처음하는게 아니니 Head First보단 K.N. King’s book이 좋을 것 같았다. 그래서 책은 C Programming: A Modern Approach 을 보려고 했으나 우리나라엔 번역서가 없으며 위키독스에 일부 번역된 번역본이 있었다.[링크]결론적으로 K.N. King’s C 책을 봐야하는데 번역본이 없어 원서로 볼 바에는 K&R책이 나을 거 같아서 K&R책을 주문해뒀다.리버싱 책도 추천받았다. The IDA Pro Book 우아한 테크 러닝 - DDD 세레나데 교육DDD 교육은 어느덧 4주차가 됐다. 그리고 며칠뒤엔 종강이다.개인적으로 가장 큰 수확은 코드리뷰와 같은 요구사항에 대해 다른사람들은 어떻게 구현했나 볼 수 있었던거 였다.그리고 다른사람은 TDD를 어떻게 하는지에 대해 궁금한게 많았는데 이번에 많이 해소되어서 좋았다. 2019 공개SW 컨트리뷰션 페스티벌평일에 회사분들과 가게되었다. 레디스 세션의 내용이 굉장히 좋았으며 이 세션 관련해서는 정리해서 포스팅해뒀다.[레디스 운영 잘하는 법] 총평3주간 새로운 공부도 하고, 세미나도 가는둥 여러가지 시도를 많이 한 주였던 것 같다.이제 슬슬 연말이 다가오고 있어 1년간 무엇을 했나 적어보고 있는데 생각보다 한게 많았다.아무쪼록 내년에는 딥하게 좀더 로우레벨을 공부할 생각을 하고있다.","categories":[{"name":"Logs","slug":"Logs","permalink":"https://sehajyang.github.io/categories/Logs/"}],"tags":[{"name":"weekly","slug":"weekly","permalink":"https://sehajyang.github.io/tags/weekly/"}]},{"title":"레디스 운영 잘하는 법","slug":"how-to-operate-redis","date":"2019-12-11T04:36:48.000Z","updated":"2019-12-28T08:36:46.209Z","comments":true,"path":"2019/12/11/how-to-operate-redis/","link":"","permalink":"https://sehajyang.github.io/2019/12/11/how-to-operate-redis/","excerpt":"","text":"이 포스팅은 지난 12.4일에 있었던KOSSCON의 강대명님의 레디스 운영 잘하는 법 을 듣고 발표자료와 발표내용을 종합하여 작성한 포스팅으로 대부분 발표자료에 있는 내용입니다. 글로 보고싶으신 분들 및 세션 내용 정리를 위해 겸사겸사 정리했습니다. Redis 운영잘하는 법 정리발표자료 : PPT링크발표자 : 강대명님 Redis 소개 In Memory data structure store 오픈소스 data structure 지원 Strings, set, hash, list sorted-set(랭킹시스템 할때 좋음) 그러나 데이터 100만건 넘어가면 느려짐(초당 백만건 순회) Hyperlog, bitmap, geospatial index Stream Redis 운영 메모리 관리를 잘하자! 99.999퍼 중요! physical memory 이상을 사용하면 swap 메모리를 사용하게됨 swap 사용하면 메모리 page 접근시마다 읽고 쓰기 때문에 엄청 느려짐 보통 레디스 갑자기 느려졌다 하면 이 이유임 max 메모리를 설정하더라도 이보다 더 사용하게됨(다른 프로세스들도 메모리를 사용하기 때문) RSS 값을 모니터링 해야함 적은 메모리 사용하는 instance 여러개가 안전 redis 는 싱글 쓰레드이기 때문 따라서 여러개의 인스턴스가 좋다 큰 메모리일시 elastic cache 쓰면 상관없음(걔가 알아서 관리해줌) 메모리 파편화 실제로 메모리 파편화가 많이 발생함 jemlloc 버전에 따라서 다르게 파편화가 발생 jemlloc 4.x 대 부터 메모리 파편화 줄이기 위한 jemalloc에 힌트를 주는 기능이 들어감 jemlloc 3.x 버전은 used memory 2GB라고 나오지만 실제론 11GB RSS를 사용하는 경우가 자주 발생함 다양한 사이즈를 가지는 데이터보단 유사크기의 데이터를 가지는 경우가 유리함 메모리 부족시? 장비 마이그레이션 메모리 빡빡하면 마이그레이션중 문제생길수도 있다 넉넉하게 하자 있는 데이터 줄이기 특정 데이터를 줄일때 이미 swap 사용중이라면 프로세스 재시작 해야됨 메모리를 줄이기위한 설정 Collection Hash -> HashTable 하나 더 사용 Sorted Set -> Skiplist와 HashTable 이용 Set -> HashTable 사용 위의 자료구조들은 메모리 많이 사용함 Ziplist 이용 인메모리 특성상 적은 개수(100만개 이하)라면 선형탐색이 정말 빠름 게다가 ziplist는 기존 자료구조보다 메모리를 적게 먹음! 그러니 List, hash, sorted set 등을 ziplist로 대체하자 hash-max-ziplist-entries, hash-max-ziplist-value list-max-ziplist-size, list-max-ziplist-value zset-max-ziplist-entries, zset-max-ziplist-value 만약 설정갯수 오버하면 원래 설정 구조로 바뀌게됨(n개 이상이면 원래 hash로 돌아감.. 이런식) O(n) 관련 명령어 조심하자! 레디스는 싱글 쓰레드 레디스는 동시에 여러개의 명령을 처리할 수 없음 그러니 오래걸리는 일 시키면 안됨 단순한 get/set의 경우 초당 10만 TPS 이상 가능 오래걸리는 대표적인 O(N) 명령들 KEYS FLUSHALL, FLUSHDB Delete Collections Get All Collections 대표적인 실수 사례 Key가 백만개 이상인데 Key 명령을 사용하는 경우 아이템이 몇만개 든 hash, sorted set, set에서 모든 데이터를 가져오는 경우 spring security oauth redis tokenStore 문제 대안 KEYS -> Scan scan 명령으로 하나의 긴 명령을 짧은 여러번의 명령으로 바꿈 Collection의 모든 아이템을 가져와야 할때 Collection 일부만 가져오거나 큰 Collection을 작은 여러개의 Collection으로 나눠서 저장 Userranks -> Userrank1, Userrank2, Userrank3 개당 몇천개 안쪽으로 저장하는게 좋음 Spring security oauth RedisTokenStore 이슈 스프링 시큐리티 레디스 토큰조회를 O(N) 으로 하고있었음 100만개 넘어가면 검색/삭제 한번 하는데에 1초씩 걸렸음 O(N) -> O(1) 로 고쳐짐, 따라서 지금은 괜찮음 Redis Replication Async Replication Replication Lag 이 발생할 수 있다. “Replicaof’(>= 5.0.0) or ‘slaveof’ 명령으로 설정 가능 Replicaof hostname port DBMS로 보면 statement replication가 유사 Replication 설정 과정 Secondary에 replicaof or slaveof 명령을 전달 Secondary는 Primary에 sync 명령 전달 Primary는 현재 메모리 상태를 저장하기 위해 Fork Fork 한 프로세서는 현재 메모리 정보를 disk에 dump 해당 정보를 secondary 에 전달 Fork 이후의 데이터를 secondary에 계속 전달 Redis Replication 시 주의할 점 Replication 과정에서 fork 가 발생하므로 메모리 부족 발생할 수 있다. Redis-cli –rdb 명령은 현재 상태의 메모리 스냅샷을 가져오므로 같은 문제를 발생시킴 AWS나 클라우드의 Redis는 좀 다르게 구현되어서 좀더 해당 부분이 안정적 많은 대수의 Redis 서버가 Replica를 두고 있다면 네트웍 이슈나, 사람의 작업으로 동시에 replication이 재시도 되도록 하면 문제가 발생할 수 있음. ex) 같은 네트웍안에서 30GB를 쓰는 Redis Master 100대 정도가 리플리케이션을 동시에 재시작하면 어떤 일이 벌어질 수 있을까? 권장 설정 redis.conf 권장 설정 Tip Maxclient 설정 50000 RDB/AOF 설정 off 특정 commands disable Keys AWS의 ElasticCache는 이미 하고 있음. 전체 장애의 90% 이상이 KEYS와 SAVE 설정을 사용해서발생. 적절한 ziplist 설정 Redis Cluster Hash 기반으로 Slot 16384 로 구분 Hash 알고리즘은 CRC16을 사용 Slot = crc16(key) % 16384 Key가 Key{hashkey} 패턴이면 실제 crc16에 hashkey가 사용된다. 특정 Redis 서버는 이 slot range를 가지고 있고, 데이터 migration은 이 slot 단위의 데이터를 다른 서버로 전달하게 된다.(migrateCommand 이용) Redis Cluster의 장점/단점 장점 자체적인 Primary, Secondary Failover. Slot 단위의 데이터 관리. 단점 메모리 사용량이 더 많음 Migration 자체는 관리자가 시점을 결정해야 함. Library 구현이 필요함. Redis Failover Coordinator 기반 Failover Zookeeper, etcd, consul 등의 Coordinator 사용 장점 Coordinator 기반으로 설정을 관리한다면 동일한 방식으로 관리가 가능. 단점 해당 기능 이용을 위한 개발(라이브러리)이 필요함 VIP/DNS 기반 Failover VIP DNS 아마존은 이 방식을 사용하고 있음 장점 클라이언트에 추가적인 구현이 필요없다. VIP 기반은 외부로 서비스를 제공해야 하는 서비스 업자에 유리(예를 들어 클라우드 업체) 단점 DNS 기반은 DNS Cache TTL을 관리해야 함. 사용하는 언어별 DNS 캐싱 정책을 잘 알아야 함 툴에 따라서 한번 가져온 DNS 정보를 다시 호출 하지 않는 경우도 존재 Redis Cluster 의 사용 모니터링 Monitoring Factor Redis Info를 통한 정보 RSS Used Memory Connection 수 초당 처리 요청 수 System CPU Disk Network rx/tx CPU가 100% 칠 경우 처리량이 매우 많다면 좀 더 CPU 성능이 좋은 서버로 이전 실제 CPU 성능에 영향을 받음 그러나 단순 get/set은 초당 10만 이상 처리가능 O(N) 계열의 특정 명령이 많은 경우. Monitor 명령을 통해 특정 패턴을 파악하는 것이 필요 Monitor 잘못쓰면 부하로 해당 서버에 더 큰 문제를 일으킬 수도 있음.(짧게 쓰는게 좋음) 결론 기본적으로 Redis는 매우 좋은 툴 그러나 메모리를 빡빡하게 쓸 경우, 관리하기가 어려움 32기가 장비라면 24기가 이상 사용하면 장비 증설을 고려하는 것이 좋음. Write가 Heavy 할 때는 migration도 매우 주의해야함. Client-output-buffer-limit 설정이 필요. 레디스를 캐시로 쓴다면 Cache 일 경우는 문제가 적게 발생 Redis 가 문제가 있을 때 DB등의 부하가 어느정도 증가하는 지 확인 필요. Consistent Hashing도 실제 부하를 아주 균등하게 나누지는 않음. Adaptive Consistent Hashing 을 이용해 볼 수도 있음. 레디스를 Persistent Store로 쓴다면 무조건 Primary/Secondary 구조로 구성이 필요함 메모리를 절대로 빡빡하게 사용하면 안됨. 정기적인 migration이 필요. 가능하면 자동화 툴 을 만들어서 이용 RDB/AOF가 필요하다면 Secondary에서만 구동","categories":[{"name":"Seminar","slug":"Seminar","permalink":"https://sehajyang.github.io/categories/Seminar/"}],"tags":[{"name":"Redis","slug":"Redis","permalink":"https://sehajyang.github.io/tags/Redis/"}]},{"title":"10~11월 중순 월간회고","slug":"191028-191124","date":"2019-11-26T10:00:00.000Z","updated":"2019-12-28T08:36:46.205Z","comments":true,"path":"2019/11/26/191028-191124/","link":"","permalink":"https://sehajyang.github.io/2019/11/26/191028-191124/","excerpt":"","text":"10월 중순(28일) 부터 11월 중순(24일)까지 한 월간 회고가 되었다.월간회고가 되니 한달동안 무엇을 했는지가 기억이 나지 않는다. 역시 월간회고보단 2주 회고가 좋은 것 같다. 한달간 한 학습 및 개발 스포카 크리에이터 컨퍼런스 참석 lambda + sqs 사내 스터디 발표 우아한 테크 러닝 - DDD 세레나데 교육 객체지향의 사실과 오해 자바 ORM 표준 JPA 프로그래밍 저번 회고때 설정한 목표 달성을 얼마나 했나지난 회고의 목표와 달성은 다음과 같다: 백준-SW 역량테스트준비 수강 SW 역량테스트준비는 차일피일 미루다 다 듣지 못해서 아쉬웠다. 알고리즘 문제 풀이 알고리즘 문제풀이는 중단했었다. Programming in Scala 공부(시간이 된다면) 스칼라 공부를 하기보단 지금 할 줄 아는 언어에 집중해야겠다고 생각했다. 스포카 크리에이터 컨퍼런스 참석 스포카 컨퍼런스에 다녀왔다. 스포카 크리에이터 컨퍼런스 참석여러가지 세션이 있었지만 나는 예약 문자 발송 최적화를 들으러 참석했다.나 역시 예약 문자 발송 최적화를 하기위해 고민을 했었기 때문이다(그리고 다른회사에선 어떻게 했는지 궁금했다)스포카는 rabbitMQ를 이용해 구현했더라. 나는 예약 문자 발송에 가장 맞는 방법은 MQ + asyncio 라고 생각한다.특히 많은 요청이 발생한다면 더더욱 MQ를 사용해야한다고 생각한다.람다와 SQS로 하기엔 람다 타임아웃 및 SQS에서 호출할수있는 람다수 제한 등의 문제등이 있다.내가 SQS로 구축할 당시에만 해도 FIFO큐에선 람다 트리거를 사용할 수 없었다.단 한번만 보내야하는(중복으로 보내면 안되는) 문자 메세지 특성상 기본 큐 보단 FIFO큐가 좋았지만 람다 트리거를 사용할 수 없어서 기본 큐를 사용했었다.그러나 11월 20일부터 FIFO큐에서 람다 트리거를 사용할 수 있게 됐다!어쨌든 기회를 봐서 MQ로 고칠 생각을 하고있다. lambda + sqs 사내 스터디 발표매주 목요일마다 진행하는 사내 개발 스터디에서 lambda + sqs 이용해 예약문자 서비스를 구축&운영한 내용으로 스터디를 진행했다.슬라이드가 80장정도 나왔는데 그럼에도 불구하고 겉핥기식으로 끝난 것 같아 아쉬웠다.다음주엔 다른 개발자분이 Concurrency in Golang 발표를 한다. 그 유명한(?) 고루틴에 대해 알아볼 기회가 생겼다.go는 어떻게 동시성을 처리할지 궁금하다. 우아한 테크 러닝 - DDD 세레나데 교육나는 그간 프로덕션의 코드를 개선하고싶었지만 옳은 방향을 몰라 나름대로 이것저것 해보며 헤매고 있었다.그러던 차에 우아한형제들에서 DDD 교육을 한다는걸 알게되어 신청했는데 운좋게 우아한 테크러닝 DDD 교육에 선발되었다.과정은 총 5주간 매주 화요일에 진행된다. 수강생은 30여명정도고 경쟁률이 쌨다고 들었다. 운이 좋았다.이 과정의 목표는 치킨집 포스 시스템의 레거시 리팩토링이며 매주마다 과제가 나간다.세미나처럼 듣는방식으로 교육이 진행될 줄 알았는데, 과제가 나온다 해서 조금 당황했다.게다가 코드 작성시 주의사항은 9가지 정도 됐는데 꽤 빡빡하고 어려웠다.나름대로 지키려고 노력하니 아직 1주차밖에 안했지만 벌써 코딩 스타일이 달라진게 느껴졌다.과제에 대한 다른사람의 코드를 볼 수도 있다. 같은 기능을 다른 사람은 어떻게 작성했는지 보다보면 재밌고 시간이 금방 가더라.게다가 코드리뷰를 받을 수 있어 좋다. 확실히 코드리뷰를 받으면 실력이 금방 올라가는 것 같다. 이래저래 소중한 경험을 하고있다.아직 내가 제일 못하는 것 같고 배울게 많고 빡세지만 이번 기회에 많이 배워서 꼭 레거시 개선을 하고싶고 좋은 코딩 습관이 들었음 좋겠다.그나저나 나는 내가 나름대로 테스트코드를 잘 짠다고 생각했지만 전혀 아니었다 배울게 많더라.. 객체지향의 사실과 오해이 책은 DDD 교육에서 추천한 도서이다. 이 책은 객체지향이 뭐지? 라고 생각하는 사람이 보면 좋은 도서인 것 같다.아직 초반을 읽고있긴 하지만 두께도 얇고 부담없이 볼 수 있는 내용인 것 같다. 자바 ORM 표준 JPA 프로그래밍이 책도 DDD 교육에서 추천한 도서이고 JPA관련 도서중 가장 유명한 도서이다. 알고는 있었지만 보는건 처음이다. 아직 초장을 읽고있다. 다음주 목표 우아한 테크 러닝 - DDD 세레나데 교육 계속 객체지향의 사실과 오해 책 읽기 자바 ORM 표준 JPA 프로그래밍 총평초반엔 좀 나태한 한달이었지만 DDD 교육을 듣게되며 다시 빡세졌다. 특히 회사랑 병행하긴 쉽지않더라..교육 난이도는 내가 하기엔 좀 높았다. 그러나 내가 그간 안티패턴의 개발(?) 을 했는지 아닌지, best practice 는 어떤건지 알수있어서 좋았다.","categories":[{"name":"Logs","slug":"Logs","permalink":"https://sehajyang.github.io/categories/Logs/"}],"tags":[{"name":"weekly","slug":"weekly","permalink":"https://sehajyang.github.io/tags/weekly/"}]},{"title":"springboot 2.2 버전으로 업그레이드 하는 방법","slug":"springboot-migration-1.5to2.0","date":"2019-11-11T15:00:00.000Z","updated":"2019-12-28T08:36:46.210Z","comments":true,"path":"2019/11/12/springboot-migration-1.5to2.0/","link":"","permalink":"https://sehajyang.github.io/2019/11/12/springboot-migration-1.5to2.0/","excerpt":"","text":"안녕하세요, 이 포스팅은 버전 1.5.9 부터 2.2.1(19.11.12 기준 최신 릴리즈)까지의 버전 마이그레이션하는 과정에 대한 내용으로 구성되어있습니다.[공식 가이드]대로 했지만 업그레이드 과정에서 많은 문제를 겪었기 때문에 추후에 삽질을 줄이고자 이 포스팅을 작성하게 되었습니다 😊 그리고 한번에 버전을 1.5 -> 2.2로 올려버리면 오류를 잡았음에도 불구하고 자꾸 알수 없는 오류가 발생하며 빌드가 되지 않았습니다.혹 이유를 아시는 분은 코멘트 남겨주세요🙇따라서 1.5 -> 2.0 -> 2.2 순서로 버전을 업그레이드 하도록 하겠습니다. 필수 조건 JDK 8 이상 tomcat 8.5 이상(외부 톰캣 사용하는 경우) gradle 4.10 이상 메이져 버전 마이그레이션 시 지원이 중단된 몇가지 서드파티 라이브러리들의 버전을 업그레이드 혹은 대체를 해야할 수도 있습니다.[springboot 2.2 릴리즈 노트] 에서 변경점을 더 확인할 수 있습니다. 순서1. gradle 버전이 5.0 이 아닐경우 5.0-all 로 변경스프링 2.2로의 마이그레이션을 위해선 그래들 버전이 4.10이상이어야 합니다.프레임워크 버전업과 더불어 저는 gradle 버전을 4.10보단 5로 맞췄습니다.gradle > wrapper > gradle-wrapper.properties 에서 아래와 같이 gradle 버전을 수정합니다. 1distributionUrl=https\\://services.gradle.org/distributions/gradle-5.0-all.zip gradle의 버전을 업그레이드하면 지원이 중단된 플러그인등이 발생할 수 있습니다. deprecated 된 플러그인들을 적절히 대체 및 업그레이드 합니다.(자바 코드상의 변경이 필요할 수도 있습니다) 2. build.gradle에 dependency-management를 추가마이그레이션을 위한 의존성 관리 플러그인을 추가합니다. 12apply plugin: 'io.spring.dependency-management'runtime(\"org.springframework.boot:spring-boot-properties-migrator\") 3. springboot 버전 바꾸기build.gradle의 springboot 버전을 변경합니다. 1springBootVersion = '2.2.0.RELEASE' 4. 라이브러리 교체와 클래스 변경컴파일 오류가 난다면 해당되는 오류를 고칩니다.보통은 사용하던 서드파티 라이브러리가 deprecated 되어 대체 후 오류가 나는 경우가 많습니다.(ex:log4j 지원중단으로 log4j2로 고쳤습니다. 따라서 프로젝트에 사용중이던 logger -> log 로 변경되었습니다)버전 업그레이드로 인한 특정 라이브러리 설정의 변화로 발생하는 오류를 해결하는 방법은 다음의 링크에서 확인하실 수 있습니다. common-application-properties 공식문서 링크 2.1 버전 부턴 mysql 드라이버 명이 변경되었습니다.기존 : com.mysql.jdbc.Driver바뀐것 : com.mysql.cj.jdbc.Driver 또한 몇가지 클래스및 패키지가 변경되었습니다.예를들어: WebMvcConfigurerAdapter deprecated로 인한 변경기존 : extends WebMvcConfigurerAdapter변경 : implements WebMvcConfigurer SpringBootServletInitializer 패키지 이름의 변경기존 : import org.springframework.boot.web.support.SpringBootServletInitializer;변경 : import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; 위와 같은 클래스 및 패키지가 변경되었습니다.이러한 변경은 IDE에서 잡아주거나 컴파일시 warn 알림으로 deprecated 되었다는 알림을 주기 때문에그에 맞춰 수정하거나, 2.0 릴리즈 노트에서 확인할 수 있습니다. [Spring Boot 2.0 Release Notes] 5. application.properties 수정IDE에서 해당 키워드에 warning 표시를 나타내며 제안에 따라 수정할 수 있습니다.또는 [지원하는 의존성 버전] 문서를 보며 application.properties에서 기존의 키워드를 변경된 키워드로 수정합니다. 6. bean overriding해당 변경은 2.1의 릴리즈 노트에서 다음과같이 소개하고 있습니다.[링크] Bean overriding has been disabled by default to prevent a bean being accidentally overridden. If you are relying on overriding, you will need to set spring.main.allow-bean-definition-overriding to true. 2.1 버전부터 빈의 우연한 재정의를 방지하기위해 default가 false 라고 합니다. 따라서, been overriding을 사용하려면 true로 명시해줘야 합니다.명시가 되어있지 않은 경우 다음과 같은 오류가 발생합니다. 1org.springframework.beans.factory.support.Bean Definition Override Exception 따라서 application.properties에 bean overriding을 허용하는 부분을 추가합니다. 1spring.main.allow-bean-definition-overriding=true 7. ‘KST’ is unrecognized or represents more than one time zone12The server time zone value ‘KST’ is unrecognized or represents more than one time zone : mysql-connector-java 위의 오류는 아래와 같이 db name 뒤에 ?characterEncoding=UTF-8&serverTimezone=Asia/Seoul 를 추가합니다 1jdbc:mysql://ip:port/dbname?characterEncoding=UTF-8&serverTimezone=Asia/Seoul 8. 버전 업그레이드 2.0 -> 2.2빌드 및 run이 성공적으로 되면 build.gradle에서 2.2.1.RELEASE 로 springboot 버전을 변경합니다. 1springBootVersion = '2.2.1.RELEASE' 그 후 4~5번의 작업을 반복하며 오류를 잡습니다.2.0 -> 2.2 로 버전이 올라가며 변경된 점은 springboot 릴리즈 노트에서 확인하며 수정합니다. Spring Boot 2.1 Release Notes Spring Boot 2.2 Release Notes 9. properties-migrator 제거빌드 및 run이 성공적으로 되면 build.gradle 에서 추가해뒀던 아래 코드를 제거 합니다. 1runtime(\"org.springframework.boot:spring-boot-properties-migrator\") 10. mybatis.configuration.result-maps[0] 오류혹 2.2.0 버전으로의 업그레이드를 한다면 다음과 같은 오류를 만날수도 있습니다. 1Caused by: org.springframework.boot.context.properties.bind.BindException: Failed to bind properties under 'mybatis.configuration.result-maps[0]' to org.apache.ibatis.mapping.ResultMap 다음과 같은 오류는 2.2.0.RELEASE (2.2.0.M5 +) 버전에서 발생하고 있는 이슈며 2.2.0.M4와 2.2.1.RELEASE 에선 해결되었습니다.해당 이슈는 스프링부트 깃허브 이슈 [Binding fails in presence of a synthetic constructor #18670] 에서 확인할 수 있습니다. 추가) 만약 swagger를 쓰는데 마이그레이션 시 오류 날 경우 2.9.1로 올려주셔야 됩니다.Lombok, Gradle, JPA 문제등은 [honeymon 님의 스프링 부트 2.x 준비하는 개발자를 위한 안내서] 포스팅에서 자세히 알아보실 수 있습니다. 이 포스팅은 헤렌 기술블로그에서도 보실 수 있습니다.혹 내용이 잘못되었거나 보충해야 될 부분이 있다면 코멘트 남겨주세요 🙏읽어주셔서 감사합니다 :) 참고자료 [Spring Boot 2.2 Release Notes] spring-boot-migration-java Spring-Boot-2.0-Migration-Guide [honeymon 님의 스프링 부트 2.x 준비하는 개발자를 위한 안내서]","categories":[{"name":"Spring","slug":"Spring","permalink":"https://sehajyang.github.io/categories/Spring/"}],"tags":[{"name":"Springboot","slug":"Springboot","permalink":"https://sehajyang.github.io/tags/Springboot/"},{"name":"migration","slug":"migration","permalink":"https://sehajyang.github.io/tags/migration/"}]},{"title":"191007-191028 3주간 회고","slug":"191007-191027","date":"2019-10-28T09:07:00.000Z","updated":"2019-11-16T08:45:45.542Z","comments":true,"path":"2019/10/28/191007-191027/","link":"","permalink":"https://sehajyang.github.io/2019/10/28/191007-191027/","excerpt":"","text":"회고를 안쓴지 2주가 되었다고 생각했는데 3주가 되었다. 어쩐지 오랫동안 안 쓴 느낌이었다.3주 동안 뭘 했나 생각해봤는데 알고리즘을 문제 풀이를 많이 했던 것 같다. 3주간 했던 학습 및 개발 프로덕션에 도입한 서버리스 문제 해결 스칼라 번역 포스팅 1개 알고리즘 문제 풀이 프로덕션에 도입한 서버리스 문제 해결지난 회고때에 언급했던 [기존 레거시를 서버리스로 교체]하면서 발생했던 오류를 해결했다.SQS에 DLQ설정을 해둔 상태였는데 해당 큐의 트리거로 설정해둔 Lambda에서도 DLQ 설정을 했기 때문에 문제가 발생했다.처음엔 문제를 해결하기 위해 람다쪽 DLQ를 해제했는데, 해제했음에도 불구하고 DLQ에 붙여둔 람다 트리거 함수가 실행됐다.그때 SQS에 설정해둔 배달 못한 편지 대기열(DLQ) 생각이 났고, SQS측에 설정해둔 DLQ도 해제하자 더이상 알 수 없는 작업실패는 발생하지 않았다.그 이후 lambda에 sentry를 붙여 실패한 작업은 알림을 받으며, 실패한 작업은 배치를 돌려 주기적으로 처리하도록 구성했다.그렇게 구성한 뒤론 아무 오류 없이 잘 동작하고 있는 상태이다.이건 주간회고로 정리하기엔 양이 많은 것 같아 따로 포스팅으로 정리할 생각을 하고있다.서버리스로 개편한 이유는 크게 비용, 처리속도 때문이었는데 한달간 비용이 SQS+Lambda로 만원정도 나온것을 확인했다.EC2 올리는 것보다 훨씬 저렴해서 속도는 물론이고 비용까지 두마리 토끼를 잡을 수 있었다.추후 사용자가 늘어날 것에 대비해 기존 레거시를 고치고 처음부터 설계해보면서 많은 삽질과 에러를 경험하게 되었지만성공적으로 끝나서 굉장히 안심뿌듯했다.SQS에 대한 자료는 구글링해도 별로 없었기 때문에 awskrug 슬랙방에 묻기도 했는데, 많은 고수님들이 있으니 혹 나처럼 도움을 청할 곳이 없는 사람은 awskrug 슬랙방에 질문해 보는것도 좋을 것 같다 :) 스칼라 번역 포스팅 1개[스칼라 번역 - Class vs Case Classes]7월부터 시작한 [스칼라 튜토리얼 번역시리즈] 포스팅은 어느덧 8개가 되었고, 이제 3개만 하면 끝이난다.만약 Functional Programming Principles in Scala를 보실분이 있다면 수강하며 이 번역본을 참고하시면 좋을 것 같다. 알고리즘 문제풀이며칠전부터 백준-SW 역량테스트준비 수강을 시작했다. 강사는 백준을 만드신 최백준님이다.한달만 들을수 있어 아쉽지만 강의 내용이 좋아서 열심히 수강하고있다.그밖에 3주간 DFS, BFS문제를 풀거나 트리, 힙, 탐색과 관련된 이것저것 문제를 풀었다.특히 DFS문제인 [단지번호붙이기] 문제는 DFS 개념 학습뒤 바로 풀기좋은 문제라 조만간 정리해서 포스팅을 올릴생각을 하고있다.예전엔 알고리즘 및 자료구조 개념을 익힐땐 개념학습 후 코드를 본 다음 구현해봤기 때문에 금방 잊기 일쑤였고 내 지식이 되지 않았었다.그러다 최근에 개념만 학습한 뒤 직접 구현해보는 작업을 했는데, 이렇게 학습하니 응용해서 문제를 풀 수도 있었고 확실하게 내 지식이 되어서 좋았다. 2주간 목표 백준-SW 역량테스트준비 수강 알고리즘 문제 풀이 Programming in Scala 공부(시간이 된다면) 스포카 크리에이터 컨퍼런스 참석 스포카 컨퍼런스에서 문자 메시지 전송 최적화하기 를 듣기위해 신청했다.나는 이 기능을 SQS+Lambda로 구축했는데, 스포카는 어떻게 했을지 굉장히 궁금하다. 총평Programming in Scala 공부를 안했는데, 지금 중요한게 이게 아니라는 생각이 들었다.좋아하는 학습보다 지금 나한테 필요한 학습을 하는게 더 좋을 것 같단 판단때문이었다.몇달 아니 몇주 전 까지만 해도 알고리즘은 어렵고 힘든것이었다. 그러나 몇주동안 알고리즘을 풀며 조금은 재밌어진 것 같기도 하다.여전히 어렵고 못하지만 내 힘으로 어찌저찌 풀게 되었다는게 감개무량했다. 어떻게든 돌아가게 짠 뒤 리팩토링 하는 작업도 좋다.저번달엔 슬럼프때문에 쳐저있었는데 이번달엔 조금씩 문제를 풀며 기운을 얻었던 것 같다.무엇보다 과거의 내가 못풀었던 문제를 지금은 풀 수 있었는데 그러한 경험이 슬럼프에서 벗어나는데에 도움이 된 것 같다.","categories":[{"name":"Logs","slug":"Logs","permalink":"https://sehajyang.github.io/categories/Logs/"}],"tags":[{"name":"weekly","slug":"weekly","permalink":"https://sehajyang.github.io/tags/weekly/"}]},{"title":"스칼라 번역 - Class vs Case Classes","slug":"class-vs-case-class","date":"2019-10-11T03:00:00.000Z","updated":"2021-06-20T04:25:47.787Z","comments":true,"path":"2019/10/11/class-vs-case-class/","link":"","permalink":"https://sehajyang.github.io/2019/10/11/class-vs-case-class/","excerpt":"","text":"이 포스팅은 [scala-exercises 번역 시리즈]로 scala-exercises 사이트의 스칼라 튜토리얼을 공부하며 번역한 문서 입니다.scala-exercises 는 스칼라 창시자인 마틴 오더스키 강의의 강의자료입니다.따라서 강의를 들으며 본 문서를 같이 보는것을 추천합니다.의역이 많습니다. 오역 및 오타 등은 코멘트로 알려주세요 😄원문 : [scala tutorial classes vs case classes] CLASSES VS CASE CLASSES앞 포스팅에선 케이스 클래스를 사용해 어떻게 정보집계, 데이터 추상화, 상태객체(stateful object)를 정의하는지 알아봤습니다.이제 class와 case class 사이엔 어떤 차이점이 있는지 알아봅시다. 생성 및 조작다음은 BankAccount 클래스 입니다. 1234567891011121314class BankAccount { private var balance = 0 def deposit(amount: Int): Unit = { if (amount > 0) balance = balance + amount } def withdraw(amount: Int): Int = if (0 < amount && amount <= balance) { balance = balance - amount balance } else throw new Error(\"insufficient funds\")} 그리고 Note의 케이스 클래스는 다음과 같습니다. 1case class Note(name: String, duration: String, octave: Int) 다음과 같이 BankAccount와 Note의 몇가지 인스턴스를 생성하고 조작 합니다. 1234val aliceAccount = new BankAccountval c3 = Note(\"C\", \"Quarter\", 3)c3.name shouldBe \"C\" 보통 클래스 인스턴스를 생성하려면 new키워드가 필요합니다. 하지만 case class는 new키워드가 필요하지 않습니다.또한, case classs 생성자 파라미터는 멤버로 취급되는 반면 일반 클래스는 그렇지 않습니다. EQUALITY123456789val aliceAccount = new BankAccountval bobAccount = new BankAccountaliceAccount == bobAccount shouldBe falseval c3 = Note(\"C\", \"Quarter\", 3)val cThree = Note(\"C\", \"Quarter\", 3)c3 == cThree shouldBe true 위의 예제에서 BankAccount 는 다른 값을 도출하는 반면 Note 는 동일한 값을 나타냅니다.이전 섹션에서 봤듯이, 상태가있는 클래스는 케이스 클래스에는 존재하지 않는 identity 라는 개념을 보여줍니다.실제로 BankAccount 값은 시간이 지남에 따라 변할 수 있지만 Note의 값은 불변입니다.기본적으로 스칼라에서 두개의 객체를 비교한다는것은 identity 를 비교한다는 것입니다.하지만 케이스 클래스의 경우엔 값을 비교하기 위해 동일성(equality)이 재정의 됩니다. Pattern Matching다음의 예제는 패턴매칭을 사용해 케이스클래스 인스턴스로부터 정보를 추출합니다. 123c3 match { case Note(name, duration, octave) => s\"The duration of c3 is $duration\"} 기본적으로 패턴매칭은 일반적인 클래스에선 동작하지 않습니다. 확장가능성(Extensibility)클래스는 다른 클래스를 확장할 수 있지만, 케이스 클래스는 다른 클래스를 확장할 수 없습니다(동일성(equality)을 올바르게 구현할 수 없기 때문에) Case Class Encoding케이스 클래스는 클래스의 특수한 경우이며 여러값을 하나의 값으로 모으는 것이 목적입니다.스칼라는 이러한 일반적인 기능을 명시적으로 지원합니다.케이스 클래스를 정의할때 스칼라 컴파일러는 더 많은 메소드와 동반 객체로 향상된 클래스(case class)를 정의합니다.예를들어, 다음과 같은 케이스 클래스 정의는 다음과 같습니다. 1case class Note(name: String, duration: String, octave: Int) 다음과 같은 클래스 정의로 확장됩니다. 1234567891011121314151617181920212223242526272829303132333435363738394041424344class Note(_name: String, _duration: String, _octave: Int) extends Serializable { // Constructor parameters are promoted to members val name = _name val duration = _duration val octave = _octave // Equality redefinition override def equals(other: Any): Boolean = other match { case that: Note => (that canEqual this) && name == that.name && duration == that.duration && octave == that.octave case _ => false } def canEqual(other: Any): Boolean = other.isInstanceOf[Note] // Java hashCode redefinition according to equality override def hashCode(): Int = { val state = Seq(name, duration, octave) state.map(_.hashCode()).foldLeft(0)((a, b) => 31 * a + b) } // toString redefinition to return the value of an instance instead of its memory addres override def toString = s\"Note($name,$duration,$octave)\" // Create a copy of a case class, with potentially modified field values def copy(name: String = name, duration: String = duration, octave: Int = octave): Note = new Note(name, duration, octave)}object Note { // Constructor that allows the omission of the `new` keyword def apply(name: String, duration: String, octave: Int): Note = new Note(name, duration, octave) // Extractor for pattern matching def unapply(note: Note): Option[(String, String, Int)] = if (note eq null) None else Some((note.name, note.duration, note.octave)) 12345678val c3 = Note(\"C\", \"Quarter\", 3)c3.toString shouldBe \"Note(C,Quarter,3)\"val d = Note(\"D\", \"Quarter\", 3)c3.equals(d) shouldBe falseval c4 = c3.copy(octave = 4)c4.toString shouldBe \"Note(C,Quarter,4)\" 읽어주셔서 감사합니다. 혹 글에 오역/추가할 내용이 있다면 코멘트 남겨주세요.","categories":[{"name":"Scala","slug":"Scala","permalink":"https://sehajyang.github.io/categories/Scala/"}],"tags":[{"name":"Scala","slug":"Scala","permalink":"https://sehajyang.github.io/tags/Scala/"},{"name":"scala-exercises","slug":"scala-exercises","permalink":"https://sehajyang.github.io/tags/scala-exercises/"}]},{"title":"190903-191010 월간 회고","slug":"190903-191006","date":"2019-10-10T01:29:00.000Z","updated":"2019-11-16T08:45:45.540Z","comments":true,"path":"2019/10/10/190903-191006/","link":"","permalink":"https://sehajyang.github.io/2019/10/10/190903-191006/","excerpt":"","text":"미루다보니 월간회고가 되었다. 9월달에 무엇을 했나 생각해보면 떠오르는 것은 다음과 같다. 기존 레거시를 서버리스로 교체로 인한 삽질과 에러의 향연 Lambda SQS 1부 포스팅 우아한 테크 세미나 - 우아한 스프링배치 참가 스타트업 뽀시래기콘 참가 기존 레거시를 서버리스로 교체이번달의 가장 빅 이슈였다. 기존의 메세지 발송 서비스에 추가 기능 개발 요구가 들어오면서 추후에 늘어날 유저수를 고려할 겸 기존 레거시를 뜯어고쳐야겠다고 생각했다.기존 레거시를 개편할 방법으론 1.서버리스로 만들기 2.MQ를 붙이기 등이 있었는데, 서버리스를 선택했다.서버리스를 선택한 이유 중 가장 큰 이유는 비용이었다.과거에 서버리스로 챗봇만들기 정도의 경험만 해봤던 서버리스 왕초보였던 나는 서버리스로 메세지 발송 서비스를 개편하면서 예상대로 많은 삽질과 오류들을 만나게됐다.그러나 해당 오류를 찾아봐도 아직 관련 자료가 많지 않아서 삽질을 많이 했다. 삽질은 크게 구축 삽질과 구축후 운영 삽질로 나뉘었다.구축삽질엔 VPC 셋팅과 VPC를 설정함에 따라 외부 인터넷으로 요청을 보낼 수 없어서 API Gateway를 사용한 것 등이 있었다.구축 후 QA 다 통과하고 프로덕션에 붙인 후 부터 오류가 나기 시작해서 진땀을 뺐다. 가장 큰 문제는 람다 실행시간이었다. 설정해둔 시간제한을 오버하면서 해당 이벤트가 실패하는 일이 많이 발생했다. 급한대로 시간제한을 늘렸는데, 이쯤되면 비용적인 이점은 사라졌다고 보면된다.DLQ를 잘못 셋팅한 문제도 있었다. 그 와중에 에러 로깅도 안되고 정말 혼란이었다.이러한 삽질을 겪으며 한국어로 된 get started 격의 포스팅이 있으면 좋겠다 싶어서 고민끝에 포스팅을 작성을 시작했다. [Lambda SQS 포스팅] 우선 1부를 작성했는데, 회사소스를 캡쳐할 순 없으니 예제를 처음부터 만들어가며 해야되기 때문에 굉장히 시간이 많이 걸린다는 것을 깨달았다. 다음달 안에는 완성하고 싶다.여튼 프로덕션에서 급한불은 껐는데 앞으로도 계속해서 오류가 난다면 서버리스 걷어내고 rabbitMQ를 두는 방식으로 바꿀 생각도 하고있다. 우아한 테크 세미나이동욱님이 발표하시는 우아한 스프링 배치 세미나에 당첨이 되어 9월 26일에 다녀왔다.원래 이번에 서버리스로 바꾼 메세지 발송 서비스를 초기엔 스프링 배치로 돌릴까 하는 생각을 했었다. 실제로 기존엔 배치로 돌아가고 있었다.어쨌든 우리 프로덕션에서 스프링 배치를 안티패턴으로 사용하고 있는건 아닌지, best prectice는 어떨지 궁금해서 신청했었다.내용은 굉장히 좋았고 후기를 따로 포스팅 하려고 했는데, 이미 다른 분들이 좋은 후기 포스팅을 하셨다. 굳이 바퀴를 재발명할 필요는 없을 것 같아서 후기 포스팅은 패스했다.[우아한 배치 영상][이동욱님의 Spring Batch의 멱등성 유지하기][태태태님의 우아한 스프링 배치 테크세미나 정리 및 후기] 스타트업 뽀시래기 콘 참가스타트업 뽀시래기 콘에 참가했다. 주말임에도 불구하고 많은분들이 오셨던 것 같다. 도움이 되는 내용이 굉장히 많았다. 다음주 목표 CS(computer science) 공부 Programming in Scala 공부 총평대략 1년에 한번 10월즈음 슬럼프가 오는 것 같다. 한달간 따로 공부한건 서버리스를 위한 학습과 간간히 하던 스칼라 학습 말곤 없었던 것 같다.그래서 주간회고가 미뤄졌다. 쓸 게 없었기 때문이다. 그것에 대해서 생각을 해봤는데, 그냥 기존에 하던식의 학습을 하기엔 이젠 한계에 다다랐다.게다가 최근엔 굉장히 기본적인 몇가지 질문에 답을 할 수 없었던 일이 있었다. 아무리 복습을 안하면 까먹는다지만 이건 심했다.이것도 모르면서 개발자라고 말하기엔 스스로가 부끄럽다는 생각이 들었다.사실 이론적인 것을 몰라도 개발은 할 수 있다. 하지만 그런 개발자가 되고싶진 않았다.결론적으로 이제는 이론적인 공부를 피해갈 수 없게 되었다. 대학교 다닐 때 했던 CS 공부는 시험과 함께 까먹었으므로 다시해야한다.아직 어떤 책으로 공부할건지 정하진 않았지만 다음주 내에 책을 골라 공부를 시작하는게 목표이다.","categories":[{"name":"Logs","slug":"Logs","permalink":"https://sehajyang.github.io/categories/Logs/"}],"tags":[{"name":"weekly","slug":"weekly","permalink":"https://sehajyang.github.io/tags/weekly/"}]},{"title":"SQS, Lambda를 이용해 문자전송하기(1부)","slug":"sqs-lambda-python","date":"2019-09-25T08:31:35.000Z","updated":"2019-12-28T08:36:46.212Z","comments":true,"path":"2019/09/25/sqs-lambda-python/","link":"","permalink":"https://sehajyang.github.io/2019/09/25/sqs-lambda-python/","excerpt":"","text":"들어가며이 포스팅은 전체적으로 Get Started의 성격을 띄며 3부로 나눠져 있습니다.좌측 사이드바에서 목차 빠른 이동이 가능합니다. 1부 하고자 하는 것 SQS란? 아키텍쳐 Skill Set 구축 과정 SQS 생성 및 설정 SQS 큐 생성 SQS 큐 설정 SQS 권한설정 Lambda 생성 및 SQS로 메세지 전송하기 Lambda 함수생성 Lambda 함수에 SQS, RDS 권한 추가 SQS에 메세지 전송하기 Lambda layer로 DB 조회를 위한 외부 라이브러리 추가 2부 Lambda에서 EC2, RDS등 내부 서비스 접근 문제 해결하기 VPC설정으로 접근하기 VPC 란? Lambda 함수에 VPC 셋팅하기 SQS에 메세지를 보내기 위한 VPC 설정 VPC 추가한 상태로 외부 인터넷에 요청을 보내기 위한 방법들 VPC에 SQS 엔드포인트 추가 SQS에 메세지 전송하기 Cloud Watch Event로 Cron Job 붙이기 주의할 점 SQS 큐에 람다 트리거 함수 붙이기 3부 VPC 설정되어 있는 람다함수가 외부 인터넷에 요청 보내기 API Gateway 생성 및 설정 예외처리를 위한 DLQ 설정 운영 하면서 겪은 문제들 요금이 이렇게 나오다니? 람다 타임아웃 잘못된 DLQ 설정 에러 핸들링 예약문자 서비스를 위한 가장 좋은 설계 MQ 총평 하고자 하는 것외부 문자발송 API에 예약문자 발송 요청을 보내는 작업을 해야합니다. 단 조건이 있습니다. 예약문자가 발송되기 전이면 취소가 가능해야 합니다. 분할전송되는 문자의 순서를 보장하려고 합니다.분할전송되는 문자 순서의 경우, 순서에 맞게 요청을 보내도 문자 발송 API측에서 요청이 동시에 들어올 경우 순서를 섞어 발송합니다.분할문자의 순서가 섞이는 것을 방지하려면 많은 방법이 있지만 그 중 SQS의 DelaySeconds 옵션을 사용해 해결할 것 입니다. Amazon SQS란?SQS(Simple Queue Service)는 분산 메세지 큐 서비스로 메세지에 대한 수신, 송신만이 가능한 큐 입니다.인터넷을 통해 통신하며 웹 서비스 응용 프로그램을 통해 메세지를 전송할 수 있습니다.풀링(polling) 방식으로 동작하기 때문에 수신자는 매번 풀링하는 식으로 로직을 구성해야합니다.폴링은 유연하게 동작합니다.메세지 보관기간 지정, 전송 지연시간 지정, 실패한 작업을 배달못한 편지 대기열(DeadQueue)로 전송할 수 있는 기능등이 있습니다.백만 요청당 가격은 표준 : $ 0.40 / FIFO : $ 0.50 로 저렴한 편입니다.메세지는 최대 10개, 256KB 배치 송수신이 가능하며 SQS 배치 API 작업으로 비용을 절감할 수 있습니다.대기열 종류로는 표준과 FIFO를 제공합니다. 표준 FIFO 처리량 무제한으로 초당 트랜잭션(TPS)수 지원 일괄처리를 통해 초당 3000개 혹은 API작업별로 300개 메세지를 지원 전달 최소 한번 전달이지만 가끔 두번이상 전달되기도 함 정확히 한번 전달 순서 순서보장 안됨 순서보장 됨 람다 Lambda 트리거 가능 Lambda 트리거 불가능 19/11/20 이후로 가능하게 변경되었습니다 [링크] 여기서 중요하게 봐야될 점은 순서보장과 Lambda 트리거 가능 여부입니다.FIFO는 Lambda 트리거를 지원하지 않았습니다.하지만 2019/11/20 이후로 FIFO에서도 람다 트리거를 사용할 수 있도록 변경되었습니다.[관련 링크]이 포스팅을 작성할 당시 FIFO에서는 람다트리거를 사용할 수 없었기 때문에 저는 표준 대기열을 선택했지만, 순서가 중요하거나 한번만 전달되어야한다면 FIFO를 선택하시는게 좋습니다. 추가1)SQS 트리거에 Lambda를 붙일 경우, Lambda는 연속적으로 SQS대기열을 장기 풀링합니다.Lambda는 풀링을 자동조절 합니다.대기열이 비어있을땐 5개의 병렬 폴링 연결을 하며, 처리중인 메세지 수가 증가할 경우 메세지 요청을 20회, 동시성을 분당 60회 증가시킵니다.대기열이 계속 분주할 경우 동시성이 제한에 다다를 때 까지 요청과 동시성은 계속 증가됩니다.처리중인 메세지가 하락중일 경우엔 분당 요청을 10회, 동시성을 30회씩 감소시킵니다.만약 동시성등을 더 증가시켜야 한다면 aws측에 문의를 해서 제한을 풀어야합니다. 추가2)Lambda와 SQS는 반드시 같은 AWS 리전에 있어야 합니다.하나 이상의 Lambda함수에 하나의 SQS대기열만 연결할 수 있습니다. [관련 링크] 아키텍쳐기술스택 Python 3.7 AWS Lambda AWS SQS AWS API Gateway AWS VPC AWS RDS AWS CloudWatch 최종적으로 위와같은 구조가 됩니다 각 서비스에 대한 설명은 다음과 같습니다.send sqs func : 매 분마다 지금으로부터 발송 1분전의 시간으로 DB조회를 하고 delay를 계산해 SQS에 메세지 송신을 하는 람다 함수입니다.sqs trigger func : SQS의 람다 트리거 함수입니다. API Gateway로 요청을 보내고 응답을 받아서 DB(RDS)에 저장합니다.main queue : send sqs로부터 메세지를 수신한 뒤 sqs trigger가 주기적으로 풀링해 메세지를 가져옵니다.API Gateway : 내부 서비스가 외부 인터넷으로 요청을 보낼수 있게 도와줍니다. 플로우는 다음과 같습니다. send_sqs_func가 rds에 1분후에 보내야될 데이터를 조회하는 요청을 보냅니다 조회된 데이터로 SQS 전송 delay시간을 조정해 같은 사람에게 보낼 문자의 순서가 섞이지 않도록 값을 셋팅후 SQS로 메세지를 전송합니다. SQS에 쌓여있는 데이터를 sqs_trigger_func가 지속적으로 풀링해 가져옵니다. sqs_trigger_func 에서 Api Gateway를 통해 외부 문자 API로 요청을 보냅니다. Exception이 발생한 경우 dead_queue로 해당 메세지를 보냅니다. 그럼 바로 예제에 들어가도록 하겠습니다. 구축과정SQS 생성 및 설정우선 SQS를 생성하겠습니다. 위 아키텍쳐에서 설명했던 것과 같이 두개의 SQS 큐를 생성할 것 입니다. 우선 표준대기열로 main queue를 생성합니다. 우측 하단의 대기열 구성에서 세부적인 속성을 제어할 수 있습니다. 아직 속성을 설정하지 않을 것이므로 속성을 기본값으로 놔둔 뒤 대기열을 생성합니다.main queue와 동일한 방법으로 dead queue를 생성합니다.이제 생성된 큐 중 main queue 의 속성 중 리드라이브 정책 사용을 활성화 합니다. SQS 큐 설정배달못한 편지 대기열은 dead_queue로 설정 뒤 변경사항을 저장합니다. SQS의 기본설정은 short polling입니다. 만약 비용을 줄이고 싶다면 메시지 수신 대기시간을 조정해야 합니다.다음과 같은 경우 short polling 입니다: WaitTimeSeconds이 0으로 설정되어있는 경우ReceiveMessageWaitTimeSeconds이 0으로 설정되어 있는 경우 SQS의 long polling 과 short polling에 대해 더 알고 싶다면 [공식문서]를 참고해주세요. SQS 권한 설정sqs가 외부로부터 메세지를 수신받기 위해선 다음과 같은 권한이 필요합니다: sqs:ChangeMessageVisibilitysqs:DeleteMessagesqs:GetQueueAttributessqs:ReceiveMessage 권한 설정은 하단의 권한 탭에서 추가할 수 있습니다. 권한 추가 버튼을 클릭합니다. 프린시펄이 있다면 설정합니다. 권한설정 후 하단의 권한추가로 완료합니다. Lambda 생성 및 SQS로 메세지 전송하기send sqs func, sqs trigger func 라는 두개의 람다 함수를 만들 것입니다.우선 send sqs func를 만들어보겠습니다. 새 역할생성을 선택한 뒤 함수를 생성합니다. Lambda 함수에 SQS, RDS 권한 추가send sqs func는 위 아키텍쳐 섹션에서 설명했듯이 DB 조회결과를 sqs 큐로 보내는 작업을 하는 함수입니다.따라서 정책에 SQS와 RDS권한을 추가합니다.생성된 람다함수에 권한을 추가하기 위해함수코드 아래에 그림과 같이 실행역할 > 기존역할 > send-sqs-func-role-0opyfljq 역할을 확인하십시오.를 클릭합니다. 권한이 성공적으로 추가되었다면 send sqs func 페이지에서 새로고침을 합니다. 성공적으로 추가가 되었습니다. SQS에 메세지 전송하기SQS의 main queue에 메세지를 보내는 코드를 lambda_function에 작성합니다. 123456789101112131415161718192021222324252627282930313233import jsonimport osimport boto3import loggingfrom botocore.exceptions import ClientErrordef lambda_handler(event, context): _params = {'message': \"hello\"} msg_body = json.dumps(_params) msg = send_sqs_message(os.environ['SQS_QUEUE'], msg_body) return msgdef send_sqs_message(sqs_queue_url, msg_body): \"\"\" :param sqs_queue_url: String URL of existing SQS queue :param msg_body: String message body :return: Dictionary containing information about the sent message. If error, returns None. \"\"\" # Send the SQS message sqs_client = boto3.client('sqs') try: msg = sqs_client.send_message(QueueUrl=sqs_queue_url, MessageBody=msg_body) except ClientError as e: logging.error(e) return None return msg boto3 란?python용 aws sdk 입니다.람다에선 실행환경의 일부로 aws sdk의 여러버전이 포함되어 있으므로 굳이 설치하지 않아도 됩니다. 함수코드 하단의 환경변수에서 SQS_QUEUE를 추가합니다. 환경변수 SQS_QUEUE키에대한 값은 SQS main_queue의 URL 이며 SQS대기열 세부정보에서 확인할 수 있습니다. 람다 테스트는 기본 이벤트를 선택한 후 다음과 같이 생성합니다.오른쪽 상단의 save 후 테스트를 실행합니다. SQS에서 방금 송신한 메세지가 main queue에 있는것을 확인할 수 있습니다. Lambda layer로 DB 조회를 위한 외부 라이브러리 추가이제 RDS에 접근해 DB커넥션을 생성해보도록 하겠습니다.외부 라이브러리인 pymysql을 람다에서 사용해야합니다.우선 인라인 편집에서 DB 커넥션을 생성하는 부분을 lambda_function.py에 작성합니다. 12345678910111213141516171819202122232425262728293031323334353637383940414243444546import jsonimport osimport boto3import loggingimport pymysqlfrom botocore.exceptions import ClientErrordef lambda_handler(event, context): get_connection() _params = {'message': \"hello\"} msg_body = json.dumps(_params) msg = send_sqs_message(os.environ['SQS_QUEUE'], msg_body) return msgdef send_sqs_message(sqs_queue_url, msg_body): \"\"\" :param sqs_queue_url: String URL of existing SQS queue :param msg_body: String message body :return: Dictionary containing information about the sent message. If error, returns None. \"\"\" # Send the SQS message sqs_client = boto3.client('sqs') try: msg = sqs_client.send_message(QueueUrl=sqs_queue_url, MessageBody=msg_body) except ClientError as e: logging.error(e) return None return msgdef get_connection(): connection = pymysql.connect(host=os.environ['DB_ADDR'], user=os.environ['DB_HOST'], password=os.environ['DB_PASSWD'], db=os.environ['DB_NAME'], charset='utf8mb4', autocommit=True, cursorclass=pymysql.cursors.DictCursor) return connection 이제 람다 레이어에 사용할 외부 라이브러러를 추가할 것입니다.람다 레이어 설정에 대한 내용은 이 포스팅을 참고해주세요 : [AWS Lambda Layers로 함수 공통용 Python 패키지 재사용하기]람다 레이어에 올리기전 외부 라이브러리를 패키징할 때 주의할 점이 있습니다.압축을 풀었을 시 패키지들의 상위 폴더 이름은 python 이어야 합니다 123-python - 패키지폴더 1 - 패키지폴더 2 그렇지 않으면 라이브러리 import가 되지 않는다는 오류가 발생합니다.람다 레이어에 올린 라이브러리 압축파일은 aws측에서 내부적으로 압축 해제 후 다음과 같이 /opt 아래에 둡니다. /opt/python/패키지1 따라서 패키지의 상위 폴더 이름은 python 이어야 합니다. opt/python/lib/python3.7/dist-package/ 도 가능하기 때문에 패키지들의 상위 폴더가 /python/lib/python3.7/dist-package/ 여도 됩니다.마찬가지로 node등은 node로 상위 폴더 이름을 설정합니다. 프로젝트 파일을 zip으로 압축한 뒤 code entry type > .zip 파일 업로드로 방금 생성한 프로젝트 파일을 업로드합니다(aws cli를 사용중이라면 좀 더 편하게 배포할 수 있습니다)DB 접속정보등을 환경변수에 셋팅 후 상단의 save를 하고 테스트를 실행합니다.만약 RDS가 모든 접근을 허용한다면 아무 오류없이 성공을 출력할 것 입니다.하지만 RDS 인바운드에 몇가지 접근에 대해서만 허용해뒀다면 다음과 같이 타임아웃이 발생합니다.왜 그런걸까요? Lambda 함수가 보안그룹 설정이 되어있는 RDS에 접근할 수 없기 때문입니다.lambda 함수가 왜 RDS에 접근을 할 수 없는지에 대해 알기위해선 먼저 VPC에 대해서 알아야 합니다. 2부에선 VPC가 무엇이며 RDS 및 SQS 접근 문제를 해결해보도록 하겠습니다. 2부에 계속.. 읽어주셔서 감사합니다. 혹 궁금한게 있으시거나 오류가 있다면 댓글 남겨주세요🙆","categories":[{"name":"DevOps","slug":"DevOps","permalink":"https://sehajyang.github.io/categories/DevOps/"}],"tags":[{"name":"AWS","slug":"AWS","permalink":"https://sehajyang.github.io/tags/AWS/"},{"name":"DevOps","slug":"DevOps","permalink":"https://sehajyang.github.io/tags/DevOps/"},{"name":"Serverless","slug":"Serverless","permalink":"https://sehajyang.github.io/tags/Serverless/"}]},{"title":"스칼라 번역 - 명령형 프로그래밍(Imperative Programming)","slug":"imperative-programming","date":"2019-09-02T09:03:57.000Z","updated":"2021-06-20T04:25:47.790Z","comments":true,"path":"2019/09/02/imperative-programming/","link":"","permalink":"https://sehajyang.github.io/2019/09/02/imperative-programming/","excerpt":"","text":"이 포스팅은 [scala-exercises 번역 시리즈]로 scala-exercises 사이트의 스칼라 튜토리얼을 공부하며 번역한 문서 입니다.scala-exercises 는 스칼라 창시자인 마틴 오더스키 강의의 강의자료입니다.따라서 강의를 들으며 본 문서를 같이 보는것을 추천합니다.의역이 많습니다. 오역 및 오타 등은 코멘트로 알려주세요 😄원문 : [scala-exercises imperative programming] 지금까지의 예제에선 사이드 이펙트가 없었습니다.시간이 진행되던 말던 어차피 같은 결과를 반환하기 때문에 시간이라는 개념은 중요하지 않았습니다.종료되는 모든 프로그램에 대해 ‘일련의 모든 작업이 동일한 결과를 리턴’ 했습니다.치환모델(substitution model)이기 때문입니다. 역자 추가) 12345678sumOfSquares(3, 2+2)sumOfSquares(3, 4)square(3) + square(4)3*3 + square(4)9 + square(4)9 + 4*49 + 1625 ‘일련의 모든 작업이 동일한 결과를 리턴’ 한다는 것은sumOfSquares(3, 2+2) 에서 25가 구해지기까지의 과정들이 모두 동일한 결과(25)를 리턴한다는 뜻 입니다.이렇게 계산식을 지속적으로 치환해나가며 결과를 얻어나가는 방식을 치환모델이라고 합니다. substitution model(치환 모델)재정의에 의해 다시 값이 구해집니다: 이름은 방정식(정의)의 우측(right-hand side)으로 바꿔 평가됩니다. 함수 어플리케이션은 함수의 우측으로 바꾸고 동시에 형식 파라미터(formal parameter)를 실제 인수(argument)로 바꾸어 구해집니다. 역자 추가) x + 5 = y + 7 x + 5는 좌측(left-hand side, LHS) 이며 y + 7은 우측(right-hand side, RHS) 입니다. iterate와 square 함수가 있다고 가정해봅시다: 123def iterate(n: Int, f: Int => Int, x: Int) = if (n == 0) x else iterate(n - 1, f, f(x))def square(x: Int) = x * x 그런 다음, iterate(1, square, 3)호출은 다음과같이 재작성됩니다: 1234567iterate(1, square, 3)if (1 == 0) 3 else iterate(1 - 1, square, square(3))iterate(0, square, square(3))iterate(0, square, 3 * 3)iterate(0, square, 9)if (0 == 0) 9 else iterate(0 - 1, square, square(9))9 재작성(rewriting)은 어떤 구간에서도 수행될 수 있으며,종료되는 모든 재작성은 같은 결과로 이어집니다.이것은 함수형 프로그래밍의 이론인 람다-계산의 중요한 결과입니다.예를들어, 이 두번의 재정의는 결국 같은 결과로 이어질 것입니다: 123456if (1 == 0) 3 else iterate(1 - 1, square, square(3))iterate(0, square, square(3))// ORif (1 == 0) 3 else iterate(1 - 1, square, square(3))if (1 == 0) 3 else iterate(1 - 1, square, 3 * 3) Stateful Object객체의 집합으로 일반적인 세상을 묘사하자면, 어떤건 시간에 따라 변하는 성질을 갖고있습니다(끓는 물 등) 이런 객체를 stateful 하다고 하며, 이 상태는 시간으로부터 영향을 받습니다.예를들어 : 은행 계좌는 stateful 합니다. “100원을 인출할 수 있는가” 라는 질문은 계좌의 잔고상태에 따라 다르기 때문입니다. Stateful Object 의 구현변경가능한(mutable)상태인 객체는 변수로 구성됩니다.변수 정의는 값 정의와 비슷하지만, val 대신 var 로 작성됩니다. 12var x: String = \"abc\"var count = 111 값 정의와 마찬가지로 변수 정의는 값을 이름과 연결합니다.그러나, 이 변수 값의 경우 나중에 재할당을 통해 바뀔 수 있습니다: 12x = \"hi\"count = count + 1 객체안의 상태실제로 상태가 있는 객체는 일반적으로 가변멤버가 있는 객체(var)로 표시됩니다.다음은 은행 계좌 클래스입니다: 123456789101112class BankAccount { private var balance = 0 def deposit(amount: Int): Int = { if (amount > 0) balance = balance + amount balance } def withdraw(amount: Int): Int = if (0 < amount && amount <= balance) { balance = balance - amount balance } else throw new Error(\"insufficient funds\")} BankAccount 클래스는 계좌 상태를 나타내는 balance 변수를 갖고 있습니다.deposit과 withdraw 메소드는 balance의 할당에 의해 값이 변경됩니다.BankAccount 클래스 안의 balance는 private이므로 외부 클래스에선 접근할 수 없습니다.BanckAccount 객체는 다음과 같이 만들어집니다: 1val account = new BankAccount 가변객체의 동작다음은 계좌를 조작할 수 있는 프로그램입니다: 12345val account = new BankAccount // account: BankAccount = BankAccountaccount deposit 50 //account withdraw 20 // res1: Int = 30account withdraw 20 // res2: Int = 10account withdraw 15 // java.lang.Error: insufficient funds 같은 작업을 하는 코드가 있지만 각각 다른 결과를 리턴합니다.명백하게, account는 상태 객체(stateful object)입니다. IDENTITY와 변화두 표현식이 “동일한”것인지를 결정하는 새로운 문제가 있습니다.할당을 제외한 작성은 다음과 같습니다: 1val x = E; val y = E E는 임의의 표현식이며, x와 y는 같은 것으로 칩니다: 1val x = E; val y = x 이 프로퍼티는 일반적으로 참조 투명하다라고 합니다.그러나 할당을 허용하면, 두 공식은 달라집니다.예를들어 다음과 같이 x, y 를 정의하면: 12val x = new BankAccountval y = new BankAccount x 와 y는 같나요? OPERATIONAL EQUIVALENCE위의 x 와 y는 같냐는 질문에 답을 하려면 우선 “같음”의 의미에 대해 정의해야 됩니다.“같아짐(being the same)”의 정확한 뜻은 operational equivalnance의 프로퍼티(property) 의해 정의됩니다. 역자추가) 프로퍼티란’어떤 값’이며 이 값이 다른 값과 연관을 갖고있을때 프로퍼티 라고 부릅니다. 예를들어 length 프로퍼티는 문자열 혹은 리스트등의 객체의 길이를 양의 정수로 나타낸 값을 갖고 있습니다. 다소 비공식적인 방식으로, 이 프로퍼티는 다음과 같이 명시됩니다: x, y라는 두개의 정의가 있다고 가정합니다. x 와 y는 구별할 수 있는 테스트가 없을 경우 연산적으로 동등합니다. OPERATIONAL EQUIVALENCE 을 위한 테스팅만약 x 와 y가 같음을 테스트한다면가능한 결과를 관찰하며 x와 y를 포함하는 연산의 임의의 시퀀스 S에 따른 정의를 실행합니다. 123val x = new BankAccountval y = new BankAccountf(x, y) 그런다음, 모든 y 발생 항목의 이름을 S의 x로 변경해서 얻은 다른 시퀀스인 S'로 정의를 실행합니다. 123val x = new BankAccountval y = new BankAccountf(x, x) 만약 결과가 다르다면 x 와 y는 명백히 다른 표현식입니다.반면에, 만약 (S, S') 시퀀스의 가능한 모든 쌍이 같은 결과를 나타낸다면, x 와 y는 같습니다.이 정의에 따라 다음 표현식을 봅시다: 12val x = new BankAccountval y = new BankAccount 테스트 시퀀스별로 다음 정의를 봅시다: 1234val x = new BankAccountval y = new BankAccountx deposit 30y withdraw 20 // java.lang.Error: insufficient funds 이제 이 시퀀스에서 y의 모든 항목의 이름을 x로 변경하면 다음의 결과를 얻게됩니다: 1234val x = new BankAccountval y = new BankAccountx deposit 30x withdraw 20 shouldBe 10 두 예제의 최종 결과는 다릅니다. 결론적으로 x 와 y는 동일하지 않습니다. OPERATIONAL EQUIVALENCE 의 성립반면에, 만약 다음과 같이 정의한다면: 12val x = new BankAccountval y = x x와 y 를 구분할 수 있는 일련의 작업이 없으므로 이 경우에 x와 y는 같습니다. SUBSTITUTION MODEL 의 할당위의 예는 치환에 의한 계산의 모델을 사용할 수 없음을 보여줍니다.실제로 이 모델에 따르면, 항상 ‘값 이름을 정의하는 표현식’ 으로 값 이름을 바꿀 수 있습니다.예를들어: 12val x = new BankAccountval y = x y의 정의 안에 있는 x(val y = x)는 new BankAccount로 치환될 수 있습니다.그러나 여기에 할당을 추가하게되면 치환모델은 불가능해집니다.store를 도입하여 치환모델을 적용하는게 가능하긴 하지만 이럴경우 훨씬 더 복잡해집니다. 명령형 루프첫번째 섹션에서 재귀를 사용해 루프를 작성하는 법을 살펴봤습니다. While-Loop그러나 재귀외에 while을 사용해 루프를 작성할 수 있습니다: 123456def power(x: Double, exp: Int): Double = { var r = 1.0 var i = exp while (i > 0) { r = r * x; i = i - 1 } r} while의 조건이 true 상태인 동안 body는 계속해서 값이 구해집니다. For-Loop다음은 스칼라에서의 for 종류중 하나입니다: 1for (i <- 1 until 3) { System.out.print(i + \" \") } 이것은 1 2라는 결과를 보여줍니다.for loop는 for 표현식과 비슷하지만 map과 flatMap 대신 foreach 콤비네이터(combinator)를 사용합니다. 역자추가) 콤비네이터는 함수와 컬렉션 등 다른 식을 받아서 적절한 작업을 해주는 조합 장치(함수) 정도로 생각하면 됩니다. 출처- 함수콤비네이터 타입 A 엘리먼트와 함께 forEach는 컬렉션으로 정의됩니다 : 12def forEach(f: A => Unit): Unit = // apply `f` to each element of the collection 예를들어 다음은: 1for (i <- 1 until 3; j <- \"abc\") println(s\"$i $j\") 이렇게 바꿀 수 있습니다. 1(1 until 3) foreach (i => \"abc\" foreach (j => println(s\"$i $j\"))) 연습문제factorial의 필수 구현을 완료하세요: 1234567891011121314def factorial(n: Int): Int = { var result = 1 var i = 1 while (i <= n) { result = result * i i = i + 1 } result}factorial(2) shouldBe 2factorial(3) shouldBe 6factorial(4) shouldBe 24factorial(5) shouldBe 120 읽어주셔서 감사합니다. 혹 글에 오역/추가할 내용이 있다면 코멘트 남겨주세요! 같이 보면 좋은 자료 스칼라학교의 Collection (한글) 스택오버플로우의 콤비네이터에 대한 설명 (영어)","categories":[{"name":"Scala","slug":"Scala","permalink":"https://sehajyang.github.io/categories/Scala/"}],"tags":[{"name":"Scala","slug":"Scala","permalink":"https://sehajyang.github.io/tags/Scala/"},{"name":"scala-exercises","slug":"scala-exercises","permalink":"https://sehajyang.github.io/tags/scala-exercises/"}]},{"title":"190805-190902 월간 회고","slug":"190805-190902","date":"2019-09-02T01:50:13.000Z","updated":"2019-11-16T08:45:45.538Z","comments":true,"path":"2019/09/02/190805-190902/","link":"","permalink":"https://sehajyang.github.io/2019/09/02/190805-190902/","excerpt":"","text":"이번달은 마침 2주간 회고를 쓰는 주에 파이콘이 있었기 때문에, 파이콘 후기를 쓰면서 주간회고를 건너뛰게 되었다.그렇게 이번 회고는 월간회고가 되었다.한달간 정신없이 돌아갔는데 기억나는 것 위주로 정리하자면 이렇다. 파이콘 2019 참가 뱅크샐러드 세미나(콘샐러드) 참석 Akka HTTP로 프로덕션에 쓰일 파일관련 서버 만들기(라고 쓰고 삽질기라고 읽는다) Amathon 참가 파이콘 2019 참가pycon 2019 후기 포스팅을 했으니 월간회고에서는 패스 뱅크샐러드 세미나(콘샐러드) 참석1:30 부터 6:30까지 진행됐는데, 오랜시간 앉아있어 허리는 아팠지만 내용이 너무 좋았다.특히 정겨울님이 발표하신 오픈소스 라이브러리 개발기가 인상깊었다.오픈소스 라이브러리를 개발할때에 어떤것을 명시해야하며, 어떻게 디스크립션을 작성해야 하는지에 대한 내용이 꽉차게 들어있었다.너굴맨 프로젝트를 개선할 때에 요긴하게 참고할 수 있을 것 같다.발표자료 : 링크 Akka HTTP로 프로덕션에 쓰일 파일관련 서버 만들기중요하거나 민감한 정보(aws 키, db 접속정보 등)를 담고 있는 파일을 s3에 저장하고, 회사 아이피에서만 접근할수 있는 서버를 만들어야 했다.간단하게 말하자면 s3 파일을 서빙해주는 서버이다.플라스크로 만드는게 가장 빠르고 간단했겠지만, 왠지 모를 자신감으로 스칼라로 만들겠다 했다.Actor모델을 좀 알고싶어서 일단 패기롭게 Akka HTTP를 골라서 개발하기 시작했다. 이름에 HTTP가 있어서 웹 프레임워크 같겠지만 웹 프레임워크가 아니다! Akka 공식문서를 보면서 개발했는데, scala Future를 잘 모르고 개발하다보니 탈탈 털려버렸다.그래도 어찌어찌 완성했는데, 그렇다고 Akka를 좀 알게 됐다던지.. 그런건 아니고 그냥 이제 막 걸음마를 뗀것 같다(누가 시작이 반이라고 하던데 시작은 그냥 시작일 뿐이다..) Amathon 2019 참가웃기게도, 나는 Amathon이 Armature + Hackaton = Amathon 인줄 알았다.대상도 주니어 or 학생 개발자였기 때문에 난이도가 평이할 줄 알았는데 주제를 보니 아무래도 음.. 몇몇 주제가 주니어 대상인건 아닌것같았다.그리고 어제 해커톤 결과물 발표를 들으며 깨달았는데 이건 Amazon+Hackaton 이었던 것 이다!.어쩐지 실력 쟁쟁한 참가자분들이 많더라..그리고 주니어가하기엔 어려운 주제가 많았다 카더라..이번 해커톤은 신기하게도 기획이(주제가) 정해져 있고, 원하는 주제를 골라 3지망까지 적어서 제출해야했다.공유가능한 실시간 만다라트 차트 웹이라던지 유투브 댓글추첨 웹 만들기라던지 하는 재밌어보이는 주제가 많았다.하지만 이번엔 웹 서비스를 만들기보단 백엔드에 집중하는 Pub/Sub Baas 만들기가 재밌을 것 같아서주제 16번의 WebSocket 기반의 스케일아웃 고려한 Real-time Pub/Sub BaaS 만들기를 선택했다.우리팀은 3명이었는데, 특이하게 백엔드 3명이었다. 처음엔 조원이 덜 온줄 알았는데 3명이 끝이였다..Baas를 만들어야 했으므로 프론트에 차트를 그려줄 능력자분이 필요했고 감사하게도 한분이 장고를 이용해서 하겠다 하셨다.나는 서버API 담당이었고 Real-time이란 조건 때문에 비동기 프레임워크를 사용했다.이 프로젝트의 핵심은 ZeroMQ와 비동기였다. 난이도가 살벌했다.나는 이번 해커톤을 하며 ZeroMQ에 대해 처음알게 되었다. 혹시 모르는 분들을 위해 간략하게 설명하자면 다음과 같다. ZeroMQ(ZMQ)ZeroMQ는 분산/동시성 애플리케이션에 사용하도록 개발된 아주 가벼운 고성능 비동기 메세징 라이브러리입니다.RabbitMQ와 달리 다양한 프레임워크를 결합해 직접 구현해야한다는 단점이 있습니다.또한 다음과 같은 특징이 있습니다. 동시성 프레임 워크 역할을하는 소켓 라이브러리 클러스터 제품 및 슈퍼 컴퓨팅을 위해 TCP보다 빠름 inproc, IPC, TCP 및 멀티 캐스트를 통한 메시지 전달(유니캐스트도 가능) 팬 아웃, pubsub, 파이프 라인, 요청-응답을 통해 N-to-N 연결 확장 가능한 멀티 코어 메시지 전달 앱을위한 비동기 I / O MQ로는 이렇게 ZeroMQ를 사용했으며 서버는 파이썬의 비동기 프레임워크인 Sanic을 사용했다.DB는 memcached와 redis 사이에서 고민하다 redis를 선택했다. 이번 서비스를 만듦에 있어 성능차이가 없고 redis가 익숙하고 복구도 용이해서..라이브러리도 asyncio 관련 라이브러리를 사용해야한다 따라서 asyncio-redis를 사용했다.aioredis도 있는데 문서가 불친절하다. 그냥 사용하기엔 asyncio-redis 예제가 잘 되어있어 사용하기가 좋다.websocket 기반의 realtime pub/sub은 만들어 본 적이 있기도 했고 기획이 정해져 있어서 개발을 빨리 시작할 수 있었다.심지어 새벽에 쇼파에서 잠도 잘 수 있었다.ZeroMQ를 쓰려고 보니 라이브러리 형태가 아니었다. 그래서 지인은 ZMQ PubSub 라이브러리를 만들었다ㅋㅋ마감까지 2~3시간 남았을때에 지인이 빈스톡에 배포를 했는데 계속 500 에러가 났다.redis connection 문제였던 것 같다(보안그룹에 분명히 허용을 해뒀는데 이상한 일이다) 여담으로레디스 커넥션 문제라면 웹서버는 떠야하는데 왜 안뜨나 싶겠지만 이 서버는 시작시 레디스 커넥션을 하기 때문에 실패하면 띄워지지않는다.12345@app.listener('before_server_start')async def setup(app, loop): app.conn = await redis_set_get.create_connection_pool() app.pub_server = await PubSubServer.create(os.environ['REDIS_URI']) loop.create_task(app.pub_server.run_forever()) 우선 모든 아이피에 대해 허용하니 잘 돌아갔다. 어차피 도커에 레디스 띄운거라 그렇게 해도 괜찮긴 했다.배포 문제를 해결하고 나니 시간이 20분가량 남아서..아쉽게도 부하 테스트는 하지 못하고 그대로 ws client와 postman을 써서 시연을 하며 발표를 했다. 아쉬웠다.. 꼭 부하테스트를 해보고싶었다.발표자료는 레포에 같이 올려두었다: 링크이번 해커톤에서 다른 백엔드분들이 만든 서비스를 보며 백엔드가 이정돈 해야되는구나 라는걸 많이 느꼈고난 아직 멀었다는 생각을 많이 했던 것 같다. 다음주 목표 알고리즘 문제풀이 Akka서버 개발 계속 Scala 공부 및 번역 계속 총평이번달엔 ‘이세상에서 내가 제일못해 병’에 걸려서 우울했다.이 시기가 되면 내가 그동안 뭘 했나, 뭘 배웠나, 성장한게 있긴 한가 싶어서 굉장히 우울해진다. 그렇다고 개발이 재미없어지는건 또 아니다.사실 이 월/주간 회고도 이럴때를 대비해(?) 작성해왔던 것이다.꾸준히 공부해오고 있긴 하지만 부족한게 너무 많아서 슬프다.지금 이걸 공부하는게 맞는지, 이것에 집중하는게 맞는지 다른사람들은 어떻게 성장했는지 궁금하다.과거 취준생이던 시절엔 개발자로 취직하면 누군가 이끌어주거나 뭔가를 알려줄 거라 생각했었다. 하지만 그건 크나큰 오산이었다.취직 전이나 취직후나 혼자 알아내고 혼자 학습해야하는건 매한가지다.과거나 지금이나 내가 할수 있는건 그냥 공부하고 코딩하는게 전부라서 그냥 계속 징징대면서 해야겠다.","categories":[{"name":"Logs","slug":"Logs","permalink":"https://sehajyang.github.io/categories/Logs/"}],"tags":[{"name":"weekly","slug":"weekly","permalink":"https://sehajyang.github.io/tags/weekly/"}]},{"title":"pycon 2019 후기","slug":"pycon2019","date":"2019-08-23T07:35:15.000Z","updated":"2019-11-16T08:45:45.563Z","comments":true,"path":"2019/08/23/pycon2019/","link":"","permalink":"https://sehajyang.github.io/2019/08/23/pycon2019/","excerpt":"","text":"사진을 거의 안찍어서 행사장 사진은 이것뿐이었다.. 나는 8월 15 ~ 18일 총 4일간 열린 파이콘 중 17, 18일 참석을 했다!.작년에도 참석하고 싶었지만 그땐 금전난이라 갈 수가 없었는데 올해는 감사하게도 회사의 지원을 받아 우리회사 개발자 대부분이 참석하게 되었다.파이콘은 한국에서 열리는 개발 컨퍼런스 중 가장 크다고 들었는데, 확실히 코엑스 한쪽을 전부 빌려 사용하는 위용(?) 을 보여주었다.티켓은 총 1800개가 팔렸다고 한다. 나는 그중 60번째 구매자였다! 나는 파이콘에서 듣고싶은 세션을 정리해서 갔었는데 후원사 부스, 코딩게임 참가등의 이유로 아쉽게도 듣고싶은 세션을 다 듣진 못했다.내가 들은 세션은 다음과 같다: 1일차 키노트(반병현 님) 파이썬의 변수 (강한 타입, Immutable vs Mutable, Class vs Instance) 셀러리 핵심과 커스터마이제이션 Python에서 DSL 제작하기 라이트닝 토크 2일차 Multitasking 환경을 상대하기 위한 DB의 특성과 그런 DB를 상대하기 위한 Django gRPC 와 python 을 활용한 Microservice 개발기 Pickle & Custom Binary Serializer 라이트닝 토크 참가한 열린공간은 다음과 같다 : 비동기 Asyncio 함수형 Kotlin 1일차코딩하는공익 으로 유명하신 반병현님의 키노트는 역시나 재미있다. 키노트(반병현 님)반병현님의 발표를 처음 들은건 올해 2월에 있었던 KCD에서 였다.이번 파이콘때의 발표는 KCD때 하셨던 내용 + 브런치에 연재하신 내용으로 구성이 되어있었다.새로운 썰(?)을 기대한 나는 조금 아쉬웠지만 다시 들어도 재밌었다. 역시 믿고듣는 반병현님의 발표였다.[발표자료] 파이썬의 변수 (강한 타입, Immutable vs Mutable, Class vs Instance)이 세션에선 파이썬의 스코프, 클래스와 인스턴스의 차이점등을 다뤘는데 알고있던 내용들이 대부분이었다.하지만! nonlocal은 몰랐다.nonlocal은 전역변수를 포함한 상위 스코프의 이름을 사용한다는 키워드이다.[발표자료] 참고 셀러리 핵심과 커스터마이제이션나는 셀러리를 사용하지 않지만, 회사 서비스중 셀러리를 이용한 서비스가 있다.때문에 언젠간 셀러리를 하게 될 것 같아서 들었는데, 대상이 셀러리를 사용해본 경험이 있는 개발자였기 때문에 나에겐 맞지 않는 내용이었다.실무에서 셀러리를 사용하고있는 지인분은 정말 좋은 내용이며 도움이 많이 됐다고 호평하셨다.[발표자료] Python에서 DSL 제작하기30분동안 줄 서 있었던 뱅크샐러드의 코딩게임을 해야했기 때문에 이 세션을 듣지 못했다.이번 파이콘 중 굉장히 기대한 세션이었는데 못 들어서 아쉬웠다. 발표영상을 기다리는 세션 중 하나이다.[발표자료] 2일차Multitasking 환경을 상대하기 위한 DB의 특성과 그런 DB를 상대하기 위한 Django이 세션은 lock관련 문제를 다뤘는데, 지금 회사에서 겪고있는 lock 관련 문제를 해결하는데에 도움이 될 것 같았다.실무에서 Django를 사용하지 않는 개발자가 들어도 좋은 내용이었다.[발표자료] gRPC 와 python 을 활용한 Microservice 개발기gRPC를 사용하게 될 날이 올 것 같아 들었는데, 도입과정이 차근차근 나와있어서 좋았다.마지막에 프레임워크를 만드셨는데 구조를 나눈 이유 부분이 특히 인상깊었다.[발표자료] 총평파이콘은 이번에 처음 참가해봤는데, 파이콘에서 내가 들은 세션들은 실무에 도움이 될, 어디가서 안 알려줄 좋은 내용들로 구성되어 있었다.Real-world asyncio을 굉장히 듣고 싶었다.국내에서 실무에 적용한 사례를 들은적이 없었기 때문이다(풍문으로만 들었다. 어디어디회사가 쓴다더라~)프로덕션에 Asyncio를 사용할 당시 개념 자체도 어려웠으며 관련 자료는 찾아봐도 적었다.그래서 Asyncio 세션에 기대를 많이 했는데, 아침에 늦잠을 자는 바람에 놓쳐버렸다. 약 한달 후에 공개될 발표영상을 봐야겠다. 나는 낯을 조금 가리는데, 어디서 스칼라얘기가 들려서 보니 열린공간의 코틀린 테이블이었다!.용기를 내서 참석해봤는데, 여려 분들과 함수형 얘기를 할 수 있어서 즐겁고 행복했다.함수형부터 코루틴까지 이런저런 얘기를 했는데 너무 즐거웠다. 라이트닝 토크를 들어야해서 중간에 나왔는데 아쉬웠다.Python에서 DSL 제작하기를 발표하신 분도 잠시 머물다 가셨는데, 파이썬을 마치 스칼라처럼 짠 걸 보여주셨다! 정말 인상깊었다. 같이 파이콘에 참가했던 지인이 말하길 파이콘의 꽃은 라이트닝 토크라고 했는데, 왜 그런지 알 수 있었다.발표시간은 5분으로 굉장히 짧았지만 전반적으로 즐겁고 재밌는 내용들이었다. 정규 세션보단 가볍고 즐거운 느낌이었다.전체적으로 비개발자 분들이 어떠한 문제를 해결하기 위해 파이썬을 써봤는데 이렇게 해결할 수 있었다! 같은 내용이 많았는데, 자바나 스칼라쪽에선 거의 찾아볼 수 없는 사례라 굉장히 신선하고 재밌었다.나는 이렇게 읽기쉽고 배우기쉽고 사용하기 쉬운 파이썬의 철학이 좋다. 후원사 부스에선 많은 것이 준비되어 있었다. 퀴즈, 게임, 굿즈 등등 정말 준비를 많이 한 것 같았다.굿즈도 굉장히 많이 받았다. 공식굿즈 포함 티셔츠만 거의 다섯개는 받은것 같다.스티커와 재미있는 굿즈도 많이 받았다. 내 노트북에 붙일 스티커가 많아졌다.노트북이 많이 무거워서 들고가지 못했다. 그래서 몇가지 게임/퀴즈에 참가하지 못해서 굉장히 아쉬웠다. 내년엔 가벼운 노트북을 장만해 퀴즈/게임에 참가해봐야겠다. 마지막날은 엔딩까지 함께했는데, 이렇게 엔딩을 하는 세미나는 처음이었던 것 같다.(아니면 내가 늘 마지막 세션 듣자마자 집에 가느라 경험하지 못했던 것일 수도 있다)엔딩을 함께하는데 뭔가 찡했다.양일간 파이콘에서 파이썬을 좋아하는 사람들과 함께 다같이 좋아하는 얘기를 하고, 세션을 듣고 게임에 참여하고, 그런게 너무 좋았다.내년에도 참가해야겠다😎","categories":[{"name":"Seminar","slug":"Seminar","permalink":"https://sehajyang.github.io/categories/Seminar/"}],"tags":[{"name":"seminar","slug":"seminar","permalink":"https://sehajyang.github.io/tags/seminar/"},{"name":"pycon","slug":"pycon","permalink":"https://sehajyang.github.io/tags/pycon/"}]},{"title":"스칼라 번역 - 객체지향 (Object Oriented Programming)","slug":"oop","date":"2019-08-06T14:46:00.000Z","updated":"2021-02-09T15:14:45.565Z","comments":true,"path":"2019/08/06/oop/","link":"","permalink":"https://sehajyang.github.io/2019/08/06/oop/","excerpt":"","text":"이 포스팅은 [scala-exercises 번역 시리즈]로 scala-exercises 사이트의 스칼라 튜토리얼을 공부하며 번역한 문서 입니다.scala-exercises 는 스칼라 창시자인 마틴 오더스키 강의의 강의자료입니다.따라서 강의를 들으며 본 문서를 같이 보는것을 추천합니다.의역이 많습니다. 오역 및 오타 등은 코멘트로 알려주세요 😄원문 : [scala-exercises object_oriented_programming] 객체지향 프로그래밍함수와 데이터어떻게 함수가 생성되고 데이터 구조를 캡슐화 하는지 살펴보겠습니다.우린 산술연산을 위한 패키지를 만들려 합니다.분수 x/y는 두가지 정수로 표현됩니다: 분자 x 그리고 분모 y 유리수 덧셈두 분수의 덧셈을 하고 싶다고 가정해봅시다. 12def addRationalNumerator(n1: Int, d1: Int, n2: Int, d2: Int): Intdef addRationalDenominator(n1: Int, d1: Int, n2: Int, d2: Int): Int 이 많은 분자와 분모를 관리하기는 어렵습니다!.이렇게 하기보단, 데이터구조 안에서 분자와 분모를 결합하는 것이 더 낫습니다. 클래스스칼라에서, 클래스를 이렇게 정의할 수 있습니다: 1234class Rational(x: Int, y: Int) { def numer = x def denom = y} 이 정의는 두가지 엔티티를 나타냅니다: Rational 이라는 새로운 타입 이러한 타입으로 요소를 생성하기 위한 Rational 생성자스칼라는 서로 다른 네임스페이스에 타입과 생성된 값을 보관합니다. 따라서 Rational에 대한 두 정의끼리 충돌하지 않습니다. 객체클래스 타입의 요소(element)는 객체라고 불리며 클래스 생성자의 어플리케이션 앞에 new 연산자를 붙여 객체를 생성합니다. 1new Rational(1, 2) 객체의 멤버Rational 클래스 의 객체는 numer 과 denom 라는 두 멤버를 갖고 있습니다.자바처럼 . 연산자를 객체에 붙여 멤버를 호출할 수 있습니다. 123val x = new Rational(1, 2) // x: Rational = Rational@2abe0e27x.numer // 1x.denom // 2 분수 연산이제 스탠다드 룰에 따른 분수를 연산하는 함수를 정의할 수 있습니다. 12345n1 / d1 + n2 / d2 = (n1 * d2 + n2 * d1) / (d1 * d2)n1 / d1 - n2 / d2 = (n1 * d2 - n2 * d1) / (d1 * d2)n1 / d1 * n2 / d2 = (n1 * n2) / (d1 * d2)n1 / d1 / n2 / d2 = (n1 * d2) / (d1 * n2)n1 / d1 = n2 / d2 iff n1 * d2 = d1 * n2 분수 연산 구현12345678def addRational(r: Rational, s: Rational): Rational = new Rational( r.numer * s.denom + s.numer * r.denom, r.denom * s.denom )def makeString(r: Rational) = r.numer + \"/\" + r.denom 그런다음 : 1makeString(addRational(new Rational(1, 2), new Rational(2, 3))) 메소드더 나아가 데이터 추상화 자체에서 데이터 추상화에 따라 작동하는 기능도 패키징할 수 있습니다.이러한 함수를 메소드 라고 합니다.Rational 클래스는 numer 과 denom 함수 뿐 만 아니라 add, sub, mul, div, equal, toString 함수도 있습니다.구현은 다음과 같습니다: 123456789class Rational(x: Int, y: Int) { def numer = x def denom = y def add(r: Rational) = new Rational(numer * r.denom + r.numer * denom, denom * r.denom) def mul(r: Rational) = ... ... override def toString = numer + \"/\" + denom} 수정자 override 선언은 java.lang.Object 클래스에 있던 toString 메소드를 재정의 합니다.다음은 new Rational 을 사용하는 방법 입니다: 1234val x = new Rational(1, 3)val y = new Rational(5, 7)val z = new Rational(3, 2)x.add(y).mul(z) 데이터 추상화위의 분수 예제는 항상 가장 단순한 형태로 표현된 것이 아닙니다.역자 추가) 42/77 은 6/11로 약분될 수 있지만, 위의 분수 예제는 42/77 을 나타내므로 가장 단순한 형태(약분이 다 된 상태) 가 아니란 뜻따라서 분수가 약분될 수 있음을 예상할 수 있습니다: 최대공약수로 나눠서 가장 작은 분자와 분모로 줄입니다 우린 분수 연산을 할 때 마다 약분을 할 수 있지만 약분해야 한다는 걸 금방 까먹을 것 입니다.그러니 다음과 같이 객체가 생성될 때 클래스의 약분함수를 거쳐 객체가 생성되는게 더 낫습니다. 1234567class Rational(x: Int, y: Int) { private def gcd(a: Int, b: Int): Int = if (b == 0) a else gcd(b, a % b) private val g = gcd(x, y) def numer = x / g def denom = y / g ...} gcd와 d는 private 멤버이므로, Rational 클래스 안에서만 접근할 수 있습니다.이 예제에서, gcd 함수를 즉시 계산하며, 그 값을 numer과 denom의 계산에서 재사용할 수 있습니다.또한 numer과 denom 코드안에서 gcd 호출이 가능합니다(Rational 클래스 안이기 때문에): 12345class Rational(x: Int, y: Int) { private def gcd(a: Int, b: Int): Int = if (b == 0) a else gcd(b, a % b) def numer = x / gcd(x, y) def denom = y / gcd(x, y)} 위 코드는 numer과 denom 함수가 가끔 호출되는 경우에 유리합니다.numer과 denom의 def를 val로 변환하는 것 과도 같습니다. 그리고 val 는 단 한번만 계산됩니다: 12345class Rational(x: Int, y: Int) { private def gcd(a: Int, b: Int): Int = if (b == 0) a else gcd(b, a % b) val numer = x / gcd(x, y) val denom = y / gcd(x, y)} 이는 numer과 denom이 종종 호출될 때 유리합니다. 클라이언트 뷰클라이언트는 각각의 케이스에서 정확히 같은 경향을 보입니다.클라이언트에 영향을 주지 않고 데이터의 다른 구현을 선택할 수 있는 이러한 기능을 데이터 추상화라고 합니다.이것은 소프트 엔지니어링의 초석입니다. 자기 참조클래스 내부의 this는 현재 메소드가 실행되는 객체를 나타냅니다.Rational 클래스에 less 와 max 함수를 추가해봅시다: 12345678class Rational(x: Int, y: Int) { ... def less(that: Rational) = numer * that.denom < that.numer * denom def max(that: Rational) = if (this.less(that)) that else this} 클래스의 다른 멤버를 참조하는 x는, this.x이 생략된 표현됩니다. this를 생략하지 않은 less 구현은 다음과 같습니다: 12def less(that: Rational) = this.numer * that.denom < that.numer * this.denom 전제 조건(Preconditions)Rational 클래스의 분모는 양의 정수여야 한다고 가정해봅시다.require 라는 함수로 이를 구현할 수 있습니다. 1234class Rational(x: Int, y: Int) { require(y > 0, \"denominator must be positive\") ...} require는 미리 정의된 함수입니다. 이 함수는 조건과 메세지 문자열(옵션)이 필요합니다.만약 require의 조건 결과가 false 라면 메세지 문자열과 함께 IllegalArgumentException 오류를 던집니다. ASSERTIONSrequire 말고, assert도 있습니다.assert또한 조건과 메세지 문자열(옵션)이 필요합니다. 12val x = sqrt(y)assert(x >= 0) require 처럼 assert의 조건이 실패시 예외를 던집니다, 그러나 assert의 AssertionError과 require의 IllegalArgumentException는 한가지 차이가 있습니다.이것은 의도의 차이를 나타냅니다. require는 함수 호출시 사전 조건을 적용하는데에 사용됩니다. assert는 함수의 자체의 코드를 검사하기 위해 사용됩니다. 생성자스칼라에서, 클래스는 암시적으로 생성자를 선언합니다. 이것을 주 생성자(primary constructor)라고 합니다.주 생성자는 : 클래스의 파라미터를 가져옵니다. 그리고, 클래스 바디안의 모든 명령문을 실행합니다(require 같은 것들) 보조 생성자또한 스칼라는 보조생성자의 선언을 허용하며 이름은 this라고 합니다.Rational 클래스에 보조 생성자를 추가해봅시다: 1234class Rational(x: Int, y: Int) { def this(x: Int) = this(x, 1) ...} 클래스와 치환(Subtitution)이전엔 치환에 기반한 계산 모델을 사용해 함수 어플리케이션의 의미를 정의했습니다. 이제 이 모델을 클래스와 객체로 확장합니다.new C(e1, …, en)(C: 클래스, e: 인스턴스)는 어떻게 값이 구해질까요?표현식 인수(argument) e1, …, en는 일반 함수의 인수와 같이 간주됩니다.결과 표현식 new C(v1, …, vn)은 이미 값입니다.이제 클래스 정의가 있다고 가정해봅시다: 12345class C(x1, …, xn) { … def f(y1, …, ym) = b …} x1, …, xn는 클래스의 형식적인 파라미터입니다. 이 클래스는 y1, …, ym파라미터가 있는 f 메소드를 정의합니다 (함수 파라미터 리스트가 없을 수 있습니다. 심플함을 위해, 파라미터 타입을 생략했습니다)다음의 표현식은 어떻게 될까요? 1new C(v1, …, vn).f(w1, …, wm) 다음과 같은 세가지의 치환이 발생합니다. 인수 w1, ..., wm에 대한 함수 f의 매개변수 y1, ..., ym 치환. 클래스 인수 v1, ..., vn에 의한 클래스 C의 매개변수 x1, ..., xn 치환 자체 참조 this를 new C(v1, ..., vn) 객체의 값으로 치환. 연산자원칙적으로, Rational이 정의한 분수는 정수와 같습니다(분수는 정수라는 뜻).하지만 눈에 띄는 차이점이 있습니다: x 과 y가 정수인 x+y를 작성했지만, r.add(s)의 경우 r과 s 는 분수입니다. 역자추가) x와 y는 정수라서 +가 되는데 r과 s는 분수라 +가 없어서 add 메소드를 씀니다.근데 원칙적으로 분수는 정수인데 뭐지? 라는 차이점이 있다는 뜻 입니다. 스칼라에선, 연산자를 식별자로 사용할 수 있으므로 이 차이를 없앨 수 있습니다.식별자는 다음과 같습니다: Alphanumeric : 문자로 시작하고 문자 또는 숫자 시퀀스 심볼릭 : 연산자 기호로 시작하고, 그 뒤에 다른 연산자 기호가 옵니다. 밑줄 문자 _는 문자로 계산됩니다. Alphanumeric 식별자는 밑줄로 끝나며 일부 연산자 기호가 이어질 수 있습니다. 식별자 예제: 1x1 * +?%& vector_++ counter_= 분수를 위한 연산자여기 Rational 클래스에 대한 보다 자연스러운 정의가 있습니다: 1234567891011121314class Rational(x: Int, y: Int) { private def gcd(a: Int, b: Int): Int = if (b == 0) a else gcd(b, a % b) private val g = gcd(x, y) def numer = x / g def denom = y / g def + (r: Rational) = new Rational( numer * r.denom + r.numer * denom, denom * r.denom ) def - (r: Rational) = ... def * (r: Rational) = ... ...} 이제 분수는 Int 나 Double 처럼 사용될 수 있습니다. 123val x = new Rational(1, 2)val y = new Rational(1, 3)x * x + y * y 우선순위 규칙연산자 우선순위는 첫 문자에 의해 결정됩니다.다음은 우선순위가 높은 순서대로 문자를 나열한 것 입니다: 12345678910(all letters)|^&< >= !:+ -* / %(all other special characters) 추상 클래스IntSet 클래스의 작성에 대해 생각해봅시다. 1234abstract class IntSet { def incl(x: Int): IntSet def contains(x: Int): Boolean} IntSet은 추상 클래스입니다.추상 클래스는 구현이 되지 않은 멤버를 포함할 수 있습니다(이 경우엔, incl과 contains 이며 추상메소드 라고 합니다).그렇기 때문에, 추상클래스는 new 연산자로 새로운 객체를 생성할 수 없습니다. 클래스 확장set 을 이진트리로 구현하는 것에 대해서 생각해봅시다.가능한 트리에는 두가지 타입이 있습니다. 빈 세트에 대한 트리 정수와 두개의 하위트리로 구성된 트리 구현은 다음과 같습니다: 1234567891011121314151617class Empty extends IntSet { def contains(x: Int): Boolean = false def incl(x: Int): IntSet = new NonEmpty(x, new Empty, new Empty)}class NonEmpty(elem: Int, left: IntSet, right: IntSet) extends IntSet { def contains(x: Int): Boolean = if (x < elem) left contains x else if (x > elem) right contains x else true def incl(x: Int): IntSet = if (x < elem) new NonEmpty(elem, left incl x, right) else if (x > elem) new NonEmpty(elem, left, right incl x) else this} Empty와 NonEmpty는 IntSet 클래스를 상속 받았습니다.이 상속은 Empty와 NonEmpty의 타입이 IntSet의 타입을 따르게 합니다.Empty 혹은 NonEmpty는 IntSet 타입의 객체가 필요한 곳이라면 어디서나 사용할 수 있습니다. IntSet은 Empty와 NonEmpty의 ‘슈퍼클래스’ 라고 불립니다.Empty 및 NonEmpty는 IntSet의 하위 클래스입니다.스칼라에서는 사용자 정의 클래스가 다른 클래스를 상속받습니다.슈퍼 클래스가 주어지지 않는 경우, Java 패키지 java.lang의 표준 클래스 객체로 가정합니다.C 클래스의 직접 또는 간접 슈퍼클래스를 C 의 기본 클래스라고 합니다.그래서, NonEmpty의 기본 클래스는 IntSet과 Object 입니다. 상속(implementation)과 오버라이딩Empty 와 NonEmpty 클래스의 contains 과 incl의 정의는 IntSet 의 추상 함수를 구현합니다.또한 오버라이드를 사용하여 하위 클래스에서 기존 비추상 정의를 재정의할 수 있습니다. 123456789abstract class Base { def foo = 1 def bar: Int}class Sub extends Base { override def foo = 2 def bar = 3} 객체 정의IntSet 예제에서, 실제론 하나의 빈 IntSet만 존재한다고 할 수도 있습니다.그렇기 때문에 사용자가 많은 인스턴스를 만들도록 하는 것은 지나친 것 같습니다.우린 객체 정의로 이 경우를 개선할 수 있습니다: 1234object Empty extends IntSet { def contains(x: Int): Boolean = false def incl(x: Int): IntSet = new NonEmpty(x, Empty, Empty)} 위 코드는 Empty라는 싱클톤 객체를 정의합니다.다른 어떤 Empty 객체도 생성될 수 없습니다.싱글톤 객체는 값이기 때문에 Empty는 스스로 계산됩니다. 동적 바인딩스칼라를 포함한 OOP 언어에선 동적 메소드 디스패치를 구현합니다.이것은 메소드 호출에 의해 호출된 코드는 메소드를 포함하는 객체의 런타임 유형에 따라 다르다는 것을 의미합니다.추가 12Empty contains 1 shouldBe falsenew NonEmpty(7, Empty, Empty) contains 7 shouldBe true 메소드의 동적 디스패치는 고차함수의 호출과 비슷합니다.이 개념을 다른 개념으로 구현할 수 있습니까? 고차함수의 측면에서 객체? 객체 측면에서 고차함수? 트레잇스칼라에서, 클래스는 단 하나의 슈퍼클래스를 가질 수 있습니다.그러나 한 클래스가 몇 가지 슈퍼타입을 가지고 있거나 그로부터 코드를 상속받고자 하면 어떨까요?이때, 당신은 트레잇(trait)를 사용할 수 있습니다.트레잇은 추상클래스처럼 선언되며, trait 으로 선언합니다. 12345trait Planar { def height: Int def width: Int def surface = height * width} 클래스, 객체, 트레잇은 최대 하나의 클래스에서 상속 할 수 있지만 임의의 많은 트레잇이 있습니다: 1class Square extends Shape with Planar with Movable … 반면에, 트레잇은 값 파라미터를 가지지 않으며 클래스만 가질 수 있습니다. 스칼라의 클래스 계층 Top Type타입 계층 구조의 맨 위에는 다음이 있습니다. Any 모든 타입의 기본 타입 메소드: ==, !=, equals, hashCode, toString AnyRef 모든 참조 타입의 기본 타입 별칭 java.lang.Object AnyVal 모든 원시 타입의 기본 타입 Bottom TypeNothing은 스칼라의 타입 계층의 최하위에 있습니다. 그것은 다른 모든 타입의 하위 유형입니다.Nothing타입의 값은 없습니다.이걸 어디에 사용하나요? 비정상 종료 신호 빈 콜렉션 의 요소(element) 타입 Null Type모든 참조 클래스 타입은 또한 null을 값으로 갖고 있습니다.null 타입은 Null 입니다.Null은 Object에서 상속하는 모든 클래스의 하위 타입이며, AnyVal의 하위 타입과 호환되지 않습니다. 123val x = null // x: Nullval y: String = null // y: Stringval z: Int = null // error: type mismatch 읽어주셔서 감사합니다. 혹 글에 오역/추가할 내용이 있다면 코멘트 남겨주세요!🙆","categories":[{"name":"Scala","slug":"Scala","permalink":"https://sehajyang.github.io/categories/Scala/"}],"tags":[{"name":"Scala","slug":"Scala","permalink":"https://sehajyang.github.io/tags/Scala/"},{"name":"scala-exercises","slug":"scala-exercises","permalink":"https://sehajyang.github.io/tags/scala-exercises/"}]},{"title":"190722-190804 2주간 회고","slug":"190722-190804","date":"2019-08-05T07:09:32.000Z","updated":"2019-08-06T14:31:35.583Z","comments":true,"path":"2019/08/05/190722-190804/","link":"","permalink":"https://sehajyang.github.io/2019/08/05/190722-190804/","excerpt":"","text":"2주간 스칼라 공부를 하고, 개인 프로젝트를 했다.처음엔 날씨 정보를 알려주는 슬랙봇을 만들었으나, 개발팀의 반응이 좋아서 기능을 확장시켜 결국 너굴맨 프로젝트를 만들게 되었다! 너굴쟝.JPG 너굴맨은 가끔 까칠하다. 너굴맨 프로젝트의 아이디어는 9XD에 있는 item4 님의 yui에서 얻었다.Slacker를 이용해서 만들었는데, 부족한 기능이 많아서 라이브러리를 고치다 문득 이럴바엔 차라리 async로 만드는게 낫겠다는 생각이 들었다.yui가 비동기로 짜여져 있던데, 나도 시간이 나면 처음부터 저렇게 싹 만들고 싶다. 2주간 했던 학습 및 개발 Functional Programming in Scala 코세라 강의 Code Wars 스칼라 풀이 Scala Exercises 번역 Scala 학습마틴 오더스키 스칼라 코세라 강의를 듣던 중 깨달은건데, 강의 예제가 내가 번역하던 Scala Exercises 번역이라는 걸 깨달았다!.게다가, 스칼라 강의엔 한글 자막이 붙어있다. 이럴수가.. 내가 바퀴를 재발명 하고있었던걸까?다행히도 스칼라 강의에 붙어있는 한글 자막은 구글 번역기로 돌린듯한 퀄리티를 보여줬기 때문에 내 번역자료는 향상된 바퀴가 되었다.Programming in Scala 도 계속해서 보고있다. 개인적으론, 강의보단 책의 내용이 좀 더 자세하며 좋은 것 같다.(그리고 많다) 스칼라는 어렵기 때문에 생산성에 대한 의문이 있다. 주위에선 왜 스칼라를 하냐 코틀린을 하지 라는 반응을 보이기도 했다.그렇지만 멀티 프로세싱이 중요해진 요즘 시대에 (꽤)순수한 함수형 언어는 꼭 배워야 하며, 그렇게 새로운 패러다임을 배움으로써 시야를 확장해 나가는 것이 중요하다고 생각하기 때문에 어렵지만 여차저차 공부하고있다.누군가, 그럴거면 하스켈을 하지 라는 말을 할지도 모르겠다. 하지만 하스켈을 실무에서 쓰기엔 그닥 이라고 생각한다. 다음 주부터는 지인과 매주 주말마다 스칼라 스터디를 하기로 했다. 책은 당연히 Programming in Scala 이다.라스칼라 코딩단에서 팀원을 모아볼까 했지만 왠지 참가하는 사람이 적을 것 같은 느낌적인 느낌(왠지 고수분들만 있는것같은)이 들어서 지인과 하기로 결정됐다.지금껏 많은 스터디를 참여하기도, 열기도 했지만 꾸준히 파토나지 않고 유지해나가는게 정말 어려운 것 같다.발표하는 방식의 스터디가 가장 좋았던 것 같아, 한 주 동안 1~2강을 학습하고 주말에 해당 내용을 발표 및 토의, 질문, 문제풀이의 시간을 가질 예정이다! Code Wars는 부끄럽게도 너굴맨 프로젝트를 하느라 몇 문제 못 풀었다.Scala Exercises 번역은 회사일이 바빠 속도가 느려졌지만 계속해서 하고있긴하다. 다음주 목표 Functional Programming in Scala 코세라 강의 3Week 까지 Code Wars 스칼라 풀이 Scala Exercises 번역 너굴맨 슬랙봇 개발 총평2주간 스칼라 강의를 듣고 책을 봤다. 너굴맨 프로젝트를 하느라(이게 생각보다 재밌었다) 스칼라 코드를 짜는 횟수는 좀 적었다..책은 반정도 봤다. 다음주에는 좀 더 코드를 짜는것에 집중해야겠다. 다음 주부터 시작하는 지인과 함께하는 스칼라 스터디는 정말 기대된다!","categories":[{"name":"Logs","slug":"Logs","permalink":"https://sehajyang.github.io/categories/Logs/"}],"tags":[{"name":"weekly","slug":"weekly","permalink":"https://sehajyang.github.io/tags/weekly/"}]},{"title":"190708-190721 2주간 회고","slug":"190708-190721","date":"2019-07-23T00:55:56.000Z","updated":"2019-08-02T14:41:53.794Z","comments":true,"path":"2019/07/23/190708-190721/","link":"","permalink":"https://sehajyang.github.io/2019/07/23/190708-190721/","excerpt":"","text":"2주간 스칼라공부를 많이 했다. 스칼라는 무슨말을 하는지 뭔가 머리론 알겠는데 막상 사용하려면 손이 안떨어지는 느낌이다.아직도 객체가 불변하다는것과 파라미터로 함수를 넘긴다는게 내겐 너무 낯설다.사람의 머리는 재귀에 가깝다고 한다 하지만 나는 너무 for loop에 익숙해져 있어서 그런지 재귀적인 사고가 잘 되지 않는 것 같다.그래도 최대한 var 나 for loop를 사용하지 않으려 노력하고 있다💦스칼라 문법에 빨리 익숙해지기 위해 스칼라로 프로젝트 오일러를 몇 문제 풀어보기도 하고, Scala Exercises 를 풀거나 번역을 했는데,가장 좋은 방법은 단언 Code Wars 문제를 푸는 것 이었다. 2주간 했던 학습 및 개발 Functional Programming in Scala 코세라 강의 Code Wars 스칼라 풀이 프로젝트 오일러 스칼라 풀이 Scala Exercises 번역 Functional Programming in Scala 코세라 강의스칼라 언어를 만든 마틴 오더스키 교수님이 만든 강좌로 수강을 시작했다.지인과 같이 이 강의로 스칼라 스터디를 하고있는데 내용이 차근차근 하며 어렵지 않아서 잘 듣고 있다.OOP언어만 알던 나에게 스칼라는 너무 신선해서 강의는 그야말로 놀라움의 연속이다. 덕분에 강의를 듣는 내내 지루할 틈이 없다ㅎㅎ Code Wars 스칼라 풀이처음엔 백준문제를 풀려고 했지만 어떠한 이유에서인지 백준은 스칼라를 지원하지 않았다. 그래서 대안으로 Code Wars를 선택했다.Code Wars는 지원하는 언어도 다양하고 난이도가 나뉘어있어 수준에 맞는(?) 문제를 풀 수 있다.또한 테스트 케이스를 작성해주며 문제 제출 시 오류가 난 테스트를 상세히 알려준다.제출한 코드가 통과되면 타인이 작성한 코드 및 가장 많은 추천을 받은 릿코드를 볼 수 있다.언어별로 있는 난이도는 기초, 랭크 업, 반복 연습, 랜덤 등인데 기초 난이도는 스칼라 문법 연습으로 괜찮았다!.스칼라 문법 연습은 앞으로 계속 Code Wars로 해야겠다. 프로젝트 오일러 스칼라 풀이자바로 공개되어있는 프로젝트 오일러 문제를 스칼라로 포팅하는 식으로 몇 문제 진행했었는데, 스칼라 연습이 안되는 것 같아 금방 접었다.그리고 공개된 소스를 스칼라로 포팅하는건 왠지 지루했다. Scala Exercises 번역Scala Exercises 번역을 벌써 다섯개나 했다! 앞으로 4개정도 남은 것 같다.번역을 하면서 Scala Exercises 설명은 굉장히 대충이라는 느낌을 받았다. 대략 내가 대충 말하면 너가 잘 알아들어~ 라는 느낌이었다.FP를 좀 아는 사람이 보기 좋은 사이트이며 스칼라 입문용으로 보기엔 별로인 것 같다. 그야말로 Exercises란 이름에 낚였다.덕분에 추가설명을 다느라 애먹고 있다. 물론 번역엔 추가설명을 붙였기 때문에 이젠 초보자도 나름 볼 수 있는 자료가 되었다 😁 😁번역하며 가장 어려웠던 점은 전문 용어를 한글로 번역하는게 너무 어렵다는 것 이다.예를들어 Option value 를 보자면, 이걸 옵션 값 으로 해야할지 선택적 값 으로 해야할지 옵션벨류로 해야 할지를 선택해야 한다.조금 과장하자면 이런 문제가 거의 매 줄 매 단략마다 일어났다.앞으로 4개정도 남았다. 슬프게도 봐주는 사람이 지금은 없지만.. 언젠가 스칼라 뉴비에게 도움이 되는 자료가 된다면 좋겠다.. 다음주 목표 Functional Programming in Scala 코세라 강의 Code Wars 스칼라 풀이 Scala Exercises 번역 총평내가 목표한 학습량엔 못미쳐 좀 아쉬웠다.특히, 인터넷에서 얻는 정보로는 어느정도 한계가 있어 책을 봤어야 했는데 책을 조금밖에 못봐서 아쉬웠다.다음 2주간도 지난주와 마찬가지로 스칼라 공부를 할 예정이다. 책, 강의, CodeWars 풀이에 중점을 두고 시간날때 간간히 번역을 해야겠다.언젠가 스칼라에 좀 익숙해지고 좀 알 것 같아지면 매주마다 하는 라스칼라 스터디에도 참여해보고싶다.","categories":[{"name":"Logs","slug":"Logs","permalink":"https://sehajyang.github.io/categories/Logs/"}],"tags":[{"name":"weekly","slug":"weekly","permalink":"https://sehajyang.github.io/tags/weekly/"}]},{"title":"스칼라 번역- 편리한 문법들 (Syntactic Conveniences)","slug":"syntactic-conveniences","date":"2019-07-18T12:47:06.000Z","updated":"2021-02-09T15:14:45.567Z","comments":true,"path":"2019/07/18/syntactic-conveniences/","link":"","permalink":"https://sehajyang.github.io/2019/07/18/syntactic-conveniences/","excerpt":"","text":"이 포스팅은 [scala-exercises 번역 시리즈]로 scala-exercises 사이트의 스칼라 튜토리얼을 공부하며 번역한 문서 입니다.scala-exercises 는 스칼라 창시자인 마틴 오더스키 강의의 강의자료입니다.따라서 강의를 들으며 본 문서를 같이 보는것을 추천합니다.의역이 많습니다. 오역 및 오타 등은 코멘트로 알려주세요 😄원문 : [scala-exercises syntactic_conveniences] 편리한 문법들(SYNTACTIC CONVENIENCES)이 섹션에선 언어가 지원하는 몇가지 문법적 설탕에 대해 소개합니다. 문자열 인터폴레이션(INTERPOLATION)런타임에서 String 에 값을 붙일 시 문자열 인터폴레이션을 사용할 수 있습니다: 12345def greet(name: String): String = s\"Hello, $name!\"greet(\"Scala\") shouldBe \"Hello, Scala!\"greet(\"Functional Programming\") shouldBe \"Hello, Functional Programming!\" 문자열 리터럴 접미사로 s를 붙이면 $으로 동적값을 그 안에서 사용할 수 있습니다.만약 복잡한 식을 연결할시엔 중괄호로 둘러쌉니다. 1234def greet(name: String): String = s\"Hello, ${name.toUpperCase}!\"greet(\"Scala\") shouldBe \"Hello, SCALA!\" 튜플우리는 이전 섹션들을 통해 케이스 클래스는 정보를 모으는데에 유용하다는 것을 알게되었습니다.그러나 때로는 완전한 케이스 클래스를 정의할 필요 없이 정보를 모을 수 있습니다. 튜플로 말이죠 1234def pair(i: Int, s: String): (Int, String) = (i, s)pair(42, \"foo\") shouldBe (42, \"foo\")pair(0, \"bar\") shouldBe (0, \"bar\") 위 예제에서의 타입은 (Int, String)로 첫번째 요소(element)의 타입은 Int 두번째 요소는 String 입니다.비슷하게, (i, s) 쌍의 첫번째 요소는 i, 두번째 요소는 s 입니다.일반적으로, (T1, …, Tn)의 타입은 i번째 요소는 Ti 타입을 가진, n개의 요소가 있는 튜플입니다.그리고 값은 n개 요소 (t1, …, tn)의 튜플 값 입니다. (역자추가) 튜플의 각 요소들은 타입이 각자 다를 수 있습니다. ("a",1,'b') 튜플의 타입은 Tuple[String,Int,Char] 입니다.즉, 튜플의 타입은 요소의 개수와 각각의 타입에 따라 달라집니다. [출처] 튜플 조작하기튜플 패턴을 사용해 튜플의 요소를 검색할 수 있습니다. 1234567val is: (Int, String) = (42, \"foo\")is match { case (i, s) => i shouldBe 42 s shouldBe \"foo\"} 또는 심플하게 다음과 같이 작성할 수 있습니다: 12345val is: (Int, String) = (42, \"foo\")val (i, s) = isi shouldBe 42s shouldBe \"foo\" 또는 _1멤버로 첫번째 요소를, _2멤버로 두번째 요소를 검색할 수 있습니다: 123val is: (Int, String) = (42, \"foo\")is._1 shouldBe 42is._2 shouldBe \"foo\" 객체로서의 함수우리는 스칼라의 넘버릭 타입들과 Boolean 타입이 일반 클래스처럼 상속될 수 있음을 보았습니다.그러나 함수는 어떨까요?실제로 스칼라에서 함수의 값은 객체로 다뤄집니다.타입이 A = B 인 함수는 사실 scala.Function1[A, B] 가 생략된 것 이며 다음과 같이 정의됩니다: 1234package scalatrait Function1[A, B] { def apply(x: A): B} 그래서, 함수는 apply 메소드를 가지고있는 객체입니다.또한 Function2, Function3… , 등 더 많은 매개변수를 취하는 함수(튜플..최대 22개)가 있습니다. 함수값의 확장아래의 익명함수는: 1(x: Int) => x * x 다음과 같이 확장됩니다. 123456{ class AnonFun extends Function1[Int, Int] { def apply(x: Int) = x * x } new AnonFun} 또는 익명 클래스 문법을 사용해 짧아집니다. 123new Function1[Int, Int] { def apply(x: Int) = x * x} 함수호출의 확장f(a, b) (f는 일부 클래스 타입의 값) 함수의 호출은 다음과 같이 확장됩니다. 1f.apply(a, b) 그래서 객체지향(OO)으로 변환하면 12val f = (x: Int) => x * xf(7) 아래와 같을 것 입니다: 1234val f = new Function1[Int, Int] { def apply(x: Int) = x * x}f.apply(7) 함수와 메소드다음과 같은 메소드 자체는 함수 값이 아닙니다. 1def f(x: Int): Boolean = … 그러나 만약 함수 유형이 예상되는 곳에 f 가 사용되면, 자동으로 함수값으로 변환됩니다. 1(x: Int) => f(x) FOR 표현표준 라이브러리의 여러 데이터 타입은 map, flatMap, filter라는 메소드를 갖고있음을 알 수 있습니다.이 메소드들이 실제로 사용되는 경우가 많기 때문에 스칼라는 표현식에 대한 전용 문법을 지원합니다: map 대신: 1xs.map(x => x + 1) 다음과 같이 작성할 수 있습니다: 1for (x <- xs) yield x + 1 그리고 “xs의 모든 요소 x에 x+1 하고 리턴합니다”라고 읽습니다. (역자추가) xs의 요소들에 대해 x 라고 명명하며 xs를 순회하며 x+1 을 하고, 그 결과를 새로운 리스트로 리턴합니다. filter 대신: 1xs.filter(x => x % 2 == 0) 다음과 같이 작성할 수 있습니다: 1for (x <- xs if x % 2 == 0) yield x 이 문법의 이점은 이전 문법과 같이 보면 더욱 분명해집니다(가독성이 향상되었습니다): 1234for (x <- xs if x % 2 == 0) yield x + 1// Equivalent to the following:xs.filter(x => x % 2 == 0).map(x => x + 1) 마지막으로 flatMap 대신: 1xs.flatMap(x => ys.map(y => (x, y))) 다음과 같이 작성할 수 있습니다: 1for (x <- xs; y <- ys) yield (x, y) 그리고 “xs의 모든 요소 x 와 ys의 모든 요소y를 (x,y)하고 (그 결과를 새로운 리스트로) 리턴합니다” 라고 읽습니다. 한꺼번에 값 넣기다음은 한꺼번에 값을 넣는 예제입니다: 1234for { x <- xs if x % 2 == 0 y <- ys} yield (x, y) 문법적 설탕을 해제한 코드는 이렇습니다: 1234567xs.filter { x => x % 2 == 0}.flatMap { x => ys.map { y => (x, y) }} 메소드의 파라미터명명된 파라미터때때로 함수에 전달된 몇몇 파라미터의 의미가 무엇인지 파악하기 어려울 수 있습니다.다음 예제를보며 생각해봅시다: 1Range(1, 10, 2) 이것은 무슨 뜻 일까요? 명명된 파라미터(named parameter)를 사용해 읽기 쉽게 만들 수 있습니다.사실 위의 코드에서 Range 는 다음과 같이 정의되어 있습니다: 1case class Range(start: Int, end: Int, step: Int) 그리고 다음과 재작성 할 수 있습니다: 1Range(start = 1, end = 10, step = 2) 이제 위 코드는 1 부터 10까지 2씩 증가시킨다 는 정의를 했음이 명확해졌습니다. 기본 값메소드의 파라미터는 기본값을 가질 수 있습니다.Range를 재정의 해 봅시다: 1case class Range(start: Int, end: Int, step: Int = 1) 위 코드에서, step 파라미터는 기본값으로 1을 가집니다.그 뒤, step 파라미터를 생략할 수 있으며, 생략할 시 컴파일러는 해당 파라미터의 기본값으로 지정한 값을 사용하게 됩니다. 12345case class Range(start: Int, end: Int, step: Int = 1)val xs = Range(start = 1, end = 10)xs.step shouldBe 1 반복된 파라미터다음과 같이 임의의 수의 파라미터(동일한 타입의)를 받을 수 있는 함수를 정의할 수 있습니다: 123456def average(x: Int, xs: Int*): Double = (x :: xs.to[List]).sum.toDouble / (xs.size + 1)average(1) shouldBe 1.0average(1, 2) shouldBe 1.5average(1, 2, 3) shouldBe 2 average 함수는 최소한 하나의 Int 파라미터와 임의의 수의 파라미터의 값들을 가져와 평균을 계산합니다.또한, 사용자가 적어도 하나의 파라미터를 제공하도록 함으로써 빈 숫자 리스트의 평균을 계산할 수 없도록 만듭니다.때로는 리스트의 각 요소를 많은 파라미터로 제공하려면, : _*를 추가합니다: 12val xs: List[Int] = …average(1, xs: _*) 타입 엘리어스(TYPE ALIASES) 비슷하게, 타입 표현식(type expressions) 으로 표현식에 의미있는 이름을 줄 수 있습니다. 1234567type Result = Either[String, (Int, Int)]def divide(dividend: Int, divisor: Int): Result = if (divisor == 0) Left(\"Division by zero\") else Right((dividend / divisor, dividend % divisor))divide(6, 4) shouldBe Right((1, 2))divide(2, 0) shouldBe Left(\"Division by zero\")divide(8, 4) shouldBe Right((2,0)) 읽어주셔서 감사합니다. 혹 글에 오역/추가할 내용이 있다면 코멘트 남겨주세요!🙆","categories":[{"name":"Scala","slug":"Scala","permalink":"https://sehajyang.github.io/categories/Scala/"}],"tags":[{"name":"Scala","slug":"Scala","permalink":"https://sehajyang.github.io/tags/Scala/"},{"name":"scala-exercises","slug":"scala-exercises","permalink":"https://sehajyang.github.io/tags/scala-exercises/"}]},{"title":"스칼라 번역- 표준 라이브러리 (Standard Library)","slug":"standard-library","date":"2019-07-16T00:00:00.000Z","updated":"2021-02-09T15:14:45.566Z","comments":true,"path":"2019/07/16/standard-library/","link":"","permalink":"https://sehajyang.github.io/2019/07/16/standard-library/","excerpt":"","text":"이 포스팅은 [scala-exercises 번역 시리즈]로 scala-exercises 사이트의 스칼라 튜토리얼을 공부하며 번역한 문서 입니다.scala-exercises 는 스칼라 창시자인 마틴 오더스키 강의의 강의자료입니다.따라서 강의를 들으며 본 문서를 같이 보는것을 추천합니다.의역이 많습니다. 오역 및 오타 등은 코멘트로 알려주세요 😄원문 : [scala tutorial higher order functions] 표준 라이브러리 (STANDARD LIBRARY)LIST함수형 프로그림에서 리스트는 기본적인 데이터 구조입니다.x1, ..., xn 요소(element)를 가지고 있는 리스트는 List(x1, ..., xn) 로 작성되어집니다. 1234val fruit = List(apples, oranges, pears)val nums = List(1, 2, 3, 4)val diag3 = List(List(1, 0, 0), List(0, 1, 0), List(0, 0, 1))val empty = List() 리스트는 불변입니다 — 리스트의 요소들은 변경될 수 없습니다. 리스트는 재귀적입니다(다음 섹션에서 볼 수 있습니다) 리스트는 동질적(homogeneous) 입니다: 리스트의 요소들은 반드시 같은 타입이어야 합니다. 요소(element)들의 타입이 T인 리스트는 List[T]로 작성되어집니다: 1234val fruit: List[String] = List(apples, oranges, pears)val nums: List[Int] = List(1, 2, 3, 4)val diag3: List[List[Int]] = List(List(1, 0, 0), List(0, 1, 0), List(0, 0, 1))val empty: List[Nothing] = List() 리스트의 생성자사실 스칼라의 모든 리스트는 이렇게 구성되어집니다: Nil (빈 리스트) :: 메소드: x::xs는 첫번째 요소(x)에 새 리스트를 지정하고, 그 뒤에 xs 목록(리스트 목록 자체)이 뒤따릅니다. 123val fruit = apples :: (oranges :: (pears :: Nil))val nums = 1 :: (2 :: (3 :: (4 :: Nil)))val empty = Nil 오른쪽과의 연관성규칙 : : 로 끝나는 작업은 오른쪽과 연결됩니다. 따라서 A :: B :: C 는 A :: (B :: C)라고 해석됩니다.그러나 다음처럼 괄호를 생략할 수 있습니다. 1val nums = 1 :: 2 :: 3 :: 4 :: Nil 하지만 :로 끝나는 작업은 오른쪽 피연산자의 메소드 호출과는 다릅니다. (역: 1이 2 요소를 호출하진 않습니다 라는 뜻 입니다)사실 위 표현식은 다음과 같습니다. 1val nums = Nil.::(4).::(3).::(2).::(1) (역자추가) 왜 이런일이 일어났냐면, 스칼라에서 이름이 콜론(:)으로 끝나는 메소드는 오른쪽 피연산자의 것으로 호출하기 때문입니다. Nil가 왜 있냐면 :: 메소드가 리스트 클래스의 멤버이기 때문입니다.만약 1::2::3 이라고 하면 마지막 3이 Int 형이라서 ::메소드가 없기 때문에 리스트로 인식이 안됩니다.1::2::3 는 Nil.(3).::(2).::(1)라는 뜻이기 때문이죠.마지막 요소에 Nil을 넣어주면 Nil은 리스트의 멤버이기 때문에 타입을 추론해 리스트로 만들어 줍니다. [출처] 리스트 조작패턴 매칭으로 리스트를 분해(decompose) 할 수 있습니다. Nil: Nil은 고정값 입니다. p :: ps : 리스트의 패턴인 head 는 p와 tail은 ps 과 매칭됩니다. 123456789101112nums match { // 1 그리고 2로 시작하는 Int 리스트 case 1 :: 2 :: xs => … // 리스트의 길이 1 case x :: Nil => … // `x :: Nil`과 같습니다 case List(x) => … // 빈 리스트는 `Nil` 과 같습니다 case List() => // 2로 시작하는 또 다른 리스트를 요소로 포함하는 리스트 case List(2 :: xs) => …} 연습 : 리스트 정렬리스트의 숫자들을 오름차순으로 정렬해야 된다고 가정해봅시다:리스트를 정렬하기 위한 방법 중 중 한가지 방법으로 해보겠습니다. List(7, 3, 9, 2) 리스트를 정렬하려면 우선 List(2, 3, 9)를 얻기위해 tail 인 List(3, 9, 2) 를 정렬합니다. 그 다음 head 인 7을 올바른 자리에 삽입해 List(2, 3, 7, 9)를 얻습니다. 이 아이디어를 삽입 정렬(Insertion Sort) 이라고 합니다. 1234def insertionSort(xs: List[Int]): List[Int] = xs match { case List() => List() case y :: ys => insert(y, insertionSort(ys))} 12345678910111213val cond: (Int, Int) => Boolean = (x, y) => x < ydef insert(x: Int, xs: List[Int]): List[Int] = xs match { case List() => x :: Nil case y :: ys => if (cond(x, y)) x :: y :: ys else y :: insert(x, ys) }insert(2, 1 :: 3 :: Nil) shouldBe (1 :: 2 :: 3 :: Nil)insert(1, 2 :: 3 :: Nil) shouldBe (1 :: 2 :: 3 :: Nil)insert(3, 1 :: 2 :: Nil) shouldBe (1 :: 2 :: 3 :: Nil) 리스트에 대한 일반적인 작업(Common Operations)map을 사용해 요소를 바꿉니다. 1List(1, 2, 3).map(x => x + 1) == List(2, 3, 4) filter를 사용해 요소를 조건에 맞게 걸러냅니다. 1List(1, 2, 3).filter(x => x % 2 == 0) == List(2) 리스트 안의 각 요소들을 변환 후 리스트에 담고, flatMap을 사용해 결과를 단일 리스트로 만듭니다. 12345val xs = List(1, 2, 3).flatMap { x => List(x, 2 * x, 3 * x) }xs == List(1, 2, 3, 2, 4, 6, 3, 6, 9) 옵션 값(Option Values) Option[A]로 A 타입의 옵션 값(Option Values)을 표현할 수 있습니다.이것은 부분적으로 정의된 함수 구현시 유용합니다. 12// The `sqrt` function is not defined for negative valuesdef sqrt(x: Double): Option[Double] = … Option[A]는 None(값이 없음) 혹은 Some[A](값이 있음)이 될 수 있습니다. 12def sqrt(x: Double): Option[Double] = if (x < 0) None else Some(…) 옵션 조작(Manipulating Options)패턴 매칭으로 리스트를 분해(decompose) 할 수 있습니다: 12345def foo(x: Double): String = sqrt(x) match { case None => no result case Some(y) => y.toString } 옵션에 대한 일반적인 작업map을 사용해 요소를 바꿉니다. 12Some(1).map(x => x + 1) shouldBe Some(2)None.map((x: Int) => x + 1) shouldBe None filter를 사용해 요소를 조건에 맞게 걸러냅니다. 12Some(1).filter(x => x % 2 == 0) shouldBe NoneSome(2).filter(x => x % 2 == 0) shouldBe Some(2) flatMap으로 값을 옵션 값(Option value)으로 변환합니다. 12Some(1).flatMap(x => Some(x + 1)) shouldBe Some(2)None.flatMap((x: Int) => Some(x + 1)) shouldBe None 에러 핸들링이 서브섹션은 오류를 핸들링하는데에 유용한 타입들을 소개합니다. TryTry[A]는 A 를 리턴하려고 시도한 계산을 표현합니다. 이것은 Success[A] 과 Failure 중 하나 입니다.None과 Failure사이엔 중요한 차이점이 있는데, Failure는 실패에 대한 이유를 알려줍니다. 123def sqrt(x: Double): Try[Double] = if (x < 0) Failure(new IllegalArgumentException(x must be positive)) else Success(…) Try[A] 값 조작하기Options 와 리스트처럼, Try[A]는 대수적인 데이터 타입입니다.따라서 패턴 매칭으로 리스트를 분해(decompose) 할 수 있습니다.또한 Try[A]는 map, filter, flatMap 을 가지고 있습니다.따라서 실행중 발생한 오류는 Failure 로 변환된다는 점을 제외하면, 마치 Option[A] 처럼 동작합니다. EitherEither또한 예외 처리하는데에 유용하며, 기본적으로 타입 Either[A, B]는 A 혹은 B 타입 일 수 있는 값을 나타냅니다.이것은 Left 혹은 Right라는 두가지 경우로 나뉘어집니다.한가지 경우는 Failure를 나타내고 다른 하나는 SUCCESS를 나타낼 수 있습니다.한가지 차이점은, Try는 Throwable 이 아닌 다른 타입을 선택해 예외를 나타낼 수 있습니다.또 다른 차이점은 Either값을 변환할 때 발생하는 예외는 Failure 로 변환되지 않는다는 점 입니다. 123def sqrt(x: Double): Either[String, Double] = if (x < 0) Left(x must be positive) else Right(…) Either[A, B] 값 조작스칼라 2.12 이후로 Either 는 map과 flatMap을 갖게 되었습니다. 이 메소드들은 Right 케이스로만 변환됩니다.따라서 Either는 우편향(right biased) 라고 할 수 있습니다. (Right 로만 가기 때문이죠) 12Right(1).map((x: Int) => x + 1) shouldBe Right(2)Left(foo).map((x: Int) => x + 1) shouldBe Left(foo) 또한 Either 는 filterOrElse 메소드도 갖고 있습니다.이 메소드는 만약 Right값이 predicate(술어) 를 만족하지 못하는 경우 Left로 만들어줍니다.(역 : 여기서 predicate 는 (A) ⇒ B 같은 것을 의미합니다. [참고]) 1Right(1).filterOrElse(x => x % 2 == 0, Odd value) shouldBe Left(Odd value) 그러나 스칼라 2.12 이전에는, Either는 편향되지 않았습니다(unbiased).무슨 뜻이냐면, 스칼라 2.12 이전엔 map 사용시 Side(Right or Left)를 명시적으로 지정해야 했습니다. 1234567def triple(x: Int): Int = 3 * xdef tripleEither(x: Either[String, Int]): Either[String, Int] = x.right.map(triple) tripleEither(Right(1)) shouldBe Right(3)tripleEither(Left(not a number)) shouldBe Left(not a number) 읽어주셔서 감사합니다. 혹 글에 오역/추가할 내용이 있다면 코멘트 남겨주세요!🙆 같이 보면 좋은 포스팅 HAMA 블로그 | 스칼라 강좌 (3) - List HAMA 블로그 | 스칼라 강좌 (21) - Option 과 Either","categories":[{"name":"Scala","slug":"Scala","permalink":"https://sehajyang.github.io/categories/Scala/"}],"tags":[{"name":"Scala","slug":"Scala","permalink":"https://sehajyang.github.io/tags/Scala/"},{"name":"scala-exercises","slug":"scala-exercises","permalink":"https://sehajyang.github.io/tags/scala-exercises/"}]},{"title":"스칼라 번역- 꼬리재귀 (Tail Recursion)","slug":"tail-recursion","date":"2019-07-11T05:07:42.000Z","updated":"2021-02-09T15:14:45.568Z","comments":true,"path":"2019/07/11/tail-recursion/","link":"","permalink":"https://sehajyang.github.io/2019/07/11/tail-recursion/","excerpt":"","text":"이 포스팅은 [scala-exercises 번역 시리즈]로 scala-exercises 사이트의 스칼라 튜토리얼을 공부하며 번역한 문서 입니다.scala-exercises 는 스칼라 창시자인 마틴 오더스키 강의의 강의자료입니다.따라서 강의를 들으며 본 문서를 같이 보는것을 추천합니다.의역이 많습니다. 오역 및 오타 등은 코멘트로 알려주세요 😄원문 : [scala-exercises tail_recursion] 꼬리 재귀(Tail Recurstion)재귀 함수 응용프로그램두개의 재귀 메소드의 실행과정(evaluation step) 을 비교해 보겠습니다.먼저 두 수의 최대공약수를 계산하는 gcd 메소드를 생각해봅시다.다음의 gcd 는 유클리드 알고리즘을 사용해 구현되었습니다. 12def gcd(a: Int, b: Int): Int = if (b == 0) a else gcd(b, a % b) gcd(14, 21) 는 다음의 실행과정을 거칩니다. 12345678910111213gcd(14, 21)if (21 == 0) 14 else gcd(21, 14 % 21)if (false) 14 else gcd(21, 14 % 21)gcd(21, 14 % 21)gcd(21, 14)if (14 == 0) 21 else gcd(14, 21 % 14)if (false) 21 else gcd(14, 21 % 14)gcd(14, 7)gcd(7, 14 % 7)gcd(7, 0)if (0 == 0) 7 else gcd(0, 7 % 0)if (true) 7 else gcd(0, 7 % 0)7 factorial 을 생각해봅시다: 12def factorial(n: Int): Int = if (n == 0) 1 else n * factorial(n - 1) factorial(4)는 다음의 실행과정을 거칩니다. 12345678factorial(4)if (4 == 0) 1 else 4 * factorial(4 - 1)4 * factorial(3)4 * (3 * factorial(2))4 * (3 * (2 * factorial(1)))4 * (3 * (2 * (1 * factorial(0)))4 * (3 * (2 * (1 * 1)))24 이 두 시퀀스는 뭐가 다른걸까요?가장 중요한 차이점은 gcd 경우 시퀀스가 본질적으로 감소하며 변합니다.(gcd(21, 14 % 21) 가 gcd(14, 7) 처럼 점점 줄어듭니다)그렇게 gcd의 하나의 호출에서 다음 호출로 넘어가며 결국엔 종료됩니다.그리고 그 중간단계들 에는 if then elses 같은 표현식이 있습니다.어쨌든 항상 우리가 최초 호출한 모양인 gcd(a,b) 로 돌아옵니다. 반면에 factorial 에선, 하나의 요소를 매 단계마다 추가한다는 것을 알 수 있습니다.(4 * factorial(3) 에서 4 * (3 * factorial(2))으로 3 * 요소가 추가 된 것 처럼요)즉, 최종 값으로 줄어들 때 까지 표현식은 점점 커집니다. 꼬리 재귀(Tail Recursion)재활용(rewriting) 규칙의 차이점은 컴퓨터의 실제 실행의 직접적인 변화로 이어질 수 있습니다(데이터를 다시 만들거나 하지 않고 재 활용 합니다)사실, 마지막 동작으로 자신을 호출하는 재귀함수가 있는 경우 해당 스택 프레임을 재사용할 수 있습니다.이것을 꼬리 재귀 라고 부릅니다. 그리고 이 트릭을 적용함으로써, 꼬리 재귀함수는 불변의 스택 영역에서 실행될 수 있습니다. 따라서 이건 단순히 반복적인 프로세스(iterative process)와는 다른 방법입니다.꼬리 재귀함수는 루프의 함수형 이며 루프처럼 효율적으로 실행됩니다. 다시 살펴보면, gdc의 else 부분에서 gcd의 마지막 동작으로 자신을 호출한다는 것을 알 수 있습니다.그리고 이것은 본질적으로 크기가 불변인 재활용 시퀀스(rewriting sequence)로 변환되며,이는 컴퓨터에서 실제 실행 시 불변의 공간에서 실행할 수 있는 꼬리재귀 호출로 변환됩니다. 반면에, factorial 을 보면 factorial(n - 1)이 호출 된 후에도 여전히 작업이 있습니다.다시말해서, 호출의 결과에 대해 n을 곱해야 한다는 걸 알 수 있습니다.따라서 재귀호출은 꼬래 재귀호출이 아니라는게 단계가 진행 되어지며 호출이 감소하지 않는 것(오히려 늘어나는 것) 에서 분명해집니다.최종 값을 계산하기 전 까지 실제 유지해야 하는 중간값들이 쌓여있는것을 볼 수 있습니다.그러므로 factorial은 재귀 함수가 아닙니다. factorial과 gdc는 단지 자기 자신을 호출하지만, 일반적으로 함수는 다른 함수를 호출할 수 있습니다.꼬리재귀는 만약 함수의 마지막 동작으로 다른 함수를 호출하는 경우 스택프레임을 두 함수 모두에 재사용 할 수 있습니다.이러한 호출을 꼬리 호출(tail calls) 이라고 합니다. 스칼라에서의 꼬리재귀스칼라에서 현재 함수에 대한 직접 재귀 호출(directly recursive calls) 만 최적화됩니다.@tailrec 어노테이션을 사용해 꼬리재귀함수로 만들 수 있습니다. 12@tailrecdef gcd(a: Int, b: Int): Int = … 만약 @tailrec 어노테이션을 사용했지만 gcd가 꼬리재귀가 아닌경우 오류가 발생합니다. (역자추가) JVM은 보안상의 이유로 꼬리재귀를 지원하지 않기 때문에스칼라에서의 꼬리재귀는 컴파일러가 스택 하나만 사용해 재귀호출을 할 수 있도록 지원하고 있습니다.때문에 직접 호출하는 재귀호출 만 최적화가 가능하며 간접적으로 재귀호출이 일어나는 경우는 최적화 하지 못합니다.[참고] 읽어주셔서 감사합니다. 혹 글에 오역/추가할 내용이 있다면 코멘트 남겨주세요!🙆 같이보면 좋은 포스팅 Outsider’s Dev Story | Scala의 Tail Recursion 간단 예제","categories":[{"name":"Scala","slug":"Scala","permalink":"https://sehajyang.github.io/categories/Scala/"}],"tags":[{"name":"Scala","slug":"Scala","permalink":"https://sehajyang.github.io/tags/Scala/"},{"name":"scala-exercises","slug":"scala-exercises","permalink":"https://sehajyang.github.io/tags/scala-exercises/"}]},{"title":"스칼라 번역- 유효범위 (Lexical Scopes)","slug":"lexical-scope","date":"2019-07-11T04:04:44.000Z","updated":"2021-02-09T15:14:45.564Z","comments":true,"path":"2019/07/11/lexical-scope/","link":"","permalink":"https://sehajyang.github.io/2019/07/11/lexical-scope/","excerpt":"","text":"이 포스팅은 [scala-exercises 번역 시리즈]로 scala-exercises 사이트의 스칼라 튜토리얼을 공부하며 번역한 문서 입니다.scala-exercises 는 스칼라 창시자인 마틴 오더스키 강의의 강의자료입니다.따라서 강의를 들으며 본 문서를 같이 보는것을 추천합니다.의역이 많습니다. 오역 및 오타 등은 코멘트로 알려주세요 😄원문 : [scala tutorial lexical scopes] 유효범위(Lexical Scopes)중첩 함수작업을 여러 작은 함수로 분리하는 것은 좋은 함수형 프로그래밍 스타일입니다.그러나 sqrtIter, improve, isGoodEnough 같은 함수는 sqrt 의 구현만을 위한 것이지 사용되기 위한 것은 아닙니다.일반적으로 우리는 사용자가 저런 함수에 직접적으로 접근하는 것을 원하지 않습니다.이것을 해결하려면 sqrt안에 보조함수를 두어 이름 공간 오염(name-space pollution) 을 피할 수 있습니다.즉, 이렇게 따로 있던 함수들을 : 1234567891011def sqrtIter(guess: Double, x: Double): Double = if (isGoodEnough(guess, x)) guess else sqrtIter(improve(guess, x), x) def improve(guess: Double, x: Double) = (guess + x / guess) / 2def isGoodEnough(guess: Double, x: Double) = abs(guess * guess - x) < 0.001 def sqrt(x: Double) = sqrtIter(1.0, x) 이렇게 말이죠: 12345678910111213def sqrt(x: Double) = { def sqrtIter(guess: Double, x: Double): Double = if (isGoodEnough(guess, x)) guess else sqrtIter(improve(guess, x), x) def improve(guess: Double, x: Double) = (guess + x / guess) / 2 def isGoodEnough(guess: Double, x: Double) = abs(square(guess) - x) < 0.001 sqrtIter(1.0, x)} 스칼라의 블록스칼라의 블록은 중괄호로 구분됩니다. 1234{ val x = f(3) x * x} 여기에는 일련의 정의 또는 표현식이 포함됩니다. 블록의 마지막 요소는 값을 정의하는 표현식입니다. 리턴 표현식 앞엔 보조정의가 올 수 있습니다. 블록 자체는 표현식이며, 표현이 가능할 때 마다 블록이 나타날 수 있습니다. 블록 및 가시성 블록 내부의 정의는 블록내에서만 볼 수 있습니다. 블록 내부의 정의는 블록 외부 정의와 같은 이름인 그림자 정의(shadow definitions)입니다. 123456val x = 0def f(y: Int) = y + 1val result = { val x = f(3) x * x} + x 이 경우 result = 16 입니다. 유효범위(LEXICAL SCOPING)블록 외부의 정의가 그림자 정의가 되지 않는 한 블록 내부에서도 볼 수 있습니다.따라서 모든 곳에서 동일한 것을 의미하는 x파라미터의 중복 발생을 제거함으로써 sqrt를 단순화 할 수 있습니다: 12345678910111213def sqrt(x: Double) = { def sqrtIter(guess: Double): Double = if (isGoodEnough(guess)) guess else sqrtIter(improve(guess)) def improve(guess: Double) = (guess + x / guess) / 2 def isGoodEnough(guess: Double) = abs(square(guess) - x) < 0.001 sqrtIter(1.0)} 세미콜론스칼라에서 대부분의 경우 세미콜론은 옵션입니다.이렇게 쓸 수 있습니다: 1val x = 1; 그러나 대부분의 사람은 세미콜론을 생략할 겁니다.반면에 만약 한 줄에 둘 이상의 명령문이 있다면 세미콜론으로 구분해야 합니다. 1val y = x + 1; y * y 세미콜론과 삽입 연산자(SEMICOLONS AND INFIX OPERATORS)스칼라 세미콜론 규칙엔 여러행에 걸쳐있는 표현식 작성하는 방법에 대한 문제가 있습니다.예를들면 : 12someLongExpression +someOtherExpression 이럴경우 12someLongExpression; +someOtherExpression 이렇게 해석됩니다.이 문제를 해결하는데엔 두 가지 방법이 있습니다.세미콜론은 내부에 삽입되지 않으므로 괄호안에 여러 줄 표현식을 쓸 수 있습니다 (…): 12(someLongExpression + someOtherExpression) 또는 첫번째 행에 연산자를 쓰면 됩니다.이렇게 하면 스칼라 컴파일러에게 표현식이 아직 완료되지 않았음을 알릴 수 있기 때문입니다. 12someLongExpression + someOtherExpression 최상위 정의스칼라 프로그램에서 def와 val은 최상위 객체 정의(top-level object define )를 해야합니다. 1234object MyExecutableProgram { val myVal = … def myMethod = …} 위 코드는 MyExecutableProgram 라는 객체(object)를 정의합니다.또한 점 표기법으로 멤버를 참조할 수 있습니다 . 1MyExecutableProgram.myMethod MyExecutableProgram 정의는 다른 정의에 내포되어 있는 정의가 아니기 때문에 최상위(top-level) 정의 입니다. PACKAGES AND IMPORTS최상위 정의는 패키지로 구성될 수 있으며 클래스 혹은 객체를 패키지 안에 넣으려면 package 절을 소스 파일 상단에 사용합니다. 1234567// file foo/Bar.scalapackage fooobject Bar { … }// file foo/Baz.scalapackage fooobject Baz { … } 패키지에 있는 정의는 동일한 패키지에 있는 다른 정의 에서도 볼 수 있습니다. 123456// file foo/Baz.scalapackage fooobject Baz { // Bar is visible because it is in the `foo` package too Bar.someMethod} 하지만 다른 패키지에 있는 다른 정의는 못보므로 이를 참조하려면 풀 네임(fully qualified names)을 사용해야 합니다. 12345// file quux/Quux.scalapackage quuxobject Quux { foo.Bar.someMethod} 혹은 이렇게도 가능합니다. 1234567// file quux/Quux.scalapackage quuximport foo.Barobject Quux { // Bar refers to the imported `foo.Bar` Bar.someMethod} Auto Import스칼라 프로그램에서 몇몇 엔티티는 자동으로 import 됩니다. 모든 맴버가 스칼라 패키지인 경우 모든 맴버가 java.lang 패키지인 경우 모든 맴버가 싱글톤 객체인 scala.Predef 인 경우 아래는 지금까지 본 몇가지 유형 및 기능의 풀 네임 입니다. 1234Int scala.IntBoolean scala.BooleanObject java.lang.ObjectString java.lang.String 실행 프로그램 작성하기지금까지의 코드 예제는 웹 브라우저(scala-exercises 사이트)에서 실행됐지만 스칼라에서 독립 실행형 응용프로그램을 만들 수 있습니다.이러한 각 응용프로그램에는 main메소드가 있는 객체가 있습니다.예를들어 여기 “Hello World!” 가 있습니다.스칼라 프로그램: 1234567object Hello { def main(args: Array[String]) = println(\"hello world!\")}``` 이 프로그램을 컴파일 후 다음 명령으로 실행할 수 있습니다.```scala$ scala Hello 읽어주셔서 감사합니다. 혹 글에 오역/추가할 내용이 있다면 코멘트 남겨주세요!🙆","categories":[{"name":"Scala","slug":"Scala","permalink":"https://sehajyang.github.io/categories/Scala/"}],"tags":[{"name":"Scala","slug":"Scala","permalink":"https://sehajyang.github.io/tags/Scala/"},{"name":"scala-exercises","slug":"scala-exercises","permalink":"https://sehajyang.github.io/tags/scala-exercises/"}]},{"title":"스칼라 번역- 고차함수 (Higher Order Functions)","slug":"higher-order-function","date":"2019-07-11T02:39:20.000Z","updated":"2021-02-09T15:25:56.495Z","comments":true,"path":"2019/07/11/higher-order-function/","link":"","permalink":"https://sehajyang.github.io/2019/07/11/higher-order-function/","excerpt":"","text":"이 포스팅은 [scala-exercises 번역 시리즈]로 scala-exercises 사이트의 스칼라 튜토리얼을 공부하며 번역한 문서 입니다.scala-exercises 는 스칼라 창시자인 마틴 오더스키 강의의 강의자료입니다.따라서 강의를 들으며 본 문서를 같이 보는것을 추천합니다.의역이 많습니다. 오역 및 오타 등은 코멘트로 알려주세요 😄원문 : [scala tutorial higher order functions] 고차함수(Higher Order Functions)함수형 언어는 함수를 일급 시민(first-class) 으로 다룹니다.즉 값처럼 함수를 매개변수로 전달하고 결과를 반환할 수 있습니다.고차함수는 프로그램을 유연하게 조립하는 방법을 제공합니다.이렇게 마치 값 처럼 다른 함수를 매개변수로 사용하거나 함수를 결과로 리턴하는 함수를 고차함수라고 합니다. MOTIVATION a와 b사이의 정수(integer)들을 더합니다. 12def sumInts(a: Int, b: Int): Int = if (a > b) 0 else a + sumInts(a + 1, b) a 와 b 사이의 정수(integer)들인 cube 들을 더합니다. 1234def cube(x: Int): Int = x * x * xdef sumCubes(a: Int, b: Int): Int = if (a > b) 0 else cube(a) + sumCubes(a + 1, b) a 와 b 사이의 정수(integer)들인 factorial 들을 더합니다. 12def sumFactorials(a: Int, b: Int): Int = if (a > b) 0 else factorial(a) + sumFactorials(a + 1, b) 어떻게 이 비슷한 메소드들의 공통 패턴을 제거할수 있을까요? 고차함수를 이용해 더하기sum 함수는 다음과 같습니다. 123def sum(f: Int => Int, a: Int, b: Int): Int = if (a > b) 0 else f(a) + sum(f, a + 1, b) 그리고 다음과 같이 작성할수 있습니다. 1234def id(x: Int): Int = xdef sumInts(a: Int, b: Int) = sum(id, a, b)def sumCubes(a: Int, b: Int) = sum(cube, a, b)def sumFactorials(a: Int, b: Int) = sum(factorial, a, b) 함수 타입A => B의 타입은 함수 입니다. 함수 형태인 A argument 를 입력한 결과를 B 라는 결과로 리턴합니다.그러므로, Int => Int는 int를 int로 맵핑하는 함수 입니다. 익명함수(ANONYMOUS FUNCTIONS)함수를 매개변수로 전달하려면 많은 작은 함수가 필요하고, 생성해야합니다.그리고 def 로 이런 함수(및 함수의 이름)를 일일히 정의해야하는 일은 너무 번거롭습니다. 1val str = \"abc\"; println(str) // 지루한 코드 그러니 스칼라는 바로 아래와 같이 이렇게 작성할 수 있습니다. 1println(\"abc\") string 과 비교하자면 : val을 사용해 string을 정의할 필요가 없습니다.왜냐하면, string 은 리터럴(literals)로 존재하기 때문입니다.이와 비슷하게 함수 리터럴을 원하므로, 함수 리터럴에 이름을 주지않고 함수를 작성하게 됩니다.이를 익명 함수(anonymous functions) 라고 합니다. 익명함수의 문법argument 를 cube 로 전달하는 함수는 다음과 같습니다. 1(x: Int) => x * x * x (x: Int)는 함수의 매개변수(parameter) 이며 x * x * x는 함수의 body 입니다.만약 컴파일러가 컨텍스트에서 유추할 수 있는 경우 파라미터의 타입은 생략할 수 있습니다.파라미터가 여러개인 경우 쉼표로 구분됩니다. 1(x: Int, y: Int) => x + y 익명함수는 Syntax Sugar 입니다(Anonymous Functions are Syntactic Sugar)익명함수 (x1: T1, …, xn: Tn) => e는 항상 def 를 사용해 다음과 같이 표현할 수 있습니다. 1{ def f(x1: T1, …, xn: Tn) = e ; f } 여기서 f 는 프로그램에서 아직 사용되지않은 임의의 새로운 이름입니다 따라서 익명함수로 표현될수 있습니다.이렇게 익명함수는 문법적 설탕입니다. 익명함수를 이용한 sum 함수 작성익명함수를 이용하면, sum 함수를 좀더 짧게 작성할 수 있습니다. 12def sumInts(a: Int, b: Int) = sum(x => x, a, b)def sumCubes(a: Int, b: Int) = sum(x => x * x * x, a, b) 읽어주셔서 감사합니다. 혹 글에 오역/추가할 내용이 있다면 코멘트 남겨주세요. 같이 보면 좋은 포스팅 : 일급 함수","categories":[{"name":"Scala","slug":"Scala","permalink":"https://sehajyang.github.io/categories/Scala/"}],"tags":[{"name":"Scala","slug":"Scala","permalink":"https://sehajyang.github.io/tags/Scala/"},{"name":"scala-exercises","slug":"scala-exercises","permalink":"https://sehajyang.github.io/tags/scala-exercises/"}]},{"title":"190627-190707 주간 회고","slug":"190627-190707","date":"2019-07-08T02:37:51.000Z","updated":"2019-07-15T14:11:55.556Z","comments":true,"path":"2019/07/08/190627-190707/","link":"","permalink":"https://sehajyang.github.io/2019/07/08/190627-190707/","excerpt":"","text":"학습할 언어로 스칼라를 선택한 뒤로 한주간 다른 공부보단 스칼라 공부에 전념했다.처음엔 스칼라의 교과서라고 불리는 Programming in Scala로 학습했으나 내겐 아직 어려운 책이라 러닝 스칼라란 책을 추천받아 이 책으로 학습하고 있다.스칼라 과거에 프로그래밍 첫 언어로 C++을 독학하던 때가 생각 날 정도로 어려웠다.파이썬도 코틀린도 이렇게 어렵진 않았는데 스칼라는 이해가 가지 않는다.이 이해라는건 머리론 했는데 납득이 가지 않은 상태와 비슷해서, 이해가 안되니 배우고 금방 잊어버리기까지 한다.그러던 중 스칼라의 문법을 배우며 예제를 풀어 볼 수 있는 scala exercises 사이트에 대해 알게되었다.이 사이트에 대한 한국어 번역이 없었기 때문에, 나의 스칼라 학습 및 입문하는 분들에게 도움이 되기 위해 번역을 하기로 결정했다.이 번역을 완성하면 블로그에도 게시를 할 생각이다! 최근에 그간 얕고 넓은 지식을 쌓아온 것 같다는 생각이 들었는데, 그러한 지식 및 학습방식에 대해 염증을 느끼게 되었다.그래서 이번 학습은 바텀-업(bottom-up)방식으로 하는 만큼 탑-다운 방식 으로 공부하던 예전과 달리 좀 더 꼼꼼하게 이론/문법 등을 익히고 싶다는 욕심이 있다. 한주간 했던 학습 scala와 kotlin 비교 포스팅 Scala Exercises 학습 및 번역 Programming in Scala 학습 러닝 스칼라 학습 다음주 목표 Functional Programming Principles in Scala 수강 러닝 스칼라 학습 Scala Exercises 학습 및 번역 총평이번주는 오랜만에 새로운 언어를 학습하느라 즐겁게 공부했었다.다음주엔 Functional Programming Principles in Scala 강의를 수강할 예정이다.마틴 오더스키가 직접 강의했는데, 한글 자막이 없어서 조금 아쉽다.책은 러닝 스칼라를 먼저 본 뒤에 Programming in Scala를 봐야될 것 같다. Scala Exercises 번역은 다음주 혹은 2주뒤에 마무리 될 것 같다.한달간 주말엔 통 시간이 나지 않았는데, 다음주에는 주말에 조금이라도 짬을 내서 학습에 쏟는 시간을 늘려야겠다..","categories":[{"name":"Logs","slug":"Logs","permalink":"https://sehajyang.github.io/categories/Logs/"}],"tags":[{"name":"weekly","slug":"weekly","permalink":"https://sehajyang.github.io/tags/weekly/"}]},{"title":"Scala와 Kotlin 비교","slug":"scala-vs-kotlin","date":"2019-07-02T02:49:54.000Z","updated":"2020-02-16T07:52:59.573Z","comments":true,"path":"2019/07/02/scala-vs-kotlin/","link":"","permalink":"https://sehajyang.github.io/2019/07/02/scala-vs-kotlin/","excerpt":"","text":"최근 함수형 언어(FP) 를 학습하기 위해 스칼라와 코틀린을 비교하다 정리하게 되었습니다.이 포스팅은 함수형 프로그래밍에 대한 글이 아니기 때문에 바로 스칼라와 코틀린을 비교해보도록 하겠습니다.혹시 함수형 프로그래밍이 궁금하시다면 함수형 프로그래밍 요약을 참고해주세요! Scala스칼라는 확장된 자바 를 지향하며 다중 OOP특성과 FP특성을 함께 가진 다중패러다임 언어입니다.그러한 철학은 스칼라 라는 이름에서도 볼 수 있는데, 스칼라는 Scalable(확장가능한) + Language(언어) 라는 단어의 결합으로 탄생한 이름입니다.EPFL대학의 마틴 오더스키가 만들었으며 그가 제작한 강의와 책이 있습니다.매우 강력하며 세심하게 디자인 되었지만 그 만큼 제대로 공부하고 사용하는것이 어렵다는 평을 받고 있습니다.함수형으로나 객체지향적으로 원하는 모든 기능(큰 자유와 수많은 기회)을 제공합니다.심지어 JVM에서 벗어나 컴파일 언어가 되는 작업을 진행하기도 합니다.Java에는 없는 많은 기능이 포함되어 있으며 동시 처리등의 큰 데이터 처리작업에 적합합니다. 장점 강력한 OOP 스타일의 FP 기능1급 객체(1급 시민), 고차 함수, 순수 함수, 불변성, 합성 함수 등을 잘 지원합니다 쉬운 언어 확장 및 DSL 자바와 코틀린에는 없는 기능 지원패턴 매칭, 매크로 및 상위 유형의 완벽한 지원, 동시 처리 지원 등(코틀린에도 코루틴이 있지만 스칼라의 future은 더욱 다양하게 사용 가능합니다) 연산자 오버로딩이 기능은 코틀린에도 있지만 스칼라의 연산자 오버로딩은 새로운 연산자를 정의할 수 있습니다. 코틀린에 비해 자료 및 라이브러리가 많습니다.스칼라는 2004년에 나온 언어로 코틀린에 비해 자료와 라이브러리가 풍부합니다.스택오버플로우(2019.7 기준)에서 약 7만건정도 차이나는 것을 알 수 있습니다. Java와의 호환성Java와의 호환성이 좋습니다. 스칼라에선 자바코드를 100% 가져다 쓸 수 있습니다. 단점 러닝커브가 높습니다.많은 자바 개발자들은 스칼라의 복잡성 때문에 당황했으며 높은 학습비용은 포기하는 이유가 되었습니다. 컴파일 속도가 느리며 jar 파일 용량이 큽니다.이것은 사람들이 말하는 스칼라의 가장 큰 단점 중 하나입니다. 이전 버전 컴파일이 어렵습니다(몇몇 버전은 이전 버전과 호환되지 않습니다) null safety한 측면에서 코틀린보다 별로입니다. scala 2.1.1의 경우 자바 1.8 부터 호환이 가능합니다.따라서 자바 1.8이하의 기존 레거시 코드와 같이 사용할 수 없습니다.또한 자바에서 스칼라코드를 가져와서 그대로 쓸 순 없습니다. 일각에선 스칼라는 어렵기 때문에 자바 > 코틀린 > 스칼라순으로 공부하는 것을 추천하기도 합니다. Kotlin 코틀린은 더 나은 자바 를 목표로 한 언어입니다.코틀린은 보일러플레이트 코드를 줄이며, null safety 한 기능을 제공하는 등 자바의 부족한 기능을 보완한 언어입니다. 장점 젯브레인사 에서 만든 언어이며 구글 안드로이드 공식 언어로 채택되었습니다. 강력한 null safety 기능을 제공합니다. 러닝커브가 낮습니다. 자바 개발자는 금방 코틀린에 적응할 수 있으며 쉽게 사용할 수 있습니다. Java 1.6 부터 호환이 가능하므로 기존 자바 레거시 프로젝트와의 결합이 용이합니다. 단점 Java 100% 호환 이지만 자바 서드파티들과 호환이 다 되는 것은 아닙니다.(하지만 스칼라보단 호환이 좋습니다) OOP와 FP둘다 가능한 멀티 패러다임 언어지만 Scala에 비해 다소 미약한 FP를 지원합니다.(이것은 객관적인 단점이라기보단 언어의 특성, 철학 때문입니다) 다소 아쉬운 동시성을 지원합니다. 마무리일반적으로 스칼라와 코틀린은 자바에 대한 대안입니다. 그러나 두 언어는 확연히 다른 언어입니다. 스칼라는 잘 쓰면 고급 함수 프로그래밍에 대한 강력한 자원을 제공 하지만 잘못 쓰게되면 금새 엉망이 되어버립니다.코틀린은 스칼라에 비해 다소 약한 FP를 지원하지만 배우기 쉽고 사용하기 쉬우며 자바만큼 빠른 컴파일 속도 및 가벼운 jar를 만들 수 있습니다.완벽한 100% FP는 없습니다. 얼마나 더 FP 하냐의 차이입니다. 그런 부분에 있어서 스칼라가 코틀린에 비해 더 FP할 수 있는 기능을 제공합니다.저는 좀더 FP한 언어를 원했기 때문에 스칼라를 선택했습니다.여담으로 스칼라는 안드로이드 포팅이 어렵기 때문에 코틀린이 좋습니다.두 언어는 철학부터 다르기 때문에 본인에게 필요한 언어를 파악해 잘 선택하는것이 중요하겠습니다. 큰 데이터로 작업을 하거나 속도를 높이고 싶으면 스칼라가,배우기 쉬우며 향상된 자바를 원하면 코틀린을 선택하는 것이 좋을 것 같습니다. 읽어주셔서 감사합니다. 혹 글에 오류/추가할 내용이 있다면 코멘트 남겨주세요!🙆 참고 Scala vs Kotlin Kotlin vs. Scala: What Should I Choose Instead of Java? Kotlin vs Scala: Which Problems Do They Solve? Scala vs Kotlin: Operator overloading","categories":[{"name":"Scala","slug":"Scala","permalink":"https://sehajyang.github.io/categories/Scala/"}],"tags":[{"name":"Scala","slug":"Scala","permalink":"https://sehajyang.github.io/tags/Scala/"},{"name":"Kotlin","slug":"Kotlin","permalink":"https://sehajyang.github.io/tags/Kotlin/"}]},{"title":"190529~190625 월간회고","slug":"190529-190625","date":"2019-06-25T05:27:42.000Z","updated":"2019-08-02T14:41:53.792Z","comments":true,"path":"2019/06/25/190529-190625/","link":"","permalink":"https://sehajyang.github.io/2019/06/25/190529-190625/","excerpt":"","text":"해커톤 이후 바쁘기도 하고 블로그도 리뉴얼 하느라 한달만에 주간회고 월간회고를 작성하게 되었다. 주간회고를 적는 이유는 그 주에 어떤걸 배웠고 어떤걸 배울건지 계획을 세우는, 한주를 마무리짓는 중요한 작업 중 하나였는데 바뻣다는 핑계로 미루게되어 부끄럽다. 한달동안 한 학습 및 개발한 것 Hexo + next theme (블로그 리뉴얼) 알고리즘 문제 풀이 Kafka Call for code 버츄얼 해커톤 Hexo + next theme블로그 프레임워크를 Jekyll에서 Hexo로 바꿨다!처음엔 오른쪽 사이드바에 카테고리가 없는게 불만이라 수정을 시도해 봤지만 이미 만들어져 있는 테마를 갈아엎기엔 시간이 많이 들어갈 것 같아 몇번 시도하다 다른 테마로 바꾸려는데 엔진을 바꿔야 했다.루비 문법을 몰랐기 때문에 Jekyll을 사용하기가 부담스러웠고, 속도부분에서도 별로라고 생각했기 때문에 Hexo로 바꿨다.물론 Hexo 는 Github로 버전관리가 되지 않는다는 단점이 있지만 나는 그간 yml파일이 올라가는것에 대한 불만(secret key 노출 등)이 있었기 때문에 Hexo로 바꾼 후 매우 만족중이다!버전관리에 대한 이슈는 따로 레포를 파서 관리 중이다. 몇번의 삽질 끝에 [이 포스팅]을 보게되어 참고했는데 굉장히 설명이 잘 되어있어서 삽질을 끝내고 비로소 서브모듈을 잘 달아 배포할 수 있었다😄그 밖에 카테고리, 태그등을 달았는데 생각보다 Hexo에 뉴비를 위한 카테고리, 태그등을 추가하는 방법에 대한 한글 포스팅이 적고 불충분했다.. 그래서 시간이 되면 해당 내용에 대해 포스팅 할 계획이다. 댓글은 gittalk를 사용했다. 거의 중국어로 된 포스팅이 많으며 한글로 된 포스팅이 거의 없기 때문에 문제가 생기면 해결하기가 쉽진 않았다.그 후 블로그 내의 포스팅 검색을 위한 algolia 와 구글 서치를 위한 sitemap 생성등을 마치고 기존 포스팅 규격을 새로운 블로그 규격에 맞추는 등의 작업을 했다.날 잡고 했으면 하루 이틀이면 끝냈을텐데 차일피일 미루다 보니 1~2주가 걸렸다. 하지만 처음 지킬 블로그 썼을땐 설정잡고 하는데에 몇달간 질질 끄는 등 굉장히 오래걸렸었는데, 이젠 금방 설정을 잡게되어 감게무량했다.(심지어 지인의 지킬블로그에서 카테고리가 동작하지 않는 이슈도 해결하고 풀리퀘를 날렸다😮)깃허브 블로그는 한번 설정 잘하고 잘 만들어두면 후에 포스팅만 작성하면 되기 때문에 애용하고 있다. 알고리즘 문제 풀이최근 지인들과 알고리즘 문제풀이를 시작했는데, 몇가지 문제 중 Farm 문제가 기억에남는다. 이 문제는 연립방정식을 세워서 해를 구하면 되는 문제였는데, 이 문제는 식을 세우거나 브루트포스(for문 돌리기)로 해결할 수 있다.후자의 경우 범위가 크게 늘어나면 시간이 오래걸린다는 단점이 있으므로 나는 식을 세우는 방향을 택했다.식을 세우는 작업은 예외도 같이 생각해야 하기 때문에 예외를 생각해서 처리하지 않으면 십중팔구 틀린다!나는 식 및 예외는 잘 처리한 것 같은데 자꾸 틀려서 헤메다 자꾸 틀리는 원인이 부동소수점 때문이라는 걸 알게되었다.부동소수점에 대한 설명은 이 포스팅에 잘 나와있다.부동소수점이 일어나는 원인은 컴퓨터의 숫자는 2진수이기 때문에 특정값을 정확히 표현할 수 없으며 근사값을 얻어 계산하기 때문이다.이것을 해결하기 위해선 div_mod등을 사용하는 방법등이 있다.이 문제는 부동소수점의 중요성을 깨닫기에 좋은 문제인 것 같다! 항상 나누기를 할 땐 조심해야된다. Kafka최근 프로젝트에 Kafka를 도입할 각을 보고 있었다. 도입 이유로는 12345유연한 스케일링스케줄링 용이실시간성데이터의 무결성고가용성 등이 있었지만 초보인 내가 프로덕션에 도입하기엔 너무 위험한 것 같아 포기했다. Call for CodeCall for Code가 이제 제출까지 약 한달이 남았다!최근엔 6/20일에 팀원이 모여서 24시간동안 버츄얼 해커톤을 진행했다.그러나 재난시엔 네트워크가 파괴되어 통신이 안되거나, 디바이스가 파손/분실되기도 하며배터리 이슈도 있기 때문에 한계가 많아서 아직 뚜렷한 아이디어는 내지 못했다. 좀 더 고민해봐야될 것 같다.. 2주간 목표 자료구조와 함께 배우는 알고리즘 학습 알고리즘 문제 풀이 Scala (맛보기) 공부 시작, Programming in Scala 3/e 총평이번달은 작년 슬럼프 이후로 가장 학습을 게을리 한 달 이었다..학습을 하기보단 과거에 한 학습을 써먹은 달이 되었는데, 나는 아직 배워야 할 것이 많기 때문에 아쉬운 달이 되어버렸다.다음 회고는 좀 더 알차고 게으르지 않은 회고가 되길..! 다음 회고까지 2주간 자료구조와 알고리즘에 전념할 예정이며 저번에 살짝 알아보기만 했던 Scala 공부를 천천히 시작할 것 이다 😄","categories":[{"name":"Logs","slug":"Logs","permalink":"https://sehajyang.github.io/categories/Logs/"}],"tags":[{"name":"weekly","slug":"weekly","permalink":"https://sehajyang.github.io/tags/weekly/"}]},{"title":"AngelHack 2019 서울 참석 및 우승 후기","slug":"2019-06-13-angelhack-2019-seoul-win-review","date":"2019-06-12T15:00:00.000Z","updated":"2020-07-26T12:51:24.022Z","comments":true,"path":"2019/06/13/2019-06-13-angelhack-2019-seoul-win-review/","link":"","permalink":"https://sehajyang.github.io/2019/06/13/2019-06-13-angelhack-2019-seoul-win-review/","excerpt":"","text":"지난 6.1~6.2일에 엔젤핵 해커톤에 참가했다.참가한 해커톤은 AngelHack 2019 Seoul 라는 해커톤이었는데, 우승 후 진행되는 프로그램을 보니 투자를 받고자 하는 팀이 지원할 것 같은 해커톤이었고 그만큼 스폰서도 크고 많았다.해커톤은 처음이라 지인과 함께(개발자) 떨리는 마음으로 해커톤에 참가하게 되었다. 가기 전날엔 내 실력으로 민폐만 끼치는게 아닐까 하며 매우 걱정했었다.행사는 9시 시작이었는데 늦잠을 자는 바람에 10시에 도착했다. 장소는 마루 180의 지상1층과 지하1층이었는데 특이하게 지하는 차고같이 꾸며져 있었다. 실리콘밸리의 성공한 많은 기업들이 차고에서 탄생해서 그런것이었을까?굿즈(티셔츠와 스티커 등)를 받아들고 입장하니 많은 사람들이 벌써 도착해 자리가 꽉 차 있었다.150명정도 신청했는데 대략 100명정도 왔다고 한다. 일정표는 이러했다 11시부턴 팀 빌딩이었는데, 지인과 나는 둘다 백엔드 개발자였기 때문에 기획자, 디자이너, 프론트엔드 개발자를 찾아 팀을 꾸려야 했다(프론트엔드 개발자는 적었고 구할 수 없었다..)처음보는 분들과 얘기를 나누고 바로 팀으로 영입(?)시키는건 여간 어려운게 아니었다.여차저차 팀을 꾸리니 12시였고, 우리팀은 백엔드지만 프론트를 조금 하시는 개발자 한분, 백엔드인 지인과 나, 기획자, 디자이너 이렇게 다섯이서 팀을 꾸리게 되었다.그 후 후원사의 스피치가 있었고 제출은 내일 오후 1시라는것을 듣게 되었다. 이 해커톤이 제출기한이 좀 빠른거라고 개발하기 빠듯하겠다고 지인은 말했다.팀이 꾸려지자 바로 기획에 들어갔다.도전과제로는 AWS Amplify 사용, IBM 서비스를 사용, IBM의 call for code등이 있었다.처음엔 AWS Amplify를 사용하려고 했는데, 웹앱 혹은 앱 개발시에만 사용할 수 있었으므로 우린 사용할 수 없었다.IBM 서비스는 우리 모두 처음이라 셋팅하는데에 너무 오랜시간이 걸려 그냥 AWS 서비스를 사용했다. AWS에선 개발자 한명당 100$ 크래딧을 줬다! 우리팀은 Call For Code에 도전했는데, 당신의 코드로 세상을 구하다 라는 캐치프레이드로 공식 홈페이지에선자연재해 대비 및 구호를 위해 AI, 블록체인, 클라우드, IoT를 활용한 솔루션을 개발하는 글로벌 챌린지입니다라고 설명하고있다. 재난시에 사람을 살릴 수 있는 프로그램등을 개발하는 것 이다. 우리팀의 아이디어는 핫스팟을 엮어 재난시에 외부 네트워크 이용이 되지 않는(외부망에 접속이 안되는) 상황에 재난자들 사이에 프라이빗한 네트워크를 구축해 재난자들끼리 소통이 되게 하자는 것이었고 여러 아이디어중 지인이 낸 해당 아이디어로 채택되었다. 협업을 해 서비스를 짧은 시간안에 만들어야 되는 만큼 충분히 대화가 필요했다.또한, 같이 논의를 했지만 서로 이해하는바가 다르며 그 부분을 조율하고 서로 대화로써 풀고 이해하는것이 중요하다는 것을 많이 깨달았던 것 같다.멘토님들도 계셔서 멘토님들께 모르는 것을 물어보거나 작년 우승자 혹은 참가자와 컨셉이 겹치지는 않는지를 물어봤었다.다행히 전혀 겹치지 않는다고 하셔서 걱정없이 그 뒤 개발에 착수할 수 있었다.멘토님들은 돌아다니시면서 기술적으로 혹은 그 밖의 질문에 대해서 답을 해주시곤 했는데 큰 도움이 되었다. 개발은 대략 오후 3시즈음에 시작하게 되었다.내가 맡은 부분은 재난시 모니터링 및 채팅 등을 할 수 있는 이른바 어드민 페이지를 개발이었다.플라스크로 하려다 겪어본적 없는 오류가 나면 잡는데에 오랜시간이 걸릴까 불안해 익숙한 스프링부트로 개발을 했다.그리고 두번다시 해커톤에서 스프링부트를 사용하지 않으리라 다짐했다(내 숙련도에 문제가 있긴 했지만)JPA때문에 굉장히 고생을 했고 잡아뒀던 환경도 뭣도 아무것도 없었기 때문에(지금 생각해보면 뭔 자신감으로 아무것도 없이 갔나 싶다) 프로젝트 생성하고 환경 잡고 여차저차하니 대략 7시즈음이었던 것 같다.환경잡는데에 너무 많은 시간이 걸려서 당시엔 정말 속이 답답했었다. 당시 커밋로그들 밥은 정말 잘 나왔었는데 대체로 샐러드류라 조금 배가 고팠다..노트북은 한성 보스몬스터(게이밍)무겁다 새벽 2시즈음인가, JPA를 잘못 사용해서 select 순환 참조 오류가 생겼었다. 그때 정말 이거 다 밀고 플라스크로 작업할까 생각했었다. 해결하는데에 한시간정도 걸렸었는데, 정말 아찔했다.해결은 [링크] 와 같이 했다.개발시간이 빠듯하게 정해져 있어서 뭔가 이상한 오류가 나면 정말 심장이 쫄깃했던 것 같다. 한숨도 못자고 밤을 그렇게 샜다.중간에 피자와 치킨을 받았지만 먹을 시간이 없었다ㅠㅠ새벽 다섯시경 주위를 보니 다른팀 개발자분들도 안자고 열코딩중이었다. 해커톤은 원래 이렇게 빡센가요.. 지인이 말하길 원래 이렇게 빡세다고 한다. 최초의 팀 이름은 angel cell 이었다 밤 사이 우리팀의 이름은 Conectus로 결정되었다. 맨처음엔 링크드리스트등의 후보가 있었지만 생존자를 잇는다는 의미로 Connect + Us 해서 Conectus 가 되었다.왜 Connect가 아니고 Conect인진 모르겠다 7시즈음에 대략 API를 다 완성했었다. 그 후 한 10분정도 자다가 아침이 되니 대략 정신이 나가서 아무것도 머릿속에 들어오지 않았다.나 외에 지인 및 다른 개발자분도 다 완성을 했고 우리팀은 다같이 실제 테스트(사람이 하는)를 해보고 수정하고 테스트하고를 반복하다보니 1시가 되었다. 사실 중간에 마크업 개발자의 부재로 인한 문제가 있었다. 그 때문에 어드민페이지는 API만 잔뜩 만들어두고 보여줄 수 없어서 아쉬웠다. 우리팀은 12번째 발표였다 발표 시간은 2분이었는데 굉장히 짧았다. 컨셉, 간단한 기능소개 하고 바로 시연하기에도 빠듯한 시간이었다. 후에 알게되었지만 샌프란시스코 데모데이의 발표시간이2분으로 제한되어있어 그런게 아닌가 싶다.2분의 발표 후엔 심사위원분들의 질문이 이어졌다. 질문에 대한 답은 총 14초 이상을 넘을 수 없었다. 그것 또한 데모데이의 룰과 같았다. 우리조는 간단한 기능소개(1분)+짧은 시연(1분) 으로 발표를 했는데, 다 보여주진 못했지만 아이디어나 컨셉은 잘 전달한 것 같았다.22개조의 발표가 끝나고 몇십분의 대기 후 바로 시상식이 시작되었다. 상은 IBM Challenge, AWS Challenge, AngelHack 전체 우승 이렇게 세개였는데 우리팀은 IBM과 Amplify를 사용하지 않았기에 IBM, AWS 챌린지상과는 전혀 관련이 없었다.전체상 또한 굉장히 쟁쟁하고 잘 만든 팀이 많았기 때문에 나는 마음을 비우고 1박2일동안 이정도를 만들어냈다는것에 의의를 두고 있었다.아쉬운 부분이 많았지만 개인적으로 완성했다는 것에 뿌듯함을 느끼고있었다.그런데 최종우승 팀으로 우리팀이 호명되었다! 우리조원 전부 정말 하나도 기대를 하고 있지 않았었기 때문에 굉장히 놀랐었고 그야말로 대 패닉 상태였다.그렇게 얼떨떨하게 상을 받게 되었다. 많은 분들이 우리팀 아이디어가 좋았다고 칭찬해주셨다.이렇게 동료를 잘 만나 처음 참가해서 수상도 하고 정말 개발적으로 혹은 개발 외적으로 배울것도 많았던 해커톤이었다.혼자였으면 절대 못했을텐데.. 처음 만나서 다 같이 고생하고 다 같이 만들어내서 더 뜻 깊었던 것 같다.다음에 기회가 된다면 또 참가할 것 같다! 고마워요 엔젤핵!해당 소스 및 레포는 github에 공개되어 있습니다.읽어주셔서 감사합니다!😄","categories":[{"name":"Seminar","slug":"Seminar","permalink":"https://sehajyang.github.io/categories/Seminar/"}],"tags":[{"name":"hackaton","slug":"hackaton","permalink":"https://sehajyang.github.io/tags/hackaton/"}]},{"title":"190522~190528 주간 회고","slug":"2019-05-28-190522~190528","date":"2019-05-27T15:00:00.000Z","updated":"2019-07-15T14:11:55.596Z","comments":true,"path":"2019/05/28/2019-05-28-190522~190528/","link":"","permalink":"https://sehajyang.github.io/2019/05/28/2019-05-28-190522~190528/","excerpt":"","text":"이번주엔 springboot로 약 일주일간 개발하던 사내 익명게시판 프로젝트가 어느정도 마무리 됐기 때문에 후기 겸 주간회고를 작성하게 되었다.개발하면서 가장 애먹었던 건 handlebars.js 였는데 helper가 등록되지 않는 이슈였다.나는 hbs(handlebars 확장자) 파일을 html로 변경을 한 후 springboot properties에서 그 html을 hbs 로 인식하게 했다.helper를 사용하고 싶으면, 그렇게 하면 안되는 거였다(어쩐지 구글링해도 안나오더라)그렇게 약 3일을 삽질하다 helper를 사용하고 싶다면 html를 hbs로 인식하게 하는걸 해제하고, html에 helper와 hbs 파일(혹은 script id 및 type 에 handlebars template를 삽입 하던가 )을삽입해야 한다는 것을 알게 되었다.혹은, Handlebar를 사용하여 배포까지 (+grunt +gradle) 이런 방법도 있다.하지만 최대한 간단하고 빠르게 개발하고 싶었고(이미 기존에 쓰던 기술 대신 새로운 기술로 도입한 시점부터 빠르게 개발은 무리였던 것 같지만) 무언가를 더 늘리고 싶지 않았기 때문에결국 handlebars는 순수하게 서버로부터 받아온 데이터를 보여주기만 했고, js(바닐라 및 jquery) 로 나머지.. DOM조작이라던지 를 했다.JSP에 비해 코드가 깔끔해져서 좋았지만 handlebar에 helper를 등록해서 썼다면 더 좋았을 것 같아서 아쉬웠다. JPA도 처음이었기 때문에 굉장히 고생했다. 처음엔 아무것도 모르고 늘상 하던 것 처럼 네이티브 쿼리를 짰다.심지어, @Query에 nativequery=true를 해서 쓰다가 뭔가 잘못됐음을 깨닫고, 뒤늦게 인프런에서 스프링 데이터 JPA를 수강하기 시작했다.나는 학습을 탑 다운방식으로 한다. 새로운 기술을 배울때 문서를 읽지않고 일단 get started 혹은 example 을 보고 시작하는 것이다.딱히 그게 좋아서 라기보단 그냥 탑 다운 방식에 익숙하기 때문인데, 그렇게 이번에 handlebars 및 JPA를 시작했다가 호되게 당했다. 이론/원리에 대해 혹은 문서를 좀 더 학습한 후 개발했으면 좋았을텐데 라는 생각이 들었다.아무튼, 잘못 짜고 있었다는 걸 뒤늦게 깨달았으므로 기존에 짰던건 그냥 남겨두고, 몇가지 함수만 변경했다.이번에 이런 ORM을 사용해봤는데 기존의 방식과 많이 달라서 힘들었고 삽질도 많이 했지만 재밌었다. 좀 더 강의를 수강하고 다시 이번 프로젝트를 고쳐보고싶다. 이번 토이프로젝트를 개발할 때에 gitHub 의 issue와 project를 적극 활용해봤는데, 이슈관리하기도 편하고, 좀더 다음에 무엇을 개발해야할지 우선순위 혹은 집중하기가 좋았다.이슈 하나 클리어 할 때 마다 Done 에 closed 된 이슈들이 차곡차곡 쌓이는 것도 좋았고, 이슈 넘버를 넣어서 커밋하면 자동으로 Done 으로 이동되는 것도 좋았다.다음에 개발할때에도 적극 활용할 예정이다.GitHub로 프로젝트 관리하기 Part1 - 이슈 발급 부터 코드리뷰까지이 포스팅을 참고해서 다음엔 이슈관리를 해봐야겠다. 플라스크 학습을 시작했다. 이번주에 있을 해커톤 때문인데, sanic과 비슷해서 할만한 것 같다! 애당초 sanic이 flask의 철학을 이어받아(?) 개발되었다고 한다.그래서 두 프레임워크가 비슷한 것 같다. 총평써보고 싶던 기술을 써봐서 좋았고 학습할 수 있어서 좋았다! JPA에 대해 더 알아보고 싶다.아쉬운 부분도 많았다. 특히, 탑다운 방식으로 학습하던 나는 호되게 당했다. 다음부턴 이론과 실습(?)이 핑퐁처럼 되도록 학습해야겠다.이번 프로젝트에 대해선, 좀 더 공통적인 부분을 모듈화하고 싶고 전체적으로 리팩토링을 좀 하고싶다. 최대한 레거시가 되지 않도록 노력했지만 나름대로 리팩토링을 했었지만, 결국 레거시를 잔뜩 만들고야 말았다..자꾸 많은것이 바뀌었었기 때문에 테스트코드 짜기가 힘들어서 테스트코드를 초반에만 조금 짜다가 포기했다.나는 아직 TDD는.. 잘 모르겠다. 빠르게 개발하면서 많은것이 바뀌고 계속해서 리팩토링을 하는데, 그럴때마다 테스트코드 리팩토링 하기가 참 힘든 것 같다.그래서 아직까진 다 짜둔 코드에대해(당분간 바뀌지 않을) 테스트 코드를 작성하는게 좋은 것 같다. 한주간 했던 것 springboot 익명 게시판 프로젝트 Flask 학습 시작 다음주 목표 springboot 익명 게시판 프로젝트 리팩토링 JPA 강의 학습 Flask 학습","categories":[{"name":"Logs","slug":"Logs","permalink":"https://sehajyang.github.io/categories/Logs/"}],"tags":[{"name":"weekly","slug":"weekly","permalink":"https://sehajyang.github.io/tags/weekly/"}]},{"title":"190422~190521 월간 회고","slug":"2019-05-21-190422~190521","date":"2019-05-20T15:00:00.000Z","updated":"2019-07-15T14:11:55.595Z","comments":true,"path":"2019/05/21/2019-05-21-190422~190521/","link":"","permalink":"https://sehajyang.github.io/2019/05/21/2019-05-21-190422~190521/","excerpt":"","text":"어쩌다보니 2주치를 두번 밀려 월간 회고가 되어버렸다.이번달을 요약하자면 이것저것을 하다 초심으로(springboot) 돌아간 것 쯤 되겠다.슬럼프에 빠져 뭘 해도 의욕이 나지 않아서 새롭고 평소에 배우고 싶었던 걸 해보고 싶었다.그래서 스칼라도 해보고 코틀린도 해보고 카프카도 써봤다. 스칼라는 예전부터 관심이 있다가, KCD 에서 스칼라 세션을 듣고 라스칼라 슬랙에 들어가면서 더욱 관심이 많아졌었다.하지만 모든것에 초보가 되지 말라는 말을 듣고, 일단 지금은 하고있는것에 집중하고 스칼라는 나중에 해야겠다고 생각했었다.그러다 이번에 슬럼프가 오면서 일탈(?) 로 살짝 맛만(?) 봤는데 함수형과 관련이 없던 삶을 살아온지라 무슨 말인지 이해가 되지 않았다. 모나드는 대체 뭐란말인가.. 설명을 봐도 예제를 모르겠고 밑도끝도 없이 하나도 모르겠어서 나중을 기약하기로 했다.. 코틀린은 저번에 프로덕션에 적용하는걸 실패한 뒤로 개인적인 토이 프로젝트를 만들어 봐야겠다고 생각했었다.근데 아직 나는 코틀린이 엄청 좋다는건 못느끼겠다.자바에 익숙함과 그로인해 얻는 시간 및 비용의 절약을 버릴만큼 코틀린이 나에게 지금 필요하다고 생각하지 않는다.그리고 몇몇 자바 서드파티들과 호환이 되지 않는다는건 치명적이라고 생각한다.하지만 null safety 한 부분은 정말 매력적이라고 생각한다. 카프카는 그냥 메세징 큐 를 공부하다, springboot에 쉽게 시작할 수 있는 예제가 있길래 이것저것 환경을 잡아서 해봤다.우리 프로덕션 대형 문자를 보낼때 쓰면 좋겠다고 생각했다. 언젠가 카프카를 쓰는 빠른 실시간 처리가 필요한 프로젝트를 해보고싶다. 그렇게 이것저것을 하며 방황을 하던 중 사내 게시판(이라 쓰고 인트라넷이라 읽는다)이 필요하다 느껴 토이 프로젝트로 게시판 만들기를 시작했다.실제로 서비스 할 것이기 때문에 생각할게 많은 것 같다.그간 springboot + jsp + mysql로 작업을 했었는데, 이번엔 springboot+ JPA + handlebars + h2, postgreSql로 만들고 있어서 열심히 삽질하고 있다.과거의 내가 만들었던 허접한 게시판과 지금 진행중인 게시판을 비교하자면 굉장히 많은 변화가 있어서 나름 성장한 것 같다는 생각이 들기도 했다.오랜만에 처음부터 프로젝트를 만들고 설정을 잡고 이것저것 추가하고 그러한 작업이 스프링부트임에도 불구하고 거의 하루종일 했던 것 같다..그래도 최대한 기술부채 없이 하려고 나름대로 노력은 하고 있는데, 그렇게 한달 뒤에도 뿌듯한 프로젝트였으면 좋겠다. 다음달 초엔 해커톤을 나간다! 나는 스프링부트를 이용한 개발에 능숙한데(다른 프레임워크보다) 스프링부트는 스프링에 비해 설정 셋팅등이 간소화되었다고 해도 해커톤에서 쓰기엔 적합하지 않다고 생각한다.약간 소잡는 칼로 닭잡는 기분.. 그래서 가볍고 빠르게 개발할 수 있는 플라스크를 공부할 예정이다.최근에 했던 Sanic 토이프로젝트와 flask는 닮아있어서 배우는데에 큰 어려움이 없었음 좋겠다(본격 플라스크 벼락치기) 한달간 했던 것 Kotlin 학습 Scala 학습 시작 Kafka 환경잡고 써보기 Springboot 게시판 토이 프로젝트 다음주 목표 Springboot 게시판 토이 프로젝트 완성 JPA 강의 학습(인프런) Flask 학습","categories":[{"name":"Logs","slug":"Logs","permalink":"https://sehajyang.github.io/categories/Logs/"}],"tags":[{"name":"weekly","slug":"weekly","permalink":"https://sehajyang.github.io/tags/weekly/"}]},{"title":"spring camp 2019 참석 후기 (1부)","slug":"2019-04-29-springcamp-2019-review","date":"2019-04-28T15:00:00.000Z","updated":"2019-08-02T14:41:53.804Z","comments":true,"path":"2019/04/29/2019-04-29-springcamp-2019-review/","link":"","permalink":"https://sehajyang.github.io/2019/04/29/2019-04-29-springcamp-2019-review/","excerpt":"","text":"spring camp 2019를 다녀왔다!티켓팅이 정말 어려웠기 때문에, 지인이나 회사의 다른 개발자분이 티켓팅에 실패해서 혼자 다녀왔다.공개된 세션들은 지금 내가 개발하고 있는 프로젝트에 많은 도움이 될 것 같아서 정말 기대를 많이 했다.특히 실전에 써먹는 스프링부트 나 Monitoring With Actuator, 무엇을 테스트할 것인가? 어떻게 테스트할 것인가?, Kotlin 프로젝트를 피할 수 없을 때 라는 세션이 그러했다.최근 테스트를 내가 제대로 하고 있는지에 대한 의문이 있었고, 모니터링에 대한 필요성을 느끼고 있어서였다.Kotlin은 저번에 Springboot에 붙이려다 실패했었기 때문에 위의 세션이 기대가 됐다.세션은 오전 10:40 분 부터 시작했는데 가는길에 시간이 조금 걸려 조금 지각을 해버렸다.로비에 들어가니 팔찌와 스티커 그리고 휴대용 선풍기를 줬다(왜인지는 모르겠는데 많은 개발세미나에선 휴대용 선풍기를 준다)굿즈를 받아들고 Track 1의 실전에 써먹는 스프링부트를 들었다.중후반에 들어왔기 때문에 아쉽게 기록을 하지 못했다. 정말 아쉬웠다. Monitoring With Actuator두번째로 들은 세션은 Monitoring With Actuator 였다.보안에 대한 의문이 있었기 때문에 예전에 한번 도입하려다 그냥 포기했었는데, 이 세션에서 어떻게 사용해야 하며 모니터링을 도와주는 도구 및 팁과룰에 대한 다양한 설명을 들을 수 있었다.Actuator는 springboot 2.0 부터 사용할 수 있는데, 다행히 저번에 버전업을 해서 도입한다면 바로 도입할 수 있을 것 같았다. 1.5에서도 사용할 수 있지만 제약사항이 많았다. Spring Actuator 란? 장애 예방, 원인파악 및 조치, 상태확인, 성능개선, 서비스상태분석을 위함 제어 도구 = endpoint 지표 제공 = metrics 사용중인 라이브러리 탐지도 한다 default endpoint default 는 health, info 만 제공 properties에서 설정할 수 있다. Enabling Endpoints web > rest(health,info)로 보여줌 jmx > 셧다운 제외한 모든 정보를 보여줌 spring boot 2.0 부터 spring security에 통합 혹은 따로 서버에 띄우는 방법(총 두개)으로 사용 가능 접근 가능 ip 설정 가능 Metrics 2.0 부터 특정 지표상의 key value 쌍의 지표 tag로 검색 가능 반드시 측정해야 할 지표 (RED Method) (Request)Rate (Request)Error (Request)Duration outcome code => status 간단히 잘 볼수있음 Micrometer Registry, Meter, Tag spring boot 2.0부터 지원 meterregistry cloudwatch도 있음! 자바에서 null을 안전하게 다루는 방법세번째로 들은 세션은 자바에서 null을 안전하게 다루는 방법 이었다. 내 생각에, 자바에서 가장 많이 일어나는 Exception은 nullPointer exception이 아닐까 싶다.인기가 정말 많았던 세션이라 아쉽게도 좌석 부족으로 서서 들어 기록을 하진 못했지만 ppt가 공개되었다! ppt 링크너무 너무 유익한 세션이었다. 만약 해당 강연을 듣지 못한 분은 ppt를 보고 이 강연이 얼마나 유익했을지 알 수 있을거라 생각한다.해당 세션이 끝난 후 한시즈음 점심을 먹었다. 배달의 민족 측에서 준비한 도시락이었다. 보통 세미나에선 샌드위치를 주는데 한식을 줘서 좋았다 :D 무엇을 테스트할 것인가? 어떻게 테스트할 것인가?네번째 세션은 정말 기대하던 TDD 세션이었다. TDD라기보단 테스트 세션이었지만 그래서 더 좋았다.그간 인터넷을 찾아보며 나름대로 테스트코드를 작성해오고 있었는데, 맞게 작성하고 있는지, 이건 테스트해야되는지 이건 아닌지, 이걸 테스트하기엔 너무 어려운데 과연 의미가 있는지이건 불가능한 테스트인데 어떻게 해야 하는지에 대한 고민이 많았다.그래서 Udemy에서 Master Java Unit Testing with Spring Boot & Mockito 강의라도 들을까 하고 있던 차에, 한국에서! 그것도 실무자가 하고있는 스프링부트 테스트코드 강의라서 많은 기대가 됐다.그리고 이 세션은 그러한 내 많은 고민을 한번에 해결해 주었다! 그리고 나는 테스트코드를 맞게 짜고 있었다. 안도감이 들었다.강연 중간에 spock에 대한 언급이 있었는데, 생각보다 많은 분들이 사용하고 있어서 왠지 든든했다(?)spock는 정말 좋다. 처음엔 groovy가 낯설었지만 조금 적응이 되니 너무 편리했다. 테스트로부터 얻을 수 있는 것 안정감과 자신감 (정말 그렇다!) 대상은 나와 동료 무엇을 테스트 할 것인가 기존 플로우 안까지 할 필요없음 만약 걔를 테스트해야되면 걔를 빼는게 맞는거임 설계사항 그대로 테스트 코드로 옮기는게 좋음 테스트 가능한 것 불가능한 것 외부 API 테스트안됨(그렇다) 항상 성공할 수 있는것 동일한 결과가 나올 수 있는것을 테스트 어떻게 테스트 할 것 인가 바운더리 레이어까지 테스트안되는걸 끌어올려서 테스트 바운더리 레이어 = > 한 모듈로서의 의미를 지니는 가장 바깥쪽 springcontext의 오용은 언어의 본질을 망각하게 될 수 있다. Context, framework 종속적이지 않은 테스트를 우선 Test double 테스트 할 수 없는 영역을 주입해서 테스트할 수 있게 해줌 무엇을 test double로 처리해야할까 H2 뭐 그런거 써서 enbedded 활용 => 제어할 수 없던 그 영역을 제어할 수 있다! Endpoint Test Spring contract test tip 테스트는 상호 독립적으로 작성 공유되는 데이터는 꼭 초기화를 한다(테스트간 서로 영향을 끼치지않도록) => Dynamic Test (Junit5) 테스트 에서 의도와 목적이 드러나도록 테스트 코드도 리펙토링 대상 앞으로 테스트코드를 더 즐겁고 확신있게(?) 짤 수 있을 것 같다. 이후에 들은 세션은 당신도 할 수 있는 레거시 프로젝트 개선 이야기, Kotlin 프로젝트 적응하기 이다.Kotlin + Spring Data JPA 세션을 듣고싶었는데, 중간에 일이 생겨 아쉽게 마지막 세션을 들을 수 없었다.이전에 kotlin 프로젝트에 자바 라이브러리를 사용하려다 대차게 실패한 적이 있기 때문에 꼭 듣고 싶었다.해당글 : Kotlin 에서 Lombok을 사용할 수 없는 문제강연 영상이나 ppt가 공개되면 봐야겠다.","categories":[{"name":"Seminar","slug":"Seminar","permalink":"https://sehajyang.github.io/categories/Seminar/"}],"tags":[{"name":"seminar","slug":"seminar","permalink":"https://sehajyang.github.io/tags/seminar/"},{"name":"Springboot","slug":"Springboot","permalink":"https://sehajyang.github.io/tags/Springboot/"},{"name":"spring","slug":"spring","permalink":"https://sehajyang.github.io/tags/spring/"}]},{"title":"190408-190421 주간 회고","slug":"2019-04-21-190408~190421","date":"2019-04-20T15:00:00.000Z","updated":"2019-07-15T14:11:55.594Z","comments":true,"path":"2019/04/21/2019-04-21-190408~190421/","link":"","permalink":"https://sehajyang.github.io/2019/04/21/2019-04-21-190408~190421/","excerpt":"","text":"이번 2주간은 조금 슬럼프였던 것 같다.늘 그렇듯 공부해야할 건 많았고 그간 해왔던 것 처럼 어떤 공부를 먼저 할지 계획을 세우기만 하면 되는데, 갑자기 그 많던 투두 리스트가 전부 사라진 것 같았다.지금 이걸 하는게 맞는지, 이렇게 공부한게 맞는지, 알수가 없었고 클린코드를 읽으면 읽을수록 이해가 안됐다.특히 테스트 코드를 작성하면서 이렇게 하는게 맞는건가 하는 생각을 많이 했다. 국내 자료도 해외 자료도 적었고, 얻을 수 있는 자료는 기본적인 것임에 불과했다.슬프게도 우아한 형제들 TDD 세미나는 떨어졌으나 다행히 Spring camp 2019 의 티켓팅에 성공했으므로 제대로 Spring TDD 에 대해 들을 수 있을 것 같다. 이번에 Sanic 실시간 채팅 토이프로젝트를 진행하며, Redis를 처음 써봤다. RDB만 쓰던 내겐 굉장히 생소했으며, PUB/SUB기능은 충격적이었다.인메모리 디비가 너무 생소해 이해하는데에 고생을 했다! 그러던 차에 AWSKRUG에서 ElastiCache [Redis/Memcached] 서비스 알아보기 밋업이 있어서 참석하기로 했다. 파이썬으로 크롤링을 시작했다. Fiddler로 HTTP/HTTPS 패킷 분석하는 법 부터 배우고 있다.회사에선 크롤링에 있어 다른 개발자가 짠 것을 고치거나 수정하거나 하는 등의 간단한(?) 작업만 해왔기 때문에이번 기회를 통해 내가 원하는 사이트의 크롤링하는 스크립트를 온전히 짤 수 있게될 것을 기대하고있다. 2주간 했던 것 TDD 공부 Sanic 실시간 채팅 토이 프로젝트 파이썬 크롤링 클린코드 사내 스터디 발표 준비다음주 목표 Sanic web chatting project 이슈 몇가지 해결 Spring camp 2019 참석 AWSKRUG 밋업 참석 총평슬럼프가 와서 벗어나려 뭐라도 해보려고 했던 것 같다. 다음주에는 좀 더 깊이있는 공부를 하고싶다.","categories":[{"name":"Logs","slug":"Logs","permalink":"https://sehajyang.github.io/categories/Logs/"}],"tags":[{"name":"weekly","slug":"weekly","permalink":"https://sehajyang.github.io/tags/weekly/"}]},{"title":"비동기 기초 정리","slug":"2019-04-17-basic-of-asynchronous","date":"2019-04-16T15:00:00.000Z","updated":"2019-07-15T14:11:55.591Z","comments":true,"path":"2019/04/17/2019-04-17-basic-of-asynchronous/","link":"","permalink":"https://sehajyang.github.io/2019/04/17/2019-04-17-basic-of-asynchronous/","excerpt":"","text":"매주 목요일마다 진행하는 개발관련 사내스터디에서 비동기에 대한 발표를 들었는데 내용이 좋아서 정리를 했습니다.원본(발표자) 슬라이드는 이곳에 있고2부는 링크 에서 볼 수 있습니다 😄 1. IT Revolution 과 동시접속자 증가 직접회로를 쓰는 IC > PC > Internet > Mobile로 발전해나감. 그 과정에서 사용자의 폭발적인 증가 사용자의 증가 => 동시 접속자 증가 이를 해결하려면? 연산을 더 빠르게 하드웨어 Upgrade(램을 더 달거나, 코어를 늘리거나..), H/W 적인 해결 Low Level Language (어셈블러 C 등) => but 어렵고 힘듦, S/W 적인 해결 동시성을 늘린다 Parallelism (병렬 처리) => CPU 더 달아서 듀얼코어.., H/W 적인 해결 Concurrency (동시성) 2. Thread and Process Thread Process보다 적은 overhead와 자원 사용 => Process안에서 Thread 영역만(그 안엔 Stack 영역만이 존재) 생성하면 되기 때문 멀티코어 활용이 어려움 => 구현하려면 굳이 멀티코어로 해줘야 됨(알아서 안해줌) Data 공유가 쉬움 공유 자원(양날의 검) Process Thread보다 더 많은 자원 사용(cpu, memory) 사용, 생성시 Code, Data, Stack, Heap영역을 다 만듦 멀티코어를 활용할 수 있음 => OS가 멀티코어를 알아서 해줌 Data 동기화가 어려움 3. Deadlock생략 추천도서 : 7가지 동시성 모델 4. Sub Routine 과 Coroutine 서브루틴 (Sub Routine) 루틴이 다 끝날 때 까지 아무것도 못함 (리턴할 때 까지 대기해야됨) 함수, 메소드 코루틴 (Coroutine) 루틴 진행 중간에 멈춰서 특정 위치로 돌아갔다가 다시 원래 위치로 돌아와 나머지 루틴을 실행 비동기와 결합하면 더 강력해진다 5. 동기(Synchronous)와 비동기(Asynchronous) 동기 sync를 맞추다 모든 루틴을 순차적으로 진행 시간관계를 동시에 또는 동일하게 유지하는 처리방식 (but 시간관계 는 어떠한 관점으로 보느냐에 따라 다름) 비동기 sync를 맞추지 않아도 되는 처리 방식 (맞출수도 아닐수도 있다) 몇몇 루틴을 비순차적으로 진행할 수도 있음 즉, 무조건 sync 다 맞추지 않아야 비동기! 이건 아님 다양한 곳에서 동기와 비동기를 활용 Serial 통신에서 활용 동기 : 클럭에 맞춰 시작과 끝 비동기: 시작과 끝을 정함 (ex)101로 시작하고 001로 끝내라) CPU 연산에서 활용(pipelining) 6. Non-block 프로세스를 비동기식으로 만들기 위해서 등장 Block 함수가 끝날 때 까지 기다림 함수의 결과를 return 함 Non Block 함수를 바로 return 함 함수의 결과를 따로 저장함 Main이 Non-block Object에 주기적으로 결과리턴을 물어봄(물어보는 건 blocking function) 리턴이 False면 기다리지않고 다른 작업을 하고 또 물어봄 리턴이 True가 되면 Non-block Object는 result를 보냄 이 과정에서 언제 끝나는지 계속 물어보는 게 필요함 => Event Loop 7. Event Loop 외부 환경에서 이벤트를 받음 이벤트 발생하면 해당 이벤트에 대한 루틴을 실행시킴 8. Non block + Event Loop → Async Non block 함수가 완료되었는지 아닌지 검사하는 event loop 작업이 완료된지 아닌지를 주기적으로 물어봄 더 효율적인 Async Loop는 어떤 작업의 상태가 바뀌었는지 select 한다 더더 효율적인 Async Loop는 작업의 상태가 바뀌면 event loop에게 알려준다(커널이 지원해줘야됨) Observer Pattern? 이런것들을 I/O multiplexing 기술들이라 한다. 9. Async Async loop에 non block이 아닌 block 함수가 들어오면? Block 함수가 실행되는 동안 event loop가 멈춘다 => 성능저하 Block 함수를 Thread나 Process로 concurrency하게 실행해서 non block처럼 만든다 But 공유자원 접근의 위험 발생 => deadlock 블라블라.. 코루틴! 10. Coroutine + Async 코루틴은 루틴 실행하고 중단했다가 다시 시작할 수 있다 동시성(concurrent) 구현 Single Thread에서 실행되기 때문에 shared data 접근 충돌 걱정이 사라짐 동시성이 있지만 또 다른 thread나 process 만들 필요가 없음 메모리 save Thread, Process를 만드는 것에 대한 오버헤드가 없음 But Blocking 함수 또는 CPU Bound 작업을 할 때 성능이 저하됨 한 작업을 할때 다른 작업을 처리할 수 없기 때문 따라서 Blocking 함수는 thread로 처리 그 Blocking 함수가 공유자원을 참조해야 하는 경우에는 동시성에 대한 지식 및 S/W 적 안전장치 마련해야됨 11. CPU Bound, IO Bound CPU Bound : 연산이나 처리량이 많은 경우 문자열 연산, 사칙연산, 영상/이미지 처리 동시성을 늘리려면 돈을 더 붓던가(h/w 업그레이드), 저급 언어로 코딩 I/O bound : 입력과 출력이 많은 경우 12. 언제 비동기를 써야할까 처리순서의 시간관계가 관련이 없는 작업이 많을 때 I/O 작업이 많을때 여러개 작업을 처리해야 할 때 궁금한 점 혹은 오류등은 아래 코멘트에 남겨주세요 😄","categories":[{"name":"Async","slug":"Async","permalink":"https://sehajyang.github.io/categories/Async/"}],"tags":[{"name":"asynchronous","slug":"asynchronous","permalink":"https://sehajyang.github.io/tags/asynchronous/"}]},{"title":"Kakao Geocode API, 주소로 위도 경도 java로 파싱하기","slug":"2019-04-17-kakao-api-geocode-parsing","date":"2019-04-16T15:00:00.000Z","updated":"2019-08-02T14:41:53.803Z","comments":true,"path":"2019/04/17/2019-04-17-kakao-api-geocode-parsing/","link":"","permalink":"https://sehajyang.github.io/2019/04/17/2019-04-17-kakao-api-geocode-parsing/","excerpt":"","text":"Kakao Geocode API로 부터 받은 데이터를 직렬화 하고 JSON객체로 바꾸고 특정 데이터를 얻어오는 작업을 할 것입니다.Kakao API를 이용하기 위해선 API Key가 필요한데, 이곳 에서 얻을 수 있습니다. 카카오 지도 API로부터 주소로 위도 경도를 받아오기 위해선 이곳에 공식 예제가 있습니다. 받아온 주소 데이터를 JSON으로헤더에 발급받은 API키를 등록 후 POSTMAN으로 요청을 날려보겠습니다. https://dapi.kakao.com/v2/local/search/address.json?query=판교역로 235 응답받은 데이터는 이러합니다. 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647{ \"meta\": { \"is_end\": true, \"total_count\": 1, \"pageable_count\": 1 }, \"documents\": [ { \"road_address\": { \"undergroun_yn\": \"N\", \"road_name\": \"판교역로\", \"underground_yn\": \"N\", \"region_2depth_name\": \"성남시 분당구\", \"zone_no\": \"13494\", \"sub_building_no\": \"\", \"region_3depth_name\": \"삼평동\", \"main_building_no\": \"235\", \"address_name\": \"경기 성남시 분당구 판교역로 235\", \"y\": \"37.40209529907863\", \"x\": \"127.10863694633468\", \"region_1depth_name\": \"경기\", \"building_name\": \"에이치스퀘어 엔동\" }, \"address_name\": \"경기 성남시 분당구 판교역로 235\", \"address\": { \"b_code\": \"4113510900\", \"region_3depth_h_name\": \"삼평동\", \"main_address_no\": \"681\", \"h_code\": \"4113565500\", \"region_2depth_name\": \"성남시 분당구\", \"main_adderss_no\": \"681\", \"sub_address_no\": \"\", \"region_3depth_name\": \"삼평동\", \"address_name\": \"경기 성남시 분당구 삼평동 681\", \"y\": \"37.40206645815382\", \"x\": \"127.10864594007738\", \"mountain_yn\": \"N\", \"zip_code\": \"463400\", \"region_1depth_name\": \"경기\", \"sub_adderss_no\": \"\" }, \"y\": \"37.40209529907863\", \"x\": \"127.10863694633468\", \"address_type\": \"ROAD_ADDR\" } ]} 위의 데이터에서 Y 좌표 값과 X 좌표값이 필요하기 때문에 해당 데이터만 가져오도록 하겠습니다. 우선 KAKAO 지도 API로 요청을 보내고 응답을 받습니다. 1234567891011String APIKey = \"발급받은 API 키\"; HashMap<String, Object> map = new HashMap<>(); //결과를 담을 maptry { String apiURL = \"https://dapi.kakao.com/v2/local/search/address.json?query=\" + URLEncoder.encode(address, \"UTF-8\"); HttpResponse<JsonNode> response = Unirest.get(apiURL) .header(\"Authorization\", APIKey) .asJson(); 받아온 데이터를 JSON 객체로 변환하기 위해 ObjectMapper를 사용합니다. 12ObjectMapper objectMapper = new ObjectMapper();objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true); 위의 objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true); 는단일 리스트 객체를 싱글 값과 같게 인식합니다.ex) "fruits" : ["apple"] 를 "fruits" : "apple" 로 인식 지정된 VO에 응답받은 데이터를 셋팅지정된 형식에 잘 셋팅하기 위해 1KakaoGeoRes bodyJson = objectMapper.readValue(response.getBody().toString(), KakaoGeoRes.class); KakaoGeoRes에 응답받은 데이터를 잘 셋팅하도록 합니다. 123456789101112131415@Datapublic class KakaoGeoRes { private HashMap<String, Object> meta; private List<Documents> documents;}@Dataclass Documents { private HashMap<String, Object> address; private String address_type; private Double x; private Double y; private String address_name; private HashMap<String, Object> road_address;} X, Y값만 필요했기 때문에 위와 같이 작성했습니다.key가 응답받은 데이터와 다르면 에러가 나기 때문에 사용하지 않는 key 도 선언합니다. X,Y 값에 접근그 후 12bodyJson.getDocuments().get(0).getX()bodyJson.getDocuments().get(0).getY() 위와같이 접근할 수 있습니다. 읽어주셔서 감사합니다.혹 오류나 질문이 있다면 편하게 코멘트 부탁드리겠습니다!🙆♂️","categories":[{"name":"Java","slug":"Java","permalink":"https://sehajyang.github.io/categories/Java/"}],"tags":[{"name":"Java","slug":"Java","permalink":"https://sehajyang.github.io/tags/Java/"}]},{"title":"프로젝트 내의 특정 문자 를 전부 삭제하는 법","slug":"2019-04-12-find-and-replace-all-string","date":"2019-04-11T15:00:00.000Z","updated":"2019-07-15T14:11:55.590Z","comments":true,"path":"2019/04/12/2019-04-12-find-and-replace-all-string/","link":"","permalink":"https://sehajyang.github.io/2019/04/12/2019-04-12-find-and-replace-all-string/","excerpt":"","text":"인텔리제이에서 프로젝트 내의 특정 소스를 전부 삭제해야 될 일이 있을 땐Shift + Ctrl + R위는 없앨 대상 소스를 작성하고, 아래는 그대로 놔두고 하단의 replaceAll 을 누르면 된다.","categories":[{"name":"Tip","slug":"Tip","permalink":"https://sehajyang.github.io/categories/Tip/"}],"tags":[{"name":"IntelliJ","slug":"IntelliJ","permalink":"https://sehajyang.github.io/tags/IntelliJ/"}]},{"title":"190325-190407 주간 회고","slug":"2019-04-07-190325~190407","date":"2019-04-06T15:00:00.000Z","updated":"2019-07-15T14:11:55.589Z","comments":true,"path":"2019/04/07/2019-04-07-190325~190407/","link":"","permalink":"https://sehajyang.github.io/2019/04/07/2019-04-07-190325~190407/","excerpt":"","text":"2주간 나에게 있어 가장 의미가 컸던 일은 일부지만 프로덕션에 테스트코드를 작성해 기존 코드들에 대한 테스트를 진행한 것 과 클린코드를 읽은 일 이었다.그간 TDD라던가 테스트 코드 작성에 대해 내가 아는 것 이라곤 assertThat이 전부였다.이 세상엔 TDD라는게 있고 핫하고 그걸 해야하고 그 정도로만 막연하게 느끼고 있었는데, 테스트코드를 작성 할 기회가 생겨 이것저것 찾아보며 작성 할 수 있었다.막연하게 알던 Mock 이라던가, 단위테스트라던가 통합테스트에 대해서 알 수 있었고 이젠 능숙하진 않지만 테스트코드를 작성 할 수 있게 되었다.특히 MVC 통합테스트를 하고 있을때 Post로 파라미터가 넘어가지 않는 이슈가 있었는데 개발하자 라는 슬랙 방 에서 도움 을 받아 며칠동안 고민하던 단번에 해결할 수 있었다! 클린코드를 드디어 읽었다.클린코드는 언젠간 꼭 읽어봐야지 라고 생각했었던 개발 관련 도서 중 하나였다.어떻게 함수를 작성하면 좋은지 네이밍은 어떻게 주석은 어떻게 해야되는지, 어떻게 작성하는게 독자(내 코드를 읽는 다른 개발자)에게 좋은 코드인지, 어떻게 얽혀져 있는 스파게티같은 소스를 분리해야 되는지에 대한 내용이 담겨 있다.이 책의 내용이 너무 충격적이다! 이건 새로알게된 엄청난 것 이다! 라는 부분은 별로 없다. 한번 쯤 정리가 있었으면 좋겠다고 생각했던 규칙같은 것을 정리해 둔 책 이다.아직 다 읽진 못했지만 이걸 읽고 내가 그간 작성해온 코드들이 얼마나 잘못 됐었는지, 어떤 실수를 하고 있었는지 알 수 있었다.이 책은 내 코딩 습관들을 정말 많이 바꿔 놓을 것 같다. 2주간 했던 것 Gitlab CI Beanstalk 배포(jenkins 연동) sentry 프로덕션에 적용 springboot version migraion(1.5 > 2.x) springboot 테스트코드 작성(JUnit, Spock) 클린코드 읽기(진행중) 다음주 목표 Sanic web chatting project 이슈 몇가지 해결 총평더 나은 코드 및 품질에 대해 고민하고 개선했던 주 였던 것 같다.GitLab의 GitLab CI yml 파일을 작성해 자동 배포를 구현했고, Jenkins을 이용해 Beanstalk으로도 빌드 후 자동 배포를 구현할 수 있었고, springboot 프로덕션의 메이져 버전 업을 할 수 있었다.테스트 코드 작성과 클린코드를 읽은 건 내게 큰 의미가 있었다!아직 클린코드를 다 읽지 못했지만 뒷 내용도 기대가 된다.","categories":[{"name":"Logs","slug":"Logs","permalink":"https://sehajyang.github.io/categories/Logs/"}],"tags":[{"name":"weekly","slug":"weekly","permalink":"https://sehajyang.github.io/tags/weekly/"}]},{"title":"Springboot 에서 test code 작성하기 2편 - assetThat이 중복되는 테스트와 Spock","slug":"2019-04-05-springboot-test-code-3","date":"2019-04-04T15:00:00.000Z","updated":"2019-11-16T08:45:45.556Z","comments":true,"path":"2019/04/05/2019-04-05-springboot-test-code-3/","link":"","permalink":"https://sehajyang.github.io/2019/04/05/2019-04-05-springboot-test-code-3/","excerpt":"","text":"Springboot 에서 test code 작성하기 시리즈 Springboot 에서 test code 작성하기 1편 - 통합테스트(MVC) Springboot 에서 test code 작성하기 2편 - assetThat이 중복되는 테스트와 Spock 이전포스팅에선 통합테스트 작성에 대해서 알아봤습니다.이번 포스팅에선 spock 프레임워크를 사용해 중복되는 테스트케이스를 가독성 좋게 변경하는 방법을 알아보겠습니다. 1. 그 외의 메소드 테스트와 Spock프로덕션엔 CommonUtil이라는 클래스가 있습니다. 그 클래스엔 문자열을 조작한다던가, 리스트를 조작하거나 어떠한 값을 검증하는 등의 메소스들이 있는데 그 클래스 내의 메소드들이 잘 동작하는지 테스트하기 위해선 많은 assertThat 이 필요했고, 그러한 중복코드를 없애기 위해 검색을 하던 중 Spock 소개 및 튜토리얼라는 튜토리얼을 보게 되었습니다. BDD(Behaviour-Driven Development)는 TDD가 진화한 테스트 코드 작성 방식이며사람이 쉽게 이해하기 쉬운 작성, 즉 테스트의 동작 및 의도를 직관적으로 알 수 있다는 장점이 있습니다.Spock는 groovy 로 작성된 프레임워크인데 JVM에서 실행되며 테스팅을 하기 위한 BDD 프레임워크입니다.따라서 Given-When-Then-Expect_Where 로 시나리오를 작성하게 됩니다.또한 테스트 실패 시 상세하게 이유가 출력 됩니다 예를들어 특정 시간의 예약 가능 여부를 True/False 로 리턴하는 checkReserveYN 라는 함수가 있다고 가정해보겠습니다.일반적으론 그 함수를 테스트 할 때 1234567891011@Testpublic void Test() { boolean data1 = CommonUtil.checkReserveYN(\"월요일 09:00~19:00, 토요일 13:00~16:00\"); assertTrue(data1); boolean data2 = CommonUtil.checkReserveYN(\"금요일 09:00~24:00\"); assertTrue(data2); boolean data3 = CommonUtil.checkReserveYN(\"월,화 13:00~16:00\"); assertTrue(data3);} 이렇게 작성하게 되는데 테스트 케이스 하나를 만들 때 마다 중복이 발생하고 있는 것을 알 수 있습니다.하지만 spock를 사용해 이러한 중복을 해결할 수 있습니다. 1234567891011@Unrolldef \"#time 시간의 예약 가능 여부 : #result\"() { expect: result as Boolean == CommonUtil.checkReserveYN(time as String) where: time | result \"월요일 09:00~19:00,토요일 13:00~16:00\" | true \"금요일 09:00~24:00\" | false \"월,화 13:00~16:00\" | true} @Unroll 어노테이션은 메소드 명에 where의 객체값을 대입해 테스트를 수행해 위의 테스트의 결과는이렇게 나타납니다. 만약 테스트가 실패한 경우 아래와 같이 상세하게 테스트 실패 이유를 출력해줍니다.또한 request 나 session값 등은 메소드 필드에 그냥 선언해서 사용할 수 없습니다.따라서 다음과 같이 사용하면 안됩니다. 1234567891011121314def \"세션 Id가 없으면 false를 리턴해야한다\"() { given: MockHttpSession session = null MockHttpSession sessionNossId = null session.setAttribute(\"ssId\", \"1\") expect: result as boolean == CommonUtil.SessionIdCheck(ss as MockHttpSession) where: ss | result session | true sessionNossId | false} 위 코드는 groovy.lang.MissingPropertyException : No such property session 가 발생합니다.생성한 session 객체를 공유 하기 위해선 @shared 어노테이션을 사용하거나 static 변수로 선언하는 방법이 있습니다.@shared는 메소드간의 객체를 공유할 수 있게 해줍니다.하지만 공유 객체를 만들고 사용하는 것 보다 더 좋은 방법이 있습니다. 12345678910111213def \"세션 Id가 없으면 false를 리턴해야한다\"() { expect: result as boolean == CommonUtil.SessionIdCheck(ss as MockHttpSession) where: ss << { MockHttpSession session = new MockHttpSession() MockHttpSession sessionNossId = new MockHttpSession() session.setAttribute(\"sessionId\", \"1\") [session, sessionNossId] }() result << [true, false]} where 내 에서 session 객체를 생성합니다.위와 같이 작성하면 @shared 없이 깔끔하게 코드를 작성할 수 있습니다.또한 result << [_,false] 등으로 무시할 수 있습니다.자세한 내용은 [더 알아보기] 에서 확인할 수 있습니다. 혹 틀린 부분 혹은 궁금한 점이 있다면 코멘트 남겨주세요. 읽어주셔서 감사합니다🙏 참고자료 Spock Framework Reference Documentation Spock 소개 및 튜토리얼 Spock으로 테스트코드를 짜보자","categories":[{"name":"Spring","slug":"Spring","permalink":"https://sehajyang.github.io/categories/Spring/"}],"tags":[{"name":"Springboot","slug":"Springboot","permalink":"https://sehajyang.github.io/tags/Springboot/"},{"name":"TDD","slug":"TDD","permalink":"https://sehajyang.github.io/tags/TDD/"}]},{"title":"Springboot 에서 test code 작성하기 1편 - 통합테스트","slug":"2019-04-05-springboot-test-code-1","date":"2019-04-04T15:00:00.000Z","updated":"2019-11-16T08:45:45.552Z","comments":true,"path":"2019/04/05/2019-04-05-springboot-test-code-1/","link":"","permalink":"https://sehajyang.github.io/2019/04/05/2019-04-05-springboot-test-code-1/","excerpt":"","text":"Springboot 에서 test code 작성하기 시리즈 Springboot 에서 test code 작성하기 1편 - 통합테스트(MVC) Springboot 에서 test code 작성하기 2편 - assetThat이 중복되는 테스트와 Spock 최근사내 프로젝트에서 테스트 코드를 작성하고자 생각했습니다.목표는 해당 컨트롤러의 메소드가 잘 동작하는지(요청을 잘 보내고 예상한 응답을 잘 받는지), 서비스가 개별적으로 잘 동작하는지 확인하는 것 입니다.컨트롤러는 운영 환경과 비슷하게 테스트 하기 위해 통합 테스트, 서비스는 의존성을 줄이고 해당 서비스의 목표에만 집중하기 위해 단위테스트를 하기로 결정했습니다. 테스트에 관한 글을 찾아보던 중 우아한형제들 기술블로그에서 테스트 메소드의 이름을 한글로 짓는다는 것을 알게 되었습니다.테스트가 실패했을 때 어느 기능에서 오류가 났는지 직관적으로 알 수 있어 좋은 것 같아서 테스트 메소드 명을 한글로 작성했습니다. 1. MVC 컨트롤러 통합 테스트목표는 고객 정보를 조회 및 등록하는 메소드를 통합테스트 하는 것 입니다.컨트롤러 통합 테스트는 클래스 상단에 @SpringbootTest 을 선언합니다.모든 Bean을 올리는 것으로 다른 테스트에 비해 테스트 시간이 오래 소요되지만 운영환경과 비슷하게 테스트 할수 있습니다.선언한 어노테이션은 다음과 같습니다: 어노테이션 설명 @RunWith(SpringRunner.class) 테스트를 실행하기 위해 참조하는 클래스(SpringRunner) @AutoConfigureWebMvc MVC와 관련된 Bean을 올린다 @Transactional 테스트 후 DB 롤백 @Ignore 실제로 실행할 필요가 없기 때문에 Ignore를 선언 @SpringBootTest 모든 Bean을 올리는 통합 테스트 123456789101112131415161718192021222324252627/** * @author sehajyang * @date 2019-04-05 */@RunWith(SpringRunner.class) @AutoConfigureWebMvc @Transactional @Ignore @SpringBootTest public class CustomerControllerTest { @Autowired private MockMvc mvc; @Autowired private WebApplicationContext webApplicationContext; @SpyBean private CustomerService customerService; @Autowired private ObjectMapper objectMapper; private MockHttpSession session = new MockHttpSession(); private MockHttpServletRequest request = new MockHttpServletRequest(); @SpyBean은 해당 객체를 주입받아 사용하다 given을 주면 선언한 해당 기능으로 동작하는 Bean 입니다.해당 어노테이션은 [SpringBoot @MockBean, @SpyBean 소개] 포스팅에서 더 자세히 알 수 있습니다. 고객정보를 조회 및 등록하는 메소드가 있는 도메인 인 CustomerController 가 있습니다.아래 코드는 예시입니다. 12345678910111213141516171819202122232425262728293031@Controller@RequestMapping(\"customer\")public class CustomerController { @Autowired CustomerService customerService; @GetMapping(\"\") public ModelAndView getCustomerList(HttpSession session, HttpServletRequest request){ ModelAndView mav = new ModelAndView(\"customerListPage\"); List<Customer> customerList = customerService.getCustomerList(); mav.addObject(\"customerList\", customerList); return mav; } @PostMapping(\"\") public Object regCustomerData(@RequestBody Customer customer, HttpSession session, HttpServletRequest request){ // 기존에 해당 유저가 있는지 확인후 등록하는 메소드 int userExist = shopService.getCustomerByCustno(customer.getCustno(1)); int result; if(userExist < 1){ return Constant.RESULT_FAIL; }else{ result = shopService.regCustomerData(customer); } return (result > 0) ? Constant.RESULT_SUCCESS : Constant.RESULT_FAIL; }} 코드상엔 없지만 CustomerController의 모든 메소드의 session과 header에는 특정 값이 셋팅되어 있어야 한다고 가정합니다.따라서 위 getCustomerList 를 테스트 하는 코드는 다음과 같습니다: 123456789101112131415161718192021222324252627282930313233343536373839404142434445@Before //테스트 수행시 실행 public void setUp() { //Integration Test this.mvc = MockMvcBuilders.webAppContextSetup(webApplicationContext) .dispatchOptions(true) //HTTP TRACE 요청을 디스패치할지 여부를 설정 (default는 false) .alwaysDo(print()) .build(); session.setAttribute(\"Id\", \"셋팅 값\"); request.addHeader(\"X-FORWARDED-FOR\", \"셋팅 값\"); } @Test public void 고객리스트_조회가_정상적으로_되어야한다() throws Exception { List<Customer> customerList = customerService.getCustomerList(); this.mvc.perform(get(\"/customer\") .session(session) .header(\"X-FORWARDED-FOR\", request.getHeader(\"X-FORWARDED-FOR\")) ) .andExpect(status().isOk()) // 200 return .andExpect(view().name(\"customerListPage\")) // 리턴할 view page name .andExpect(model().attribute(\"customerList\", customerList)); // 리턴할 model attribute name // redirect 리턴일 경우 //.andExpect(redirectedUrl(\"/\")) //.andExpect(status().is3xxRedirection()) } @Test public void 고객정보_등록이_예외없이_되어야한다() throws Exception { Customer customer = new Customer(\"1\",\"sehajyang\"); // Customer(custno, custname) given(customerService.getCustomerByCustno(customer.getCustno())).willReturn(1); // getCustomerByCustno 의 result는 1을 리턴 this.mvc.perform(post(\"/customer\") .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(customer)) // JSON으로 만들어준다 .session(session) .header(\"X-FORWARDED-FOR\", request.getHeader(\"X-FORWARDED-FOR\")) ) .andExpect(status().isOk()) .andExpect(content().string(\"SUCCESS\")) .andReturn() .getResponse(); } 그 밖에도 param() 등 으로 파라미터를 넘길수도 있습니다.이렇게 Controller를 통합테스트 를 실행해 전체 플로우를 테스트 할 수 있습니다. @SessionAttributes를 사용하는 방법도 있는데 이 경우엔 테스트 코드에서 requestAttr() 대신 sessionAttr()을 사용할 수 있습니다.이 방법은 이곳의 예제로 확인할 수 있습니다. 만약 123@PostMapping(\"\")public Object regCustomerData(Customer customer, HttpSession session, HttpServletRequest request){ 이렇게 DTO에 @RequestBody가 없는 도메인을 테스트하려면 조금 복잡해집니다.저의 경우, 회사 코드의 POST 도메인 파라미터 DTO에 일부 @RequestBody가 없었고, @RequestBody를 추가 할 경우 문제가 생길 수 있었기 때문에기존 코드를 변경하지 않고 테스트 하는 방법을 찾아보았습니다. 우선 Spring에서는 권장하지 않습니다 그 이유는 다음과 같습니다. 통합 테스트의 주 목적 중 하나는 MockMvc 모델 객체가 Object 데이터로 바뀌었는지 확인하는 것 입니다.NewObject(DTO)를 자동으로 변환하면 NewObject(DTO)가 실제 form과 호환되지 않는 문제가 있는데, 이러한 문제가 있는 파라미터는 테스트에서 제외되기 때문에 NewObject(DTO)는 Null이 됩니다. 그래서 @RequestBody가 없는 도메인의 DTO 파라미터는 십중팔구 넘어가지 않으며 null이 됩니다.이것을 해결하기 위한 방법은 두가지 정도가 있습니다. HttpClient 사용1234567891011121314151617@Test public void 고객정보_등록이_예외없이_되어야한다() throws Exception { Customer customer = new Customer(\"1\",\"sehajyang\"); // Customer(custno, custname) given(customerService.getCustomerByCustno(customer.getCustno())).willReturn(1); // getCustomerByCustno 의 result는 1을 리턴 this.mvc.perform(post(\"/customer\") .contentType(MediaType.APPLICATION_FORM_URLENCODED) .content(EntityUtils.toString(new UrlEncodedFormEntity(Arrays.asList( new BasicNameValuePair(\"custno\", \"1\"), new BasicNameValuePair(\"custname\", \"sehajyang\") ))))) .andExpect(status().isOk()) .andExpect(content().string(\"SUCCESS\")) .andReturn() .getResponse(); } buildUrlEncodedFormEntity() 이용1234567891011121314151617181920212223242526272829303132333435363738394041@Test public void 고객정보_등록이_예외없이_되어야한다() throws Exception { Customer customer = new Customer(\"1\",\"sehajyang\"); // Customer(custno, custname) given(customerService.getCustomerByCustno(customer.getCustno())).willReturn(1); // getCustomerByCustno 의 result는 1을 리턴 this.mvc.perform(post(\"/customer\") .contentType(MediaType.APPLICATION_FORM_URLENCODED) .contentType(MediaType.APPLICATION_FORM_URLENCODED) .content(buildUrlEncodedFormEntity( \"custno\",\"1\", \"custname\",\"sehajyang\" )))) .andExpect(status().isOk()) .andExpect(content().string(\"SUCCESS\")) .andReturn() .getResponse(); }private String buildUrlEncodedFormEntity(String... params) { if( (params.length % 2) > 0 ) { throw new IllegalArgumentException(\"Need to give an even number of parameters\"); } StringBuilder result = new StringBuilder(); for (int i=0; i<params.length; i+=2) { if( i > 0 ) { result.append('&'); } try { result. append(URLEncoder.encode(params[i], StandardCharsets.UTF_8.name())). append('='). append(URLEncoder.encode(params[i+1], StandardCharsets.UTF_8.name())); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } } return result.toString(); } 위와 같이 작성하시면 NewObject(DTO)에 값이 셋팅되어 파라미터로 잘 전달되는 것을 확인할 수 있습니다.관련 내용은 Testing Form posts through MockMVC에서 더 자세히 알아보실수 있습니다. 위 시리즈는 2부로 나뉘어 통합테스트, spock를 사용한 테스트로 작성 될 예정입니다.많이 미숙하지만 지속적으로 알아가고 있습니다.혹 틀린 부분 혹은 궁금한 점이 있다면 코멘트로 남겨주세요. 읽어주셔서 감사합니다🙏 참고자료 Mokito 공식 문서 Mokito github wiki Yun 님의 Test Guide","categories":[{"name":"Spring","slug":"Spring","permalink":"https://sehajyang.github.io/categories/Spring/"}],"tags":[{"name":"TDD","slug":"TDD","permalink":"https://sehajyang.github.io/tags/TDD/"}]},{"title":"190311-190324 2주간 회고","slug":"2019-03-24-190311~190324","date":"2019-03-23T15:00:00.000Z","updated":"2019-07-15T14:11:55.587Z","comments":true,"path":"2019/03/24/2019-03-24-190311~190324/","link":"","permalink":"https://sehajyang.github.io/2019/03/24/2019-03-24-190311~190324/","excerpt":"","text":"2주간 토이 프로젝트인 파이썬 실시간 채팅서버 작업을 했고, 알고리즘을 풀었다.3/16일엔 코무에서 주최한 프론트엔드와는 무관합니다만, 을 다녀왔었다.사내에선 jenkins를 서비스중인 라이브 프로젝트에 적용해 특정 브랜치에 push or merge request accept 이벤트가 발생하면 빌드 후 배포 및 slack 알림이 가능하게 되었고, sentry도 붙여봤다. 파이썬 실시간 채팅 프로젝트는 설계를 잘 못해서 유저 간 채팅 기능을 추가하려하자 구조적으로 문제가 있어서 전부 다시 뜯어고쳤다.다행히 잘 해결되었고, 이제 asyncio-redis를 보며 적용할 생각인데 그냥 처음부터 redis를 쓸걸 하는 후회가 된다.. 알고리즘은 프로그래머스의 (2017년)KAKAO BLIND RECRUITMENT를 풀고 있다.그 중 이 문제는 정규식을 잘 만들어야되는 문제였는데 과거의 나라면 못 했을 것이다.하지만 이젠 어느정도는(?) 정규식을 짤 수 있어서 기뻤다. 프론트엔드와는 무관합니다만, 세미나는 정말 좋았다. 특히 ES10 변경점을 설명한 세션과 vue의 Virtual DOM에 대한 세션이 좋았다.이러이러한 변경점이 있습니다 하고 끝나지 않을까 조금 걱정했었는데, 그런 걱정이 무색하게 어느정도 깊이있고 좋은 내용이었다.observer pattern이나 generator 에 대한 이해가 있으면 더 즐겁게 들을 수 있었다.필기를 하면서 들었으면 좋았을텐데 아쉽게도 필기를 하지 못했다.다음에 또 참석하게 된다면 그땐 필기를 하며 들을 생각이다. 세미나를 다녀온 뒤 알고리즘을 풀다 flatten을 할 일이 있었다. 세미나에서 들었던 es10의 변경점 중 하나인 flatten 은 쉽게말해 배열을 펴는 건데, 그 중 flat(Infinity)는 다중 배열도 1차원 배열로 펼 수 있다. 123const array = ['a', ['b', ['c', 'd'], 'e' ]array.flat(); // ['a', 'b', Array(2), 'e']array.flat(Infinity); // ['a','b','c','d','e'] 파이썬에 flat(Infinity)같은 건 없없지만 itertools를 활용하니 비슷하게 해결할 수 있었다! 참고 링크 2주간 했던 것 Python 으로 알고리즘 문제 몇 개 Sanic web chatting project 프론트엔드와는 무관합니다만, 참석 Jenkins Sentry blog 페이징 이슈 해결 다음주 목표 Sanic web chatting project 현재 열려있는 이슈들 해결 Python 으로 알고리즘 문제 몇 개 계속 총평이번주는 나름대로 그간 성장해왔음을 알 수 있었던 주 였던 것 같다! 예를들면 알고리즘을 풀며 느꼈고, 세미나를 듣는데 전보다 이해를 할 수 있을때 느꼈고, 도큐먼트와 라이브러리를 까보며 문제를 해결했을 때 느꼈고, 묵혀뒀던 블로그 관련 이슈들을 하나씩 고쳐가며 느꼈다. 과거에 할 수 없을거라 느꼈던 것을 해결하거나 할 수 있게 되었을때의 순간이 있는데 그게 내가 개발을 좋아하는 큰 이유중 하나라는 생각이 들었다.","categories":[{"name":"Logs","slug":"Logs","permalink":"https://sehajyang.github.io/categories/Logs/"}],"tags":[{"name":"weekly","slug":"weekly","permalink":"https://sehajyang.github.io/tags/weekly/"}]},{"title":"gitlab에 이미 push된 commit 삭제","slug":"2019-03-11-git-reset-push","date":"2019-03-10T15:00:00.000Z","updated":"2019-07-15T14:11:55.587Z","comments":true,"path":"2019/03/11/2019-03-11-git-reset-push/","link":"","permalink":"https://sehajyang.github.io/2019/03/11/2019-03-11-git-reset-push/","excerpt":"","text":"gitlab, github등에 취소해야 되는 commit이 있는데 이미 push 해버렸을 때git bash에서 1git reset --hard 되돌아가고자 하는 커밋주소 커밋 주소는 git log 로 알 수 있다 reset 옵션으론 hard, soft, mixed 가 있다 링크 그 후 1git push origin +브랜치명 브랜치 명 앞에 +를 붙여야 한다(덮어씌운다는 의미)+ 없이 push 해버리면 최근 커밋을 pull 하라며 에러가 난다. 만약 1! [remote rejected] master -> master (pre-receive hook declined) 이런 에러가 났다면 해당 project settings > Repository > Protected Branches에서 unprotected로 해당 브랜치를 설정해주면 된다 (보통 master에 걸려있음)","categories":[{"name":"Git","slug":"Git","permalink":"https://sehajyang.github.io/categories/Git/"}],"tags":[{"name":"git","slug":"git","permalink":"https://sehajyang.github.io/tags/git/"}]},{"title":"190225-190310 2주간 회고","slug":"2019-03-10-190225~190310","date":"2019-03-09T15:00:00.000Z","updated":"2019-07-15T14:11:55.585Z","comments":true,"path":"2019/03/10/2019-03-10-190225~190310/","link":"","permalink":"https://sehajyang.github.io/2019/03/10/2019-03-10-190225~190310/","excerpt":"","text":"저번 주 회고에 이어서 Python으로 몇 가지 알고리즘 문제를 풀었다.또한, 사내 프로젝트에 Jenkins를 붙였다.약 2일이 걸렸고, 그 과정에서 발생했던 삽질들을 모아 Jenkins 삽질기를 작성하고 있다. Python 비동기 웹 프레임워크인 Sanic으로 실시간 채팅 웹 애플리케이션을 만들고 있다.그간 써온 웹 프레임워크는 커뮤니티가 커서 웬만한 오류는 검색하면 다 나왔었는데Sanic은 자료가 적고 인지도도 낮아서 고생하고 있다.그래도 async를 자유자재로 쓸 수 있다는 건 굉장히 매력적이다. 회사에서 어떤 python script를 async로 고쳤다! 기존엔 작업 완료까지 18분 정도 걸렸는데, 이젠 1분이면 작업이 완료된다.그간 async이론만 공부했었는데, 이번에 실제로 해보고 나니 굉장히 충격적이었다!(그리고 어려웠다)async는 어려운 만큼 매력적인 것 같다. Intelli J의 springboot starter로 Kotlin + Springboot 프로젝트를 시작해봤다.Kotlin에 Java를 섞어 쓸 수 있다고 듣기만 했지 실제로 자바 파일을 섞어보진 않았었는데,이번에 섞어볼 수 있어서 Springboot + Kotlin + Java로 만들어봤다.역시 100% 호환이 되었다! 왜 많은 서비스가 Java에서 Kotlin으로 바꾸고 있는지 조금이나마 알 것 같았다.앞으로 좀 더 알아볼 생각이다. 2주간 했던 것 Python 으로 알고리즘 문제 몇 개 Sanic web chatting project Jenkins Springboot + Jenkins blog 가독성 업데이트 다음주 목표 Python Study Sanic web chatting project Jenkins 학습 간간히 총평무려 Jenkins를 개발 팀장님의 배려로 사내 프로젝트에 붙일 수 있었는데, 라이브 서비스에 붙여보긴 처음이라 실수도 많이 하고 삽질도 많이 했었다. 그래도 완성하고 나니 정말 뿌듯했다.최근 여러가지 기술 블로그를 보고 가독성의 중요성을 깨닫게 되어 몇 개월간 미뤄뒀던 블로그의 카테고리 분류 및 가독성 향상 작업을 했다.아직 마음에 안드는 부분이 조금 있어서 차차 고쳐야 될 것 같다. Python 기존 스크립트를 비동기로 바꾸기도 했는데, semaphore를 걸지 않고 request를 날리다가 차단당하는 등의 일이 있었지만. 구글링과 주변 개발자분의 도움으로 제대로 완성할 수 있었다.그 과정에서 알던 것도 있었고 새롭게 배운 것도 있었다. 다음엔 꼭 내 힘으로 완성해보고 싶다. 우연히 패스트 캠퍼스에서 올렸던 몇 가지 동영상을 보게 되었는데, 그 영상들을 보고 많은 생각을 하게 됐다.영상 링크1, 링크2최근들어 내가 한가지 기술에 집중하는게 아닌, 넓고 얕게 이것저것 배우고 있다는 생각을 하고 있었다.그래서, 지금 진행중인 Python web framework인 Sanic으로 실시간 채팅 웹 토이 프로젝트를 조금 오래 걸리더라도 제대로 해서 내 것으로 만들 수 있도록 해야겠다..!","categories":[{"name":"Logs","slug":"Logs","permalink":"https://sehajyang.github.io/categories/Logs/"}],"tags":[{"name":"weekly","slug":"weekly","permalink":"https://sehajyang.github.io/tags/weekly/"}]},{"title":"Kotlin 에서 Lombok을 사용할 수 없는 문제","slug":"/etc/2019/03/07/kotlin-and-lombok.html","date":"2019-03-06T15:00:00.000Z","updated":"2019-07-15T14:11:55.584Z","comments":true,"path":"2019/03/07//etc/2019/03/07/kotlin-and-lombok.html/","link":"","permalink":"https://sehajyang.github.io/2019/03/07/etc/2019/03/07/kotlin-and-lombok.html/","excerpt":"","text":"최근 자바 스프링부트로 되어있는 사내 프로젝트에 코틀린을 일부분 도입하려다 대차게 실패했다..사내 프로젝트에 Lombok을 사용하고 있었는데, 코틀린이 롬복을 사용한 Bean Class 에 접근하지 못하고 있었다. 당시 1Kotlin: Cannot access '가가' it is private member of '나나' 이런 에러 메세지를 띄우며 컴파일이 되지 않았다. 처음엔 자바로 짜여진 클래스의 private object에 접근을 못해서 나는 에러인 줄 알았으나 롬복 문제였다.kotlin-doesnt-see-java-lombok-accessors그리고 위 링크에서 이유를 알 수 있었다. 위 링크를 요약하자면 일반적으로 JVM 에선 코틀린이 먼저 컴파일 된 후 자바가 컴파일 된다.코틀린이 자바의 롬복으로 된 클래스에 접근하려 했으나 getter setter가 만들어지지 않아서 접근을 하지 못한다.롬복은 컴파일시 동작 하는 어노테이션이기 때문이다.강제로 컴파일러가 자바 먼저 컴파일하게 바꿀 순 있지만 그렇게 되면 자바에서 코틀린 코드를 사용할 수 없다. 코틀린과 자바가 100% 호환은 맞지만 자바로 만들어진 third-party 라이브러리 들과 호환 되는건 아닌 것 이다.롬복을 사용한 자바 파일들을 전부 코틀린으로 바꾸지 않는 한 코틀린을 현재 진행 중인 프로젝트에 적용 하긴 힘들 것 같다. 두줄요약 코틀린과 롬복을 같이 쓸 수 없다. 코틀린을 정말 쓰고싶다면 롬복을 사용한 자바 파일을 코틀린 파일로 바꿔야 된다. 19.06.26 기준 자세한 포스팅이 나왔습니다!Naver D2 Kotlin 도입 과정에서 만난 문제와 해결 방법 혹 궁금하거나 오류가 있다면 댓글 남겨주세요😄","categories":[{"name":"Kotlin","slug":"Kotlin","permalink":"https://sehajyang.github.io/categories/Kotlin/"}],"tags":[]},{"title":"190221-190224 반 주간 회고","slug":"2019-02-24-190221~190224","date":"2019-02-23T15:00:00.000Z","updated":"2019-07-15T14:11:55.583Z","comments":true,"path":"2019/02/24/2019-02-24-190221~190224/","link":"","permalink":"https://sehajyang.github.io/2019/02/24/2019-02-24-190221~190224/","excerpt":"","text":"주간회고 주기를 맞추기 위해 이번주는 두개나 올리게 되었다..며칠간 주문했던 TDD책이 오거나 scala 강의를 신청하거나 알고리즘을 풀거나 KCD를 가는 등의 이슈가 있었다. 조만간 내가 개발하고 있는 서비스에 jenkins를 붙일 것 같다!과거 내 springboot에 jenkins를 붙일 때 큰 문제가 없었던 걸 생각해보면 크게 어렵지 않을 거라고 생각하고있다.. 아마도..? 반 주간 했던 학습 Python Study 알고리즘 몇 문제 KCD 참석 다음주 목표 스프링 기반 TDD REST API 개발공부 및 기록 계속 Python Study 알고리즘 계속 KCD(Korea Community Day) 2019주말에 KCD를 갔다왔다.간략한 정리 총평KCD 에서 스칼라와 코틀린에 대한 세션을 들었다.코틀린은 현업에서 사용할 수 있을 것 같았다.스칼라는 시작하고 싶지만 요즈음 파이썬을 공부하고 있기 때문에 나중으로 조금 미루기로 했다.조만간 알고리즘 푼 것 들을 정리할 생각이다.","categories":[{"name":"Logs","slug":"Logs","permalink":"https://sehajyang.github.io/categories/Logs/"}],"tags":[{"name":"weekly","slug":"weekly","permalink":"https://sehajyang.github.io/tags/weekly/"}]},{"title":"190204-190220 몇 주간 회고","slug":"2019-02-20-190204~190220","date":"2019-02-19T15:00:00.000Z","updated":"2019-07-15T14:11:55.582Z","comments":true,"path":"2019/02/20/2019-02-20-190204~190220/","link":"","permalink":"https://sehajyang.github.io/2019/02/20/2019-02-20-190204~190220/","excerpt":"","text":"회사일 및 기타 사정으로 인해 연휴 이후에 주간회고를 작성하지 못했는데그로인해 몇 주 지나니 2월간 내가 무엇을 학습했는지 모르는 상태가 되어서 급하게 주중에 다시금 주간회고를 작성하게 되었다. 주간회고를 작성하지 않은 기간 동안 비동기 및 쓰레드 공부를 해서 1월에 비해보다 깊이 비동기 및 python asyncio에 대해서 배우고 공부할 수 있었다. Springboot 의 강력한 기능중 하나인 Actuator를 도입할 생각을 하고있다 Vue.js 입문, Typescript 입문을 했다. Vue는 예전에 잠깐 사용해본 React랑 비슷한 부분도 다른 부분도 있었는데일단, 굉장히 React에 비해 사용하기 쉽고 공식문서가 잘 되어있다는 느낌을 받았다. 몇 주간 했던 학습 스프링 기반 TDD REST API 개발 수강 후 기록 Springboot migration JDK8 stream에 대한 공부 Python Syntax 공부 Python Built-in Library > asyncio — Asynchronous I/O 관련 학습 asyncio / thread를 사용한 request 예제 kocw 운영체제 강의 Jenkins 삽질 Springboot Actuator 토이프로젝트에 적용 및 체험 Vue, Typescript 입문 다음주 목표 스프링 기반 TDD REST API 개발공부 및 기록 계속 Python Study asyncio / thread 공부 계속 이번주에 읽었던 글 몇가지 자바 프로그래머가 자주 실수 하는 10가지 읽는 내내 내 얘기같아서 너무 찔렸다. 이 글을 읽고 어느정도 그러한 문제들을 개선하게 되었다. 예를들면 아무 생각없이 ArrayList를 사용하거나 그러한것들 말이다. 몇달전에 loop에서 list의 아이템을 제거하는 예제를 만든적이 있다이 글의 3번째 타이틀에서 보다 잘 알수 있어서 좋았다. Promise 내가 지금껏 본 Promise 글 중 가장 이해가 잘 되었다. 우린 Git-flow를 사용하고 있어요 현재 내가 개발중인 서비스에 Git Flow를 도입할 생각을 하고있어서 참고가 될 것 같다. Spring 웹 애플리케이션에서 사용하지 않는 API를 찾아보자 내가 개발중인 서비스에도 사용하지 않는 API가 많아서 정리의 필요성을 느끼고 있었다. 이 글이 큰 도움이 되었다. 몇 개월 내로 실행해 볼 생각이다. 총평몇주간 밀린것을 한꺼번에 쓰니 굉장히 열심히 공부한 것 같은데, 요 몇주간은 굉장히 루즈하게 공부했다.그래도 파이썬을 다시 공부하거나 비동기를 보다 깊게 공부하거나 새로운 몇가지 기술을 적용해보는 등 새로운 시도를 많이 한 주 였다.이번주엔 KCD(Korea Community Day) 2019 를 갈 예정이다.JS 및 DevOps에 대한 세션이 많아서 기대된다!","categories":[{"name":"Logs","slug":"Logs","permalink":"https://sehajyang.github.io/categories/Logs/"}],"tags":[{"name":"weekly","slug":"weekly","permalink":"https://sehajyang.github.io/tags/weekly/"}]},{"title":"mybatis association","slug":"/java/2019/02/18/mybatis-association.html","date":"2019-02-17T15:00:00.000Z","updated":"2019-08-02T14:41:53.801Z","comments":true,"path":"2019/02/18//java/2019/02/18/mybatis-association.html/","link":"","permalink":"https://sehajyang.github.io/2019/02/18/java/2019/02/18/mybatis-association.html/","excerpt":"","text":"Lombok 사용Service 생략 File Shop.java ShopDetail.java ShopMapper.xml Shop.java 12345678@Datapublic class Shop { private String shopno; private String id; private String pwd; private ShopDetail shopDetail; //변수명 앞문자 capital 주면 안됨(getter, setter 때문)} ShopDetail.java 123456public class ShopDetail { private String shopno; private String name; private String price; private String count;} ShopMapper.xml 123456789101112131415161718<!-- 중략 --><mapper namespace=\"com.test.mapper.ShopMapper\"> <resultMap id=\"ShopMap\" type=\"com.test.domain.Shop\"> <result property=\"shopno\" column=\"shopno\" /> <result property=\"id\" column=\"id\" /> <result property=\"pwd\" column=\"pwd\" /> <association property=\"shopDetail\" javaType=\"com.test.domain.ShopDetail\"> <result property=\"shopno\" column=\"shopno\" /> <result property=\"name\" column=\"name\" /> <result property=\"price\" column=\"price\" /> <result property=\"count\" column=\"count\" /> </association> </resultMap> <select id = \"selectTestQuery\" resultMap = \"ShopMap\"> select s.*, sd.* from shop s join shopdetail sd on s.shopno = sd.shopno </select> Result1Shop[(shopno=1, id=aa, pwd=1234, shopDetail=shopDetail(shopno=1, name=김뭐뭐, price=1000, count=100))] association, result map collection 등으로 검색하면 더 자세히 알 수 있습니다.","categories":[{"name":"Java","slug":"Java","permalink":"https://sehajyang.github.io/categories/Java/"}],"tags":[{"name":"tip","slug":"tip","permalink":"https://sehajyang.github.io/tags/tip/"},{"name":"mybatis","slug":"mybatis","permalink":"https://sehajyang.github.io/tags/mybatis/"},{"name":"spring","slug":"spring","permalink":"https://sehajyang.github.io/tags/spring/"}]},{"title":"Springboot auto build 안되는 문제","slug":"2019-02-14-springboot_autobuild_problem","date":"2019-02-13T15:00:00.000Z","updated":"2019-07-15T14:11:55.581Z","comments":true,"path":"2019/02/14/2019-02-14-springboot_autobuild_problem/","link":"","permalink":"https://sehajyang.github.io/2019/02/14/2019-02-14-springboot_autobuild_problem/","excerpt":"","text":"최근 Eclipse에서 Intelli J로 갈아탔는데 java 파일 수정시 auto build가 되지 않는 문제가 발생했다. 실행 환경OS: win10IDE : Intelli J 2018.3 해결 방법 build.gradle에 의존성 추가 1compile(\"org.springframework.boot:spring-boot-devtools\") application.properties 사용할 경우 1spring.devtools.livereload.enabled=true Intelli J Settings > Compiler 검색 > Buld Project automatically 체크 왼쪽 shift 두번 누름 > Registry 검색> compiler.automake.allow.when.app.running 체크 Run SpringbootApplication (Gradle일 경우 bootRun인데 이거 아니고 SpringbootApplication으로 실행해야됨)","categories":[{"name":"Spring","slug":"Spring","permalink":"https://sehajyang.github.io/categories/Spring/"}],"tags":[{"name":"Springboot","slug":"Springboot","permalink":"https://sehajyang.github.io/tags/Springboot/"},{"name":"Build","slug":"Build","permalink":"https://sehajyang.github.io/tags/Build/"}]},{"title":"190128~190203 주간회고","slug":"2019-02-03-190128~190203","date":"2019-02-02T15:00:00.000Z","updated":"2019-07-15T14:11:55.579Z","comments":true,"path":"2019/02/03/2019-02-03-190128~190203/","link":"","permalink":"https://sehajyang.github.io/2019/02/03/2019-02-03-190128~190203/","excerpt":"","text":"요 몇주간 회사일로 바쁘거나, 스터디 자료 준비를 하느라 주간회고를 쓰지 못했었는데 이번 명절에 시간이 남아 작성할 수 있었다.변화가 많은 주 였다. Eclipse 에서 Intelli J 로 전환 electron + vue Python 다시 시작 자바스크립트 생태계 관련 학습 및 발표 비동기 공부 이번주 학습Eclipse 에서 Intelli J로 전환문제1. springboot로 java파일 수정시 auto build를 체크해뒀는데, auto build를 할 때 마다 거의 모든 JPA를 재등록 하는 것 같았다.가끔 그것때문에 웹서버가 업데이트 되지 않는다거나 락이 걸리는 등의 문제가 있었다.그럴때는 이클립스 프로그램을 다시 껐다 켜고(심지어 프로세스를 직접 지워야했다), project clean > build 를 했는데 여간 불편한게 아니었다. 문제2. 무언가 입력하려고 할때 자주 버퍼링이 걸렸다. 내 노트북의 성능은 충분했고(i7-7700) 메모리또한 넉넉했다. 문제3. 이유없는 error reporting, 말 그대로 아무 이유 없이 아무런 작업을 하지않는데 error report를 띄우는 경우가 잦았다.그 밖에도 불편한점이 있었지만 크게 불편했던건 위와 같다. 그래서 Intelli J를 생각하고 있었는데 회사 동료의 도움으로 도입할 수 있게 되었다.전환 후 초반엔 셋팅 문제를 조금 겪긴 했지만 굉장히 만족중이다! 상기된 모든 문제가 사라졌고, 그 외의 불편한점은 아직 느끼지 못했다. Python 다시 시작과거에 알고리즘 풀이 이후로 놓았던(발만 담궜던) 파이썬에 대해 그간 별 생각이 없었는데, 최근에 주변인을 통해 좀더 알게되면서 파이썬으로 무언가 만들어봐야겠다고 생각했다.연휴때 spring reactor를 사용한 채팅 프로그램을 만들려 했는데, python으로 짜볼 예정이다. 자바스크립트 생태계 관련 학습 및 발표사내 스터디 이번주 발표자가 되어서 약 4일간 발표 준비를 했었다.자바스크립트의 특징과 역사 그리고 라이브러리, 프레임워크에 대한 내용을 다룸으로써 큰 그림을 보려는 목적이었다.개인적으로 아직 잘 몰라서 아쉬웠던 부분도 있었지만 전반적으로 즐겁게 준비했던 것 같다.특히 어디서 들어봤던 라이브러리 혹은 프레임워크에 대해 찾아보며 동작 원리나 특징을 알 수 있었고 산재되어있는 내용들을 모으며 흐름이 그려지기도 해서 준비하면서도 많은 공부가 됐었다.또한 2주전에 골머릴 앓던 자바스크립트의 Callback,Promise,Closer 그 기타등등을 이제 알 것 같아서 기쁘다!다음에 발표를 한다면 노드의 비동기로 하고싶다.시간상 노드에 대한것을 넣을 수 없어서 아쉬웠다.발표자료는 sildeshare에서 볼 수 있다. 비동기 공부몇주 전 아파서 더 듣지못했던 비동기에 대한 걸 들을 수 있었다. 조금씩이나마 짜맞춰져가는 것 같아서 굉장히 즐거웠다.발표자분이 굉장히 잘 준비해주셔서 처음 듣는데도 무리 없이 잘 이해할 수 있었다.그 후 한번 정리하니 전체적인 그림이 그려지는 것 같았다.하지만 내가 제대로 이해한건지 확신을 할 수 없고, 아직 뿌연 느낌이라서 7가지 동시성 모델(자바로 쓰여져있다)을 볼 예정이다. 다음주 연휴 학습 예정 Python 비동기 (시간이 된다면)Virtual DOM 좀더 깊이! 총평배운게 많은 주 였다. 그간 많은 기술을 해보며 즐겁기도 했지만 왠지 모르게 정체되어있는 느낌을 받았었다.그래서 나름대로 조언을 구하기도 하고 이것저것 시도해보기도 했는데, 다행히 길을 찾은 것 같다.한동안 파이썬을 하다 electron + vue를 할 예정이다(backend는 파이썬으로 할 것이다)","categories":[{"name":"Logs","slug":"Logs","permalink":"https://sehajyang.github.io/categories/Logs/"}],"tags":[{"name":"weekly","slug":"weekly","permalink":"https://sehajyang.github.io/tags/weekly/"}]},{"title":"190114~190120 주간회고","slug":"2019-01-20-190114~190120","date":"2019-01-19T15:00:00.000Z","updated":"2019-07-15T14:11:55.578Z","comments":true,"path":"2019/01/20/2019-01-20-190114~190120/","link":"","permalink":"https://sehajyang.github.io/2019/01/20/2019-01-20-190114~190120/","excerpt":"","text":"이번주는 수요일부터 주말인 일요일까지 고열+장염 크리로 개인공부를 단 하나도 하지 못했다.손 끝 하나 들 힘조차 없어 컴퓨터는 커녕 카톡도 간신히 했다.이번주에 배운건 건강을 잘 챙기자.. 정말 그간 쌓아오던 공부 계획이 속절없이 무너지는 걸 경험했다.깃허브의 잔디에 연연하지 않기로 했지만 일주일 내리 텅텅 비어버린 잔디를 보니 속이 쓰리다.. 이번 주 학습 러닝 자바스크립트 콜백, 프로미스, 스코프 학습 고열, 장염에 좋은 음식 등 다음주 학습 예정 러닝 자바스크립트 총평이번주는 너무 조급하게 초조해하며 공부하다 그대로 건강을 못 챙기고 엎어져버린 주 였다.그래서 앞으론 진도를 늦게 빼는 한이 있더라도 예전보단 조금 더 여유롭게 스트레스 받지 않으면서 공부해야겠다고 생각했다.그간 자바스크립트 + 스프링부트 강의 + 알고리즘 + 기타(최근엔 비동기) 공부를 하고있었는데 당분간 자바스크립트 하나만 가지고 여유롭게 공부할 생각이다.","categories":[{"name":"Logs","slug":"Logs","permalink":"https://sehajyang.github.io/categories/Logs/"}],"tags":[{"name":"weekly","slug":"weekly","permalink":"https://sehajyang.github.io/tags/weekly/"}]},{"title":"181231~190113 2주간회고","slug":"2019-01-13-181231~190113","date":"2019-01-12T15:00:00.000Z","updated":"2019-07-15T14:11:55.578Z","comments":true,"path":"2019/01/13/2019-01-13-181231~190113/","link":"","permalink":"https://sehajyang.github.io/2019/01/13/2019-01-13-181231~190113/","excerpt":"","text":"요즘들어 어떤 개념을 습득한 건 기억이 나는데, 내가 어떤 것을 했는지가 기억이 잘 나지 않는다.예를들어 메소드 개념을 습득했다고 치자, 그 개념에 대해선 굉장히 기억을 잘 하고 있는데몇 시간전에 작업한게 뭐였는지 어제 작업한게 뭐였는지 그런게 기억이 잘 나지 않는 식이다.딱히 스트레스 받지도 않고 잘 쉬면서 학습 하고 일 하는 것 같은데 이상하다.아무래도 요즘 내 머릿속 RAM 휘발이 너무 잘 되는 것 같다.. 저번주의 주간회고가 밀렸으므로 2주치를 같이 작성하게 되었다. 저번주에 왜 밀렸었는지 기억이…대신 학습한 것에 대한 기억은 다행히도 잘 있어서 주간회고를 작성할 수 있다. 이번주 2주치 학습 러닝 자바스크립트 콜백, 프로미스, 스코프 학습 스프링 기반 REST API 개발 수강 후 기록 @MockMVC 나 hateoas, mokito 등 기존의 내가 알던(?) TDD와는 완전 다른 것을 새로운 것을 많이 배웠다. 사내 스터디의 비동기에 대한 세미나 다음주 학습 예정 러닝 자바스크립트 스프링 기반 REST API 개발 수강 마무리 사내 스터디의 비동기에 대한 세미나 2부 총평나는 종종 자바스크립트로 개발한다. 하지만 콜백, 프로미스, 스코프에 대해서 잘 모르고 있었다. 내가 개발할 때 쓸 일이 별로 없었기 때문이다..하지만 최근에 내가 그것들에 대해서 잘 모른다는걸 깨달았을 때 굉장히 창피하고 부끄러웠다.그래서 요즘 러닝 자바스크립트와 구글링을 통해 공부하고 있다.콜백과 프로미스에 대해서 좀더 공부하고 있는데, 마침 사내 개발 스터디 발표 주제가 비동기였다.발표자분이 비동기에 대해서 깊이있게 발표해주셔서 큰 가닥을 잡을 수 있었다!각각의 개념(동시성, coroutine, Non-block 함수 등)은 알았는데 그 개념들을 연결하는게 안되고 있다.한번에 이해하기엔 어려운 개념인 것 같다. 다음주엔 내가 조금 더 잘 이해하고 있길.. 스프링 기반 REST API 개발 수강은 퇴근 후 약속이 있지 않으면 매일 한 강의씩 들었는데, 처음 써보는 라이브러리나 함수가 너무 많아서 나중엔 그냥 이해 못하고 따라치게 되었던 것 같다. 게다가 내가 띄엄띄엄 수강한 것도 한 몫 했다.그래서 다음주엔 띄엄띄엄 수강하지 말고 일단 한번 완강을 하고 모르는 것을 따로 복습하는 식으로 흐름을 끊지 않게 공부하려고 한다. git add -p 와 git commit -v 의 사용 이 글을 읽고 commit -v 하고 소스를 검토하는 습관을 들이게 됐다.그 덕분에 내가 실수로 커밋할뻔한 잘못된 코드를 커밋하지 않을 수 있었다. 종종 급하게 소스를 커밋하고 푸쉬해버리는데 정말 좋은 습관을 들일 수 있었다. 최근 콜백+프로미스와 노드 그리고 비동기 스터디가 더해지면서 머릿속을 비동기가 점령해버렸다.앞으로 몇주간은 그럴 것 같다. 그 몇주가 끝난 후 내가 비동기에 대해서 잘 이해하고 있었음 좋겠다..!","categories":[{"name":"Logs","slug":"Logs","permalink":"https://sehajyang.github.io/categories/Logs/"}],"tags":[{"name":"weekly","slug":"weekly","permalink":"https://sehajyang.github.io/tags/weekly/"}]},{"title":"2018 연간회고","slug":"2018-12-31-2018-review","date":"2018-12-30T15:00:00.000Z","updated":"2019-07-15T14:11:55.577Z","comments":true,"path":"2018/12/31/2018-12-31-2018-review/","link":"","permalink":"https://sehajyang.github.io/2018/12/31/2018-12-31-2018-review/","excerpt":"","text":"2018년을 마무리하며, 아직은 부족한게 많고 부끄러워서 연간회고를 쓸까말까 고민을 많이 했다. 많이 부족하지만 연간회고를 해 보기로 했다. 2018년은 굉장히 도전적인 해 였다. 웹 개발 교육 및 공부 시작 개인 프로젝트 및 세미나 취업 으로 크게 나눌 수 있다! 1. 웹 개발 교육 및 공부 시작원래 보안쪽으로 공부를 하다가 우연히 웹 개발에 관심을 갖게 되어 관련 교육을 듣고 다양한 기술을 접하고 공부하고 프로젝트를 만들었었다. 그 과정에서 Joshua님의 블로그와 gwonsungjun님의 TIL과 블로그를 보며 방향을 잡을 수 있었다. 나는 주간회고를 남기기 시작했고, 꾸준히 기록하는 것에 대해서 배울 수 있었고 이건 나에게 큰 변화중 하나였다! 그 밖에 많은 기술을 공부했다. 2. 개인 프로젝트 및 세미나 기억에 남는 2018년에 배운 기술 Git, Github => 연초에 형상관리를 처음 접해봤었다. 처음엔 삽질도 사고도 많이 치고 conflict도 엄청났으며, 날린적도 한두번이 아니었지만그런 시행착오를 회사 가서 하지 않아서 정말 다행이라고 생각한다.. 깃허브 블로그 => jekyll를 이용해서 깃허브 블로그를 만들었었다.루비로 짜여있는데, 루비를 할 줄 몰라서 제대로 되어있지 않은 상태이다, 리뉴얼 할 것 투성이다.처음엔 나도 개발관련 포스팅을 하고 싶었지만 부족한점이 많아서 주간회고 기록용으로 쓰고있다. React => 올해의 가장 큰 벽이었던 것 같다. 2019년 초에 다시 도전할 생각이다 CI/CD => 리눅스에 배포 환경을 일일히 설치하고, 소스코드를 리눅스로 옮기고 라이브러리를 수동으로 넣고그렇게 선사시대같은 방법으로 배포를 하던 나에게 엄청난 충격이었다. 그 밖에도 Spring, Springboot, Nodejs, ReactNative, 챗봇 등 크고 작은 개인 혹은 팀 프로젝트들을 했었다. 힘들고 지루했던 프로젝트는 없었던 것 같다 가장 기억에 남았던 세미나 Open Infra Day Korea 2018 인프라에 관심이 없었는데 이 세미나를 계기로 굉장히 관심이 많아졌었다.아마 이 세미나를 가지 않았으면 지금까지도 크게 관심이 없었을 것 같다.가서 정말 다행이었다 Seoul js 백엔드 개발자인 내가 가도 될까..? 라고 생각했었고 가서도 나는 하나도 이해하지 못했지만..프론트엔드에 관심을 갖게 된 계기가 된 좋은 세미나였다!이 세미나를 갔다오고나서 리액트와 타입스크립트를 공부했었다. 지금도 계속 공부하고 싶은 욕심이 있다.아마 이 세미나를 가지 않았다면 나는 그냥 백엔드 공부만 했을 것 이다.그런의미에서 오픈 인프라데이 컨퍼런스보다 나에겐 더 의미가 큰 세미나였다. 기회가 된다면 또 가고싶다. 3. 취업이전 회사를(실습) 잠깐 다녀 본 내 결론은 취업 전에 하고싶은 공부를 하자! 였다그래서 원없이 하고싶은 공부(React, Devops 등)를 실컷 하고 운 좋게 백엔드 포지션으로 좋은 회사에 취직했다내가 바라던 개발 환경이었고, 매주마다 사내 세미나같은 스터디를 해서 즐겁다회사에선 Springboot로 개발을 하고있다. 내가 많이 부족함을 느끼고 있다.. 총평원래 보안쪽으로 가려던 내가 웹 개발을 시작하게 되면서 굉장히 많은 정보와 기술을 알게 된, 변화가 많은 해 였다. Spring, Nodejs Reactjs MongoDB부터 Jenkins AWS Docker등 백엔드 DB 프론트엔드 인프라 등 단기간에 많은걸 접해보고 사용해보고 만들어본 해 였다. 힘든 순간도 있었고 슬럼프가 오기도 했지만 나름대로 이겨낸 것 같다. 아직 글쓰기도 그렇고 개발도 그렇고 부족한게 많지만 2019년도 꾸준히 하도록 노력해야겠고,2018년처럼 2019년도 이것저것 많이 해보고 좀더 꼼꼼하고 어느정도 능숙해 질 수 있는 한해가 됐으면 좋겠다!","categories":[{"name":"Logs","slug":"Logs","permalink":"https://sehajyang.github.io/categories/Logs/"}],"tags":[{"name":"weekly","slug":"weekly","permalink":"https://sehajyang.github.io/tags/weekly/"}]},{"title":"1801217-1801223 주간회고","slug":"2018-12-23-181217~181223","date":"2018-12-22T15:00:00.000Z","updated":"2019-07-15T14:11:55.576Z","comments":true,"path":"2018/12/23/2018-12-23-181217~181223/","link":"","permalink":"https://sehajyang.github.io/2018/12/23/2018-12-23-181217~181223/","excerpt":"","text":"이번주엔 기존의 스프링 강의와 더불어 스프링 기반 REST API 개발강의 수강을 시작했다! 강의를 들으면서 기록하는게 쉽지 않아서 생각보다 기록에 많은 시간이 걸리고 있지만 나중에 도움이 될거라고 생각한다. 예전에 읽었던 HeadFirst DesignPatter 책을 예제를 따라가며 다시 보고있다. 그리고 자바스크립트 바이블 서적 같은 러닝 자바스크립트를 공부하며 기록을 시작했다. 아는부분은 건너뛰고 모르거나 애매했던 부분부터 보고있다. 이번주에 했던 학습 스프링 기반 REST API 개발 수강 후 기록 백기선의 스프링부트 수강 후 TIL에 기록 러닝 자바스크립트 공부 후 TIL에 기록 CodeWars 3문제 다음주 목표 스프링 기반 REST API 개발공부 및 기록 계속 백기선의 스프링부트보고 TIL에 정리하기 계속 러닝 자바스크립트 공부 후 TIL에 정리하기 계속 Design Pattern 책 읽으며 개인 프로젝트 진행 계속 간간히 CodeWars 문제 풀기 총평이번주는 이것저것 하고싶은 공부를 시작한 주 였다. 잘 하는 것 보단 중간에 포기하는 일 없이 끝까지 하는걸 중심으로 해야겠다. 목표치 만큼 하지 못해서 더디다고 생각하고 있지만 조금씩 꾸준히 한다는것에 의의를 두기로 했다!","categories":[{"name":"Logs","slug":"Logs","permalink":"https://sehajyang.github.io/categories/Logs/"}],"tags":[{"name":"weekly","slug":"weekly","permalink":"https://sehajyang.github.io/tags/weekly/"}]},{"title":"두개의 리스트 아이템을 비교해 추가,삭제","slug":"2018-12-19-compare-items-in-two-arraylists","date":"2018-12-18T15:00:00.000Z","updated":"2019-08-02T14:41:53.799Z","comments":true,"path":"2018/12/19/2018-12-19-compare-items-in-two-arraylists/","link":"","permalink":"https://sehajyang.github.io/2018/12/19/2018-12-19-compare-items-in-two-arraylists/","excerpt":"","text":"최근 두개의 ArrayList의 아이템을 비교해, 추가되는 아이템과 삭제되는 아이템을 구분할 필요가 있어서 만들었습니다. 조건 list1 = [a, b, c, d] =>새로 받아온 ArrayList list2 = [a, b, e] => 기존 DB 있던 데이터를 담은 ArrayList 기존 리스트에 영향을 주지 않으며, 새로운 리스트를 생성해 리턴해야 한다. 123456789101112131415161718192021ArrayList<String> resultList = compageAndDel(list1, list2);for (int i = 0; i < resultList.size(); i++) { System.out.println(\"Inst \" + resultList.get(i)); // c,d 출력 => DB에 없던, 새롭게 추가될 데이터}ArrayList<String> resultList2 = compageAndDel(list2, list1);for (int i = 0; i < resultList2.size(); i++) { System.out.println(\"Del \" + resultList2.get(i)); // e 출력 => 기존 DB에 있었지만 삭제된 데이터}private static ArrayList<String> compageAndDel(ArrayList<String> target, ArrayList<String> source) { ArrayList<String> tmpArr = new ArrayList<>(); tmpArr.addAll(target); for (String item : source) { if (target.contains(item) == true) { //일치하는 아이템을 지움 tmpArr.remove(item); } } return tmpArr;} 위의 코드로 새로 추가될 아이템과 DB에 있었지만 삭제될 아이템을 구분할 수 있습니다.만약 기존 리스트에 영향을 줘도 된다면 다음과 같이 작성합니다. 12345// list1기준 삭제된 요소 리턴 list1.removeAll(list2); //[c,d]// list1기준 추가된 요소 리턴list2.removeAll(list1); //[e] +2019.7.6 추가자바8 람다를 이용해 위 코드를 다음과 같이 리팩토링 해 봤습니다. 12345678910List<String> list1 = new ArrayList<>(Arrays.asList(\"a\", \"b\", \"c\", \"d\"));List<String> list2 = Arrays.asList(\"a\", \"b\", \"e\");System.out.println(list1.stream() .filter(x -> !list2.contains(x)) .collect(Collectors.toList())); //[c, d]System.out.println(list2.stream() .filter(x -> !list1.contains(x)) .collect(Collectors.toList())); //[e] 과거 코드와 비교해 소스가 깔끔하게 정리된 것을 알 수 있습니다. 스칼라로는 다음과 같이 작성할 수 있습니다.+scala 버전 val diff1 = list1.diff(list2) //Set(c, d) val diff2 = list2.diff(list1) //Set(e) // 공통 아이템만 리턴 var match1 = list1.intersect(list2) // Set(a, b) 읽어주셔서 감사합니다. 혹 오류/문의할 내용이 있다면 코멘트 남겨주세요!🙆","categories":[{"name":"Java","slug":"Java","permalink":"https://sehajyang.github.io/categories/Java/"}],"tags":[{"name":"Java","slug":"Java","permalink":"https://sehajyang.github.io/tags/Java/"}]},{"title":"1801210-1801216 주간회고","slug":"2018-12-16-181210~181216","date":"2018-12-15T15:00:00.000Z","updated":"2019-07-15T14:11:55.575Z","comments":true,"path":"2018/12/16/2018-12-16-181210~181216/","link":"","permalink":"https://sehajyang.github.io/2018/12/16/2018-12-16-181210~181216/","excerpt":"","text":"이번주는 바빠서 틈틈히 스프링 관련 강의를 듣고 정리하거나 유용한 글을 읽고 정리를 해서 TIL에 올렸다. REST API에 대해서 대략 알지만 제대로 강의나 책을 보고 공부하기보단 인터넷으로 짧은 지식등을 보고 익혔었기 때문에 부족함을 많이 느껴서 스프링 기반 REST API 개발 신청을 했다! TDD로 진행한다고 되어있는데, 최근 사내에서 TDD에 대한 언급이 있어서 TDD를 익힘에 있어 많은 도움이 될 것 같다. 이번주에 읽은 글 카카오 헤어샵 개발과정 및 후기 비둘기로 설명하는 HTTPS(HTTPS explained with carrier pigeons) 웹 아키텍쳐 입문 이번주에 했던 학습 백기선의 스프링부트 수강 후 TIL에 기록 다음주 목표 백기선의 스프링부트 보고 TIL에 정리하기 계속! 스프링 기반 REST API 개발 총평목표치만큼 학습하지 못해서 아쉬운 주 였다. 연말이라서 그런 것 같은데 다음주에는 조금 더 목표를 달성 할 수 있었으면 좋겠다","categories":[{"name":"Logs","slug":"Logs","permalink":"https://sehajyang.github.io/categories/Logs/"}],"tags":[{"name":"weekly","slug":"weekly","permalink":"https://sehajyang.github.io/tags/weekly/"}]},{"title":"1801203-1801209 주간회고","slug":"2018-12-09-181203~181209","date":"2018-12-08T15:00:00.000Z","updated":"2019-07-15T14:11:55.573Z","comments":true,"path":"2018/12/09/2018-12-09-181203~181209/","link":"","permalink":"https://sehajyang.github.io/2018/12/09/2018-12-09-181203~181209/","excerpt":"","text":"이번주는 많은 일이 겹쳐서 공부를 할 수가 없었다. 다음주 부터는 할 수 있을 것 같다. 그래서 출퇴근 몇가지 읽었던 글/포스팅을 정리하는 식으로 이번주의 주간회고를 하려고 한다. 기록해두지 않으니 전부 까먹어서 앞으로 좋았던 글 등을 깃허브 TIL/Review에 정리해두려고 한다! 이번주에 읽었던 글 대규모 서비스를 지탱하는 기술 좋은 코딩을 위한 13 가지 간단한 규칙 슈퍼마켓에서 우유를 사면서 웹 캐싱(Web Caching)을 알아봅시다 다음주 목표 백기선의 스프링부트 보고 TIL에 정리하기 러닝 자바스크립트 읽고 정리 슬프게도 이번주에 아무것도 못했기 때문에 저번주와 같다. 총평다음주 부턴 공부를 할 시간이 좀 생길 것 같다! 지금 하고있는 스프링부트나 자바스크립트를 완강 후 함수형 프로그래밍 이 강의를 들을 생각을 하고 있다. 국내에 함수형 프로그래밍에 대한 강의도 자료도 많지 않았었는데 이렇게 강의가 생겨서 너무 기쁘다.","categories":[{"name":"Logs","slug":"Logs","permalink":"https://sehajyang.github.io/categories/Logs/"}],"tags":[{"name":"weekly","slug":"weekly","permalink":"https://sehajyang.github.io/tags/weekly/"}]},{"title":"2018-11 월간회고","slug":"2018-11-27-2018-11-월간회고","date":"2018-11-26T15:00:00.000Z","updated":"2019-07-15T14:11:55.572Z","comments":true,"path":"2018/11/27/2018-11-27-2018-11-월간회고/","link":"","permalink":"https://sehajyang.github.io/2018/11/27/2018-11-27-2018-11-월간회고/","excerpt":"","text":"어쩌다보니 월간 회고가 됐다. 저번달 이맘때즈음 결국 리액트 프로젝트에서 발생한 오류를 해결하지 못하면서 슬럼프가 강하게 왔었다. 책도 많이 찾아보고 stackOverFlow에 질문도 몇번 올렸지만 결국 해결하지 못해서 그대로 개발도 주간회고도 길게 쉬었다. 그래도 언젠간 그 리액트 문제를 해결해보고 싶다. 그 간 몇가지 회사에서 코딩테스트를 보기도 하고 과제를 받기도 했는데 그 중 인상깊었던 과제를 몇가지 적어볼까 한다. (지금은 좋은 회사에서 좋은 분 들과 함께 일하고있다 😊) 개인공부 과제리액트+다이나모 디비+서버리스 과제모 회사 2차 면접 과제로 받았던 과제였다. 기간은 일주일(이지만 5일) 이었고 멜론같은 뮤직 어플리케이션 웹앱을 만드는 과제였다. 리액트로 프론트, 백엔드는 서버리스(Lambda+API Gateway+S3(Cloud Front) 등등), 디비는 다이나모 디비를 사용하는 것 이었다. 서버리스는 ASUG 핸즈온랩 세미나 이후로 한 적이 없었기 때문에 그야말로 대 패닉이었다! 여차저차 서버리스는 구현했고 다이나모 디비는 몽고디비와 비슷해서 괜찮았는데 리액트가 문제였다. 결론적으로 서버리스보단 리액트를 못해서 실패했다 😢 서버리스는 ASUG 세미나덕에 생각보다 빠르게 구현할 수 있었다. 기회가 된다면 또 가고싶다! 크롤링 과제모 회사의 과제였는데 두가지 알고리즘 문제를 푼 후 4가지 구현 과제 중 하나를 선택하는 것이었다. 그 4개 중 3개는 GraphQL 과제였는데 하나도 모르는 관계로 그나마 들어본(?) 크롤링을 선택했었다. node로 cheerio 라는 모듈을 사용해서 구현했었는데, 정말 잘 만들어져 있는 모듈이라서 생각보다 쉽게 구현 할 수 있었다. 그 당시 구글에서 만든 puppeteer라는 것을 사용하려고 했는데 국내에 예제가 없어 포기했던 기억이 난다. 시간이 있다면 크롤링은 꼭 해보고 싶은 것 중 하나다. 그 외과제가 작게는 게시판을 만드는 것 부터 쇼핑몰 홈페이지를 만드는 것 까지 더 나아가 서버리스..를 사용하는 것 까지 다양했다. 대게 공통점은 AWS로 배포하라는 것 이었는데, 요즘은 정말 많은곳에서 AWS를 필요로 하고있다는 생각이 든다. 아직 난 출발선인 것 같다 그래도 과거엔 AWS가 뭔지도 몰랐는데 지금은 조금이지만 안다는 것에서 발전하고 있는 것 같아 위안이 된다. 다음주 목표 백기선의 스프링부트 보고 TIL에 정리하기 러닝 자바스크립트 읽고 정리 자바스크립트를 너무 못하기 때문에.. 이제는 다른거 하지 말고 자바스크립트에 집중을 해야겠다는 생각이 들었다. 총평리액트 프로젝트에서 발생한 오류를 일주일 이상 잡지 못하면서 그대로 슬럼프가 왔었다. 나는 고작 이런 오류를 해결을 못했는데 과연 개발자에 재능이 있는가? 적성에 맞는가? 라는 의문이 들었기 때문이었다. 그래서 한동안 개발하는게 좀 꺼려졌었는데, 그러던 차에 우연히 좋은 회사에 들어가게 됐다. 다시 마음을 잡고 개발을 할 수 있을것 같다! 슬럼프 기간 동안 좋은 세미나가 많았는데 신청해두고 가지않거나 지인에게 줬었다. 왜 그랬을까.. Dev Festa, Jet BrainDay.. 정말 아깝다. 다음엔 슬럼프가 와도 세미나는 가야겠다. 개발할 때 동료나 팀원이 있는건 정말 중요하다는 걸 리액트 프로젝트 오류로 절절히 느꼈다. 그 때 주변에 같이 리액트를 공부하던 사람이 있었다면슬럼프가 오지 않았을 거 같다고 생각한다 😢 이번주는 좀 바빠서 본격적으로 다음주부터 공부를 시작할 것 같다 :D","categories":[{"name":"Logs","slug":"Logs","permalink":"https://sehajyang.github.io/categories/Logs/"}],"tags":[{"name":"weekly","slug":"weekly","permalink":"https://sehajyang.github.io/tags/weekly/"}]},{"title":"Java Interview Answer","slug":"2018-11-27-java-interview-answer","date":"2018-11-26T15:00:00.000Z","updated":"2019-11-16T08:45:45.549Z","comments":true,"path":"2018/11/27/2018-11-27-java-interview-answer/","link":"","permalink":"https://sehajyang.github.io/2018/11/27/2018-11-27-java-interview-answer/","excerpt":"","text":"KimJunJin님의 면접에 나왔던 질문의 답을 찾아서 정리 했습니다.Link 간결한 답을 위해 질문에 대한 답을 되도록 짧게 정리했습니다.이 문서는 종종 업데이트 됩니다 JAVA1. JVM 구조class(method area), stack, heap, native method, pc register로 이루어져있음 class : 값 임시저장, 상수 풀 , static변수 저장 stack: 메소드 안에서 사용되어지는 값 저장, 매개변수, 지역변수, 리턴 값 등 임시저장, 수행끝나면 프레임별로 삭제 heap : new로 생성된 객체와 배열 저장, gc를 통해 메모리 반환, 객체 주소값 저장 native method: 타 언어 메소드 저장 pc register: 쓰레드 생성시 생성되는 영역추가 2. GC 처리방법major, minor부분이 있다. 더이상 콜이 되지 않을 new로 만들어진 힙역에 할당된 아이템들을 수집해 삭제하는 작업을 한다.삭제된 객체의 메모리를 반환 Minor Garbage Collection 1. New 영역에서 일어나는 Garbage Collection ii) Eden영역에 객체가 가득 차게 되면 첫 번째 Garbage Collection 발생 iii) Survivor1 영역에 값 복사 iv) Survivor1 영역을 제외한 나머지 영역의 객체들을 삭제 v) Eden영역과 Survivor1영역의 메모리가 기준치 이상일 경우, Eden 영역에 생성된 객체와 Survivor1영역에 있는 객체 중 참조되고 있는 객체가 있는지 검사 vi) 참조되고 있는 객체를 Survivor2 영역에 복사 vii) Surviver2 영역을 제외한 영역의 객체들을 삭제 viii) 일정시간이상 참조되고 있는 객체들을 Old영역으로 이동 ix) 반복 Major Garbage Collection (Full Garbage Collection) i) Old영역에 있는 모든 객체들을 검사 ii) 참조되지 않은 객체들을 한꺼번에 삭제 iii) Minor Garbage Collection에 비해 시간이 오래 걸리고 실행 중 프로세스가 정지 출처 3. HashMap HashTable concurrentHashMap HashMap : 동기화 지원 안함 HashTable: 동기화 지원 함 concurrentHashMap : Java5 부터 지원하는 동기화 지원, HashTable보다 좋다고한다.참고 4. 접근제어자접근 영역을 제한할때 사용, 생략시 default로 셋팅 public : 제한 x default: 같은 패키지 protect: 상속이면 가능 private: 자신 클래스에서만 사용가능 5. interface, abstract의 차이 interface 다중 상속 가능, class body 있으면 안됨, 일종의 약속 abstract 단일 상속, class body 있어도 됨, 기능 재정의가 목적 6. StringBuilder, StringBuffer StringBuilder 동기화 미 지원, StringBuffer보다 빠르다. StringBuffer 동기화 지원 7. try with resourcesIO 예외시 자원을 자동으로 닫아준다.close()시 만약 예외가 발생할 경우 catch로 보내준다.참고 8. Synchronize동기화 하기 위함 Synchronize 방법 기본적으로는 Collections라는 util 클래스에서 제공되는 static 메소드를 통해 이를 해결할 수 있다.Collections.synchroziedList(), Collections.synchroziedSet(), Collections.synchroziedMap() 등이 존재한다.JDK 1.7 부터는 concurrent package를 통해 ConcurrentHashMap이라는 구현체를 제공한다.Collections util 을 사용하는 것보다 synchronized 키워드가 적용된 범위가 좁아서 보다 좋은 성능을 낼 수 있는 자료구조이다. 9. static은 메모리 어디에 올라가는가JVM의 class 영역 (method area)에 올라간다. 10. 컬렉션 프레임워크란DataStructure 를 직접 구현하지 않고 사용할 수 있는 것이며, 배열과는 다르게 객체를 보관하기 위한 공간을 미리 정하지 않아도 되므로상황에 따라 객체의 수를 동적으로 정할 수 있음으로서 프로그램의 공간적인 효율성 또한 높여준다. List List 인터페이스를 직접 @Override를 통해 사용자가 정의하여 사용할 수도 있으며, 대표적인 구현체로는 ArrayList가 존재하며, 이는 기존에 있었던 Vector를 개선한 것이다. 이외에도 LinkedList 등의 구현체가 존재한다.Map대표적인 구현체로는 HashMap이 존재한다.key-value 의 구조로 이루어져 있으며 Map 에 대한 구체적인 내용은 DataStructure 부분의 hashtable 과 일치한다.key 를 기준으로 중복된 값을 저장하지 않으며 순서를 보장하지 않는다.key 에 대해서 순서를 보장하기 위해서는 LinkedHashMap을 사용한다.Set대표적인 구현체로는 HashSet이 존재한다. value에 대해서 중복된 값을 저장하지 않는다.사실 Set 자료구조는 Map 의 key-value 구조에서 key 대신에 value 가 들어가 value 를 key 로 하는 자료구조일 뿐이다.마찬가지로 순서를 보장하지 않으며 순서를 보장해주기 위해서는 LinkedHashSet을 사용한다. 11. Stack 과 QueueStack 객체는 직접 new 키워드로 사용할 수 있으며,Queue 인터페이스는 JDK 1.5 부터 LinkedList 객체를 통해 new 키워드를 통해 사용할 수 있다.출처 12. 제네릭컴파일과정에서 타입체크, 객체의 타입안정성 높인다. collection에 특정객체만 추가될 수 있도록 한다. 13. Vector와 List 차이에 대해 설명하시오. Vector 연속적인 메모리, 미래에 들어갈 요소 위해 선할당 함, 메모리 재할당 가능 List 비연속적 메모리, 선할당 안함, 추가제거 잦을시 사용 14. Overloading Overriding 차이는? Overriding자식클래스에서 부모클래스 메소드를 재정의한다.super()를 쓰면 부모클래스 메소드를 사용한다.Overloading같은 이름이지만 매개변수의 종류 및 숫자가 다른 메소드같은 기능이지만 다른 인자를 수행하는 메소드 정의시 사용. 15. CheckedException과 UnCheckedException의 차이를 설명하시오. CheckedException 반드시 예외처리 해야함, 컴파일단계에서 에러남 ex) IOException, SQLException UnCheckedException 예외처리 강제안함, 실행단계에서 에러남 ex) NullPointer, ILLegarArgument, Out Of Bound Exception등등 16. OOP란 무엇인가?객체지향, 크게 3가지 특징이있다. 추상화, 캡슐화, 다형성 추상화 굳이 구현할 필요없는 부분을 생략하고 필요한 부분만을 나타내는 것. 다형성 하나의 메소드나 클래스가 다양한 방법으로 동작하게하는 요소 단순한 상속이나 인터페이스가 구현이 된 클래스 계층적으로 다단계 상속을 이루고 있는 클래스 여려개의 인터페이스를 한번에 구현한 클래스 등으로 표현된다. Overriding, Overloading 이 있다. 캡슐화(encapsulation) 메소드의 기능만 알며, 어떻게 동작하는지는 알필요 없이 사용하는 것 외부에서 변경 불가하게 private로 선언하고 setter getter 메소드를 통해서만 접근 가능하다. 무결성을 보장한다. 17. final / finally / finalize 의 차이를 설명하시오. final변경 불가능finally예외처리에서 무조건 실행하는것finalize()gc에 의해 호출되는 메소드, 이거 잘 못하면 OOME(Out of memory Exceprion) 발생하니까 건들지 말 것 final class : 상속x, final method : overriding x, final var : 상수 18. new String()과 “”의 차이에 대해 설명해주세요.new String()은 heap내의 spring pool에 객체 생성 뒤 그 객체의 주소를 가지게 되는 것“”는 문자열 자체를 저장 후 그 배열의 인덱스 번호를 가리킴추가 : 상수풀 19. 스프링 IOC가 무엇인가요? (보충)) IOC란 제어의 역전으로, 제어권을 스프링에게 위임하여 스프링이 만들어둔 객체를 주입한다스프링이 모든 의존성 객체를 스프링이 실행될 때 만들어두고 필요한곳에 주입시켜준다.그래서 bean 들은 싱글턴 패턴의 특징을 가진다.그렇게 제어의 흐름을 사용자가 컨트롤하는게 아니고 스프링에게 맡겨 작업을 처리한다.IOC를 구현하는 방법중 DI 가 있다. 내가 new로 객체만드는게 아니고 스프링이 필요할때 지가 알아서 만든다.출처 20. OOP와 AOP에 대한 차이를 설명해주세요.OOP : 모든 데이터를 오브젝트로 취급하여 프로그래밍 하는 방법,독립적으로 사용하거나 부품으로 사용하므로 재사용성 및 결합 가능특징 1) 캡슐화 (Encapsulation) 사용하고자하는 자료,로직,동작을 하나의 단위(함수)로 묶는 것이다.2) 은닉화 (Data Hiding) 외부에 필요한 정보만 공개하고 나머지의 정보는 숨긴다.3) 다형성 (Polymorphism) 호출하는 객체에 따라 다른 동작을 하는 기능이다. (가상함수 재정의)4) 상속성 (Inheritance) 이미 만들어진 클래스를 파생시켜 새로운 클래스를 만들수 있는 기법이다.5) 재사용성 (Reusability) 기존에 만들어진 객체를 다른 프로젝트나 필요한 부분에 그대로 가져다 재사용하는 것이다.출처: http://godkyu.tistory.com/11 AOP : 관점지향, 코드 밖에서 설정 된다, ex)logger 21. POJO가 무엇인가요?setter, getter로 이루어진 Java bean 별도의 API가 필요하지 않은 일반적인 자바코드를 이용해서 개발 가능하다. 22. Annotation이란?주석처럼 코드에 단다. 그러나 클래스에 의미를 부여하거나 기능을 주입 할 수 있다.build-in annotation, meta annotation, custom annotation이 있다. JS 클로저에 대해 설명해주세요.Closure(클로저)는 두 개의 함수로 만들어진 환경 으로 이루어진 특별한 객체의 한 종류함수 내부에 작성된 함수사이드 이펙트(무언가를 행할때 발생) 제어하기, private 변수 생성하기 목적으로 사용참고링크 변수스코프체인에 대해 아시나요?스코프란 유효범위, 전역과 지역이 있다.참고링크 전역변수를 함수 내부에서 사용하면 성능상 이슈가 발생하는데 그 이유와 해결책에 대해 설명해주세요.지역변수에 먼저 접근 후 없으면 전역변수에 접근하기때문에 지역변수보다 느리다.또한 가비지 컬렉터가 제대로 스윕을 못해서 메모리 누수가 발생할 수 있다.해결책 : 지역변수를 쓴다. 자바스크립트에서 클래스는 어떻게 사용하나요?function을 class로서 사용한다.리터럴방식, 함수방식, 프로토타입 방식이 있다.클래스 인스턴스를 생성해야만 클래스에 들어있는 함수들의 내부기능을 사용할 수 있다. 호이스팅이란?변수 선언문을 끌어올린다 라는 뜻함수 선언문 방식만 호이스팅 가능 자바스크립트 OOP Network 데드락에 대해서 설명하시오. 데드락 4대요소에 대해 설명하시오. 상호배제(Mutual exclusion) : 프로세스들이 필요로 하는 자원에 대해 배타적인 통제권을 요구한다.점유대기(Hold and wait) : 프로세스가 할당된 자원을 가진 상태에서 다른 자원을 기다린다.비선점(No preemption) : 프로세스가 어떤 자원의 사용을 끝낼 때까지 그 자원을 뺏을 수 없다.순환대기(Circular wait) : 각 프로세스는 순환적으로 다음 프로세스가 요구하는 자원을 가지고 있다. 출처링크 멀티 스레드 환경에서의 주의사항을 설명해주세요.공유 자원 관리동기화 작업 필요 그러나 데드락 주의 사용자 수준 스레드와 커널 수준 스레드의 차이를 설명해주세요. DB 디비 풀은 왜 쓰나요?빠른 할당을 위해커넥션풀 : DB와 연결된 커넥션을 미리 만들어서 풀(pool)속에 저장해두고있다가 필요할 때 쓰는 것 디비 실시간 통신과 디비풀 이용시의 차이가 무엇인가요?실시간 통신은 요청을 할 때마다 매번 드라이버 로드하고 커넥션 객체 생성 후 연결 종료한다.커넥션풀은 동시접속자 수가 가질 수 있는 커넥션을 하나로 모아두고 관리한다.커넥션 생성하고 닫는 시간이 소모되지 않기 때문에 어플리케이션 속도 빨라지며, 한번에 생성될 수 있는 커넥션 수를제어하기 때문에 동시 접속자 수가 몰려도 쉽게 웹이 다운되지 않는다.풀 이상으로 접속자가 많아지면 해당 클라는 대기가 되고 대기하고 있는 순서대로 커넥션이 제공된다. SQL에서 left join에 대해 설명하시오. RDBMS와 NoSQL의 차이는? RDBMS : 유연한 쿼리 가능하지만 쿼리비용 높으며 트래픽 많은 상황에선 확장성 떨어진다.NoSQL : 최초 테이블 생성시 데이터간의 관계를 정의하지 않는다. 대용량 가능, 분산형 구조, 데이터를 저장만 하므로 key, value 만 있고 put, get 만 지원한다. index에 대한 설명과 장/단점으로 무엇이 있나요.index란 : RDBMS에서 검색속도를 높이기 위해 사용하는 기술, 일종의 색인장단점 : https://lalwr.blogspot.com/2016/02/db-index.html (보충) 몽고DB의 특성에 대해 설명해주세요. SQL Injection은 무엇인가요? ACID에 대해 설명해주세요. (Atomic, Consistency, Isolation, Durability) 1차 정규화, 2차 정규화, 3차 정규화, BCNF에 대해 설명해주세요. 정규화 : 논리적 데이터베이스 설계에 있어서 테이블들을 구조화하는 기법 중 하나자료의 손실이나 불필요한 정보의 도입 없이 데이터의 일관성 및 데이터 중복을 최소화하고 최대의 데이터 안정성 확보를 위한 안정적 자료구조로 변환하기 위해서 하나의 테이블을 둘 이상으로 분리하는 작업 제1정규형(1NF) : 테이블의 각 셀의 값은 단일값을 가진다.제2정규형(2NF) : 주키가 합성키며 부분종속이 존재할 경우 2차 정규형의 대상이 된다.제3정규형(3NF) : 비주키 속성 간에 발생하는 함수적 종속(이전종속)이 발생하면 3차 정규형의 대상이 된다. 출처 DB Nomalization(정규화)의 목적은?저장 공간 최소화데이터 무결성 유지자료구조의 안정성 최대화 ETC url에 www.naver.com을 입력했다. 일어나는 현상에 대해 아는대로 설명하라.브라우저에서 주소창에 url 입력시 어떤일이 일어나는가브라우저의 주소창에 url 입력브라우저 캐시에서 DNS 레코드를 확인하여 IP주소를 찾음 (없다면 DNS resolver를 통해 IP주소를 알아냄)브라우저가 서버와 TCP 연결을 시작함브라우저가 웹 서버에 HTTP 요청을 보냄서버가 요청을 처리하고 응담을 되돌려보냄브라우저는 서버가 보낸 HTML 내용을 표시 출처 Serialize와 json의 상관관계에 대해 설명하시오.직렬화(Serialize)자바 시스템 내부에서 사용되는 Object 또는 Data를 외부의 자바 시스템에서도 사용할 수 있도록 byte 형태로 데이터를 변환하는 기술.JVM(Java Virtual Machine 이하 JVM)의 메모리에 상주(힙 또는 스택)되어 있는 객체 데이터를 바이트 형태로 변환하는 기술 스레드풀에 대해 설명. 왜 쓰는지. 무엇인지.스레드를 사용할 때 마다 하나씩 만들기보다 미리 먼저 많이 만들어두는 것프로그램 성능저하 방지 및 다수의 사용자 요청 처리를 위해 사용추가 Serialize로 데이터를 통신할 때 문제점에 대해 설명하시오. call by value와 call by reference의 차이에 대해 설명하시오. 개방폐쇄 원칙에 대해 구체적으로 설명해보시오. 해시함수 sha-1에 대해 설명하시오. DI (Dependency Injection)에 대해 설명하시오.객체간의 의존관계를 개발자가 설정하는게 아니고 스프링컨테이너가 주입시켜준다.(의존관계란 ex) Animal()은 Cat()에 의존한다)B가 바뀌면 A도 바뀌는걸 의존관계라고 한다. DAO DTO에 대해 설명하시오. MVC 패턴에 대해 설명하시오. 디자인 패턴 중 Factory패턴과 Templete패턴에 대해 구체적 예를 들어 설명하시오. 프레임워크와 라이브러리의 차이는 무엇인가요? 프레임워크 : 뼈대, 틀, 내가 맞추는 것 라이브러리 : 도구, 내가 사용하는것 자바와 자바스크립트 차이를 설명해주세요. 깊은 카피와 얕은 카피에 대해 설명해주세요. 컴파일러와 인터프리터의 차이는 무엇인가요? HashTable의 충돌 해결 방법을 설명해주세요. 대칭키/비대칭키 암호화 차이대칭키 : 암복호화 해제 키가 같다비대칭키 : 암복호화 해제 키 다름 분산락이란 무엇인가요? Etc2 Typescript 특징MS 에서 만든 javascript로 컴파일되는 언어, 클래스, 모듈 및 인터페이스를 제공한다.대규모 응용 프로그램 적용이 가능하다. React Redux란?어플리케이션 클라이언트 쪽 state를 관리하기위한 거대한 이벤트 루프액션 = 이벤트, 리듀서 = 이벤트에 대한 반응","categories":[{"name":"Java","slug":"Java","permalink":"https://sehajyang.github.io/categories/Java/"}],"tags":[{"name":"studylog","slug":"studylog","permalink":"https://sehajyang.github.io/tags/studylog/"},{"name":"daily","slug":"daily","permalink":"https://sehajyang.github.io/tags/daily/"}]},{"title":"181015-181021 주간회고","slug":"2018-10-21-181015~181021","date":"2018-10-20T15:00:00.000Z","updated":"2019-07-15T14:11:55.571Z","comments":true,"path":"2018/10/21/2018-10-21-181015~181021/","link":"","permalink":"https://sehajyang.github.io/2018/10/21/2018-10-21-181015~181021/","excerpt":"","text":"이번주는 리액트+노드 개인 토이 프로젝트를 했고, 일일 1알고리즘을 했다. 리액트를 다루는 기술이란 책을 참고하면서 했는데 책 예제를 할땐 할 만 하다고 생각했지만 막상 프로젝트를 만들고 기능을 추가하려다 보니 굉장히 어려웠다. 개인적으로 스프링보다 훨씬 어려웠다ㅜㅜ 게다가 NoSQL인 MongoDB 를 사용해서 프로젝트를 해보긴 처음이라 헤매기도 했다. 개인공부-지인과 일일 1 알고리즘 풀기를 시작했다. 나름 거의 빼먹지 않고 성실하게 커밋하고 있어서 뿌듯하다. 초반이라 쉬운 패턴 찾기 문제+ 자료구조 기본 문제를 풀었다. 프로젝트에 올인하느라 좀 소흘해져서 다음날 넘어가기 직전에 커밋한적이 많았는데 내일부턴 좀 더 시간을 할애해야겠다. -리액트는 정말 어려운 것 같다. 재미는 있는데 어렵다. 프론트 작업을 거의 다 끝냈다. 다 좋은데 어떤 값을 백엔드로 넘겨줘야되는데 뭘 잘못한건지 모르겠지만 값을 못 넘겨주고 있어서 하루째 골머리를 앓고있다. 이번 프로젝트에서 마주친 거의 첫 문제라고 할 수 있겠다. 생각했던 모든 기능을 구현하는데에 일주일정도 걸릴것으로 생각했는데 이 부분에서 문제가 생길줄은 몰랐기 때문에 완성까진 더 걸릴 것 같다. 일단 다시 책이나 강의를 보면서 이해를 하고 해결해봐야겠다. 모르는게 많아서 단시간에 해결되진 않을 것 같다. -노드로 짠 백엔드 단은 문제가 없다. 몽고디비를 처음 써봐서 쿼리짜는데에 에러사항이 있었지만 다행히 금방 해결할 수 있었다. 쿼리를 짜주는 사이트도 있었다 RDBMS 쿼리를 입력하면 몽고디비 쿼리로 바꿔주는 사이트인데 앞으로 요긴하게 쓸 것 같다. 프론트부분의 문제가 해결되면 기능을 더 늘릴 예정이다. 다음주 목표 프론트 문제 해결하기 일일 1 알고리즘 빼먹지않기 노드 프로젝트 뼈대 잡기 총평오랜만에 하루종일 코딩할 수 있었다. 그리고 리액트는 정말 어려웠다. 개인적으론 스프링보다 훨씬 어렵다. 문제가 발생한 원인을 꼬박 생각해봤는데 어떻게 해야할지 아직 잘 모르겠다. 이렇게까지 막힌적은 처음인 것 같다. 흐름을 좀 그려보면서 정리해봐야겠다. 노드도 모르는 것 투성이고 새삼 스프링이 참 무언가를 빠르게 만들기 쉬웠구나 하고 생각하게된다. 그래도 스프링보다 재미있는 것 같다.","categories":[{"name":"Logs","slug":"Logs","permalink":"https://sehajyang.github.io/categories/Logs/"}],"tags":[{"name":"weekly","slug":"weekly","permalink":"https://sehajyang.github.io/tags/weekly/"}]},{"title":"181001-181007 주간회고","slug":"2018-10-07-181001~181007","date":"2018-10-06T15:00:00.000Z","updated":"2019-07-15T14:11:55.571Z","comments":true,"path":"2018/10/07/2018-10-07-181001~181007/","link":"","permalink":"https://sehajyang.github.io/2018/10/07/2018-10-07-181001~181007/","excerpt":"","text":"이번주엔 노드공부와 리액트를 했고 Dev Django 세미나에 갔다왔다! 지인과 알고리즘 스터디를 시작했다 요즘 별로 한 것도 없는거 같은데 슬럼프가 온 것 같다ㅜㅜ 개인공부-Dev Django Korea 2018 세미나에 갔다왔다. 나는 Spring과 Node를 하기때문에 장고에 대해선 잘 몰랐지만 구직사이트를 보면 종종 사용하는 기술에 장고가 있던것이 기억나기도 하고 궁금해서 갔다왔다 한번 시험삼아 장고걸스의 장고 get started를 보며 따라해 본 적이 있었는데 중간에 오류가 나기도 하고 당시에 바빴어서 금방 그만둔 기억이 났다. 아무것도 모르는 상태로 갔는데 초보자가 들을 수 있는 세션도 있었다. 장고의 장단점에 대해서도 알 수 있었다. 장점 : 데이터 분석이 용이(python), 빠른 개발가능, 복잡하고 무결성이 보장되어야하는 트랜잭션이 있을때 사용하면 좋다 단점 : 구조 복잡, 학습이 어려움(한국어로 된 자료가 별로 없음), 커스텀 힘듬 특히 단점은 학습이 어렵다는게 와 닿았다. 에러가 나도 자료가 많지 않았고 시작하려고 해도 한국어로 된 강의나 책 등이 적었던 기억이 났다. -혼자 하는 것 보다 의무감을 가질 수 있을 것 같아서 지인과 일일 1 알고리즘 풀기를 시작했다. 자바 버전과 파이썬 버전으로 풀고있는데 파이썬 버전을 미루고 있다.. 그래도 쌓여가는 알고리즘 푼걸 보니 뿌듯하다. 이렇게 3년하면 알고리즘 고수가 될수 있겠지…? -리액트는 하면 할 수록 어려워서 만들던걸 중단하고 모르는거 하나하나 찾아보고 있다ㅜㅜ 다음주 목표 리액트 공부 일일 1 알고리즘 빼먹지않기 노드 프로젝트 뼈대 잡기 총평슬럼프가 좀 길어지고 있는 것 같은데 최근에 슬럼프가 끝날 기미가 보이는 것 같다. 알고리즘 어떤 한문제를 못풀어서 하루를 꼬박 보낸 일이 있었는데 역시 알고리즘은 아직 갈길이 굉장히 먼 것 같다. 중간에 좀 느려도 멈춰도 포기하지 말자는 생각으로 해야겠다.","categories":[{"name":"Logs","slug":"Logs","permalink":"https://sehajyang.github.io/categories/Logs/"}],"tags":[{"name":"weekly","slug":"weekly","permalink":"https://sehajyang.github.io/tags/weekly/"}]},{"title":"180917-180923 주간회고","slug":"2018-09-23-180917~180923","date":"2018-09-22T15:00:00.000Z","updated":"2019-07-15T14:11:55.569Z","comments":true,"path":"2018/09/23/2018-09-23-180917~180923/","link":"","permalink":"https://sehajyang.github.io/2018/09/23/2018-09-23-180917~180923/","excerpt":"","text":"이번주엔 스프링부트 세미나와 서버리스 핸즈온 랩 세미나를 갔다왔다. 그 외에도 진행중인 노드 프로젝트의 CI를 급하게 구축하거나 알고리즘 공부를 하는 등 꽤 바쁜 한주였다. 개인공부스프링부트 세미나)를 갔다왔다! T Academy 에서 한거였는데, 경쟁률이 쌘 것 같아 떨어질까 조마조마 했지만 다행히 붙어서 잘 갔다왔다. 그곳에서 실습한 내용은 혼자 공부한 내용과 많이 비슷했지만 개인 질문시간에 궁금했던 것을 전부 물어볼 수 있어서 굉장히 유익했다. 스프링부트에 관한 내용이 아직 인터넷에 많진 않기 때문에 궁금한 부분이 꽤 많았는데 직접 굉장한 분께 들을 수 있어서 좋았다. 그 분이 RESTful API도 잘하셔서 RESTful에 대해서 궁금했던 것도 물어 볼 수 있었다. 스프링 부트 개념과 활용 강좌를 아직 다 보지 못했는데 봐야겠다.스프링 부트에 대해서 좀 더 잘 알고싶다. 근데 이거 말고도 할게많네.. -서버리스 세미나 를 갔다왔다! ASUG에서 한 거였는데, 노드도 조금 AWS도 조금 해봐서 따라가는데엔 무리가 없었지만 초보자 대상은 아니었던 것 같다. 그래도 직접 실습해보고 구축해본다는게 즐거웠다. 그렇게 서버리스에 뭔지에 대해서 조금 알 수 있게 되어서 너무 좋았다. 세미나를 들으며 몇개월 전 수동으로 하나하나 빌드 배포하고 서버돌렸던게 생각났다. 서버리스는 굉장한데 어렵긴했다. 그래도 잘 하면(?) 사용할 수 있을 것 같(은기분이 든)다. -알고리즘 문제를 풀 일이 있었는데. 나는 정말 아직 엄청 멀었구나 싶다ㅠㅠ 그런 전산적인 뇌가 되려면 어떻게 해야하는걸까…. 일단 하고있는 알고리즘 책 마저 끝내고 다시 백준 문제 풀면서 알고리즘 문제해결전략을 봐야겠다.. -추석이 끼면서 프로젝트 오프가 애매해졌다. 일단 노드부터 해야겠다! 익숙치 않은 기술을 잔뜩 쓰기 때문에 공부할게 엄청 많다. CI 구축에 문제가 있어 일단 이슈로 올려뒀다. 이것도 저것도 다 하려면 어떻게 해야하는걸까 아직은 선택과 집중을 잘 모르겠다. 다음주 목표 알고리즘 스터디 프로젝트 개발 및 공부 (Node.js) 총평요즘들어 회의가 든다. 전산능력(?)이 탄탄하면 웹 개발에 던져놓아도 금새 고수가 된다고 한다. 하지만 할 줄 아는게 많아도 그런 기본기가 없으면별 의미가 없다고 한다. 그래서 요즘 기업에선 알고리즘 테스트를 하나보다. 새로운 기술같은거 하지 말고 아키텍쳐나, 알고리즘, 네트워크 등에 집중해야 되나 라는 생각이 든다. 나는 웹 만드는게 재밌는데 그게 아무나 할 수 있는거고 내가 전산 베이스가 탄탄하게 안되어있으면 실력에 한계가 온다는게,그래서 요즘 내가 새로운 많은 기술을 배우는게 과연 잘하는 것 인가 하는 의문에 빠졌다. 최근에 자신있던 스프링 구조도 설명을 못한 일이 있었다. 내가 알고있던게 틀리면 어떡하지 싶어서 말을 못했는데, 그런걸 자신있게 말할 수 있는 사람이 되고싶다.","categories":[{"name":"Logs","slug":"Logs","permalink":"https://sehajyang.github.io/categories/Logs/"}],"tags":[{"name":"weekly","slug":"weekly","permalink":"https://sehajyang.github.io/tags/weekly/"}]},{"title":"180910-180916 주간회고","slug":"2018-09-16-180910~180916","date":"2018-09-15T15:00:00.000Z","updated":"2019-07-15T14:11:55.568Z","comments":true,"path":"2018/09/16/2018-09-16-180910~180916/","link":"","permalink":"https://sehajyang.github.io/2018/09/16/2018-09-16-180910~180916/","excerpt":"","text":"이번주는 기초 공부를 하게 된 주 였다. 그 과정에서 내가 얼마나 먼지같은 존재인지 다시금 느낄 수 있었다.. 더불어 오래간만에 프로젝트를 시작하게 되었다. 개인공부자바, 디자인패턴, 자바스크립트, 알고리즘, DB 등 많은 내가 그간 배웠던 지식에 대해 다시 복습 할 수 있었다. 아키텍쳐는 볼때마다 새롭고 어렵다. 아직 잘하는 개발자가 되려면 멀은 것 같다. 그래도 예전에 비해선 발전 한 것 같아서 다행이다. -배울때 그렇게 배웠기 때문에 한번도 생각해보지 않고 그냥 쓰던 것에 대해 그걸 왜 그렇게 쓰냐는 질문을 봤다. 약간 충격을 받았다. 컴퓨터 공부는 늘 이제 좀 알겠다 싶으면 그건 사실 먼지만한 지식이었고 실제로 배워야할 건 어마어마한 것임을 깨닫게된다. 신 기술을 배우기에만 급급했던 건 아닐까 반성을 하게된다. -지인들과 새로운 토이프로젝트를 하게 되었다 신난다! 내가 개인적으로 만들면 늘 규모가 아쉬웠는데 이것도 해보고 저것도 해보고 할 수 있어서 즐겁다 무엇보다 같이 하면 의무감이 생기고 지치지 않는 것 같아서 좋다. -JetBrains Day 2018 신청을 했다. 요즘 코틀린이 핫하다. 카카오 개발자 컨퍼런스에서 카카오택시 서버사이드를 코틀린으로 바꿨다는 세션이 있었다고한다. 코틀린이 어떤건지 궁금해서 신청했다. 다음주엔 스프링부트 세미나가 있다. 신청은 했는데 신청자가 몰릴거같은 주제라 될지 안될지 모르겠다.. 2018 F/W 초보자를 위한 AWS 뿌시기 를 간다! AWS는 독학했기 때문에 초보자 수준이고 모르는 것도 많아서 AWS meetup을 가는게 좋을 것 같아서 신청했다. 다음주엔 쿠버네티스 차근차근 다지기 도 있는데 이건 시간이 없어서 신청을 못했다 진짜.. 너무 가고싶었는데 슬프다. 왜 늘 바쁜시기에 꼭 가고싶은 세미나가 있는걸까..? 다행히 세미나 라이브 방송을 해서 집에서 들을 수 있을거같다. 다음주 목표 기초 정리 알고리즘 스터디 정해진 분량 하기 (Python, Java) 프로젝트 개발 환경 및 협업 베이스 구축 Node.js 공부 총평기초 공부도 갈 길이 멀다는 생각을 했다. 나는 이런것도 모르고 개발한다고 했나 싶은 것도 많았다 굉장히 부끄러웠다. 대규모 웹 서비스를 해보고 싶어서 관련 자료를 이것저것 찾아보고 있다. 언젠간 대규모 웹 서비스를 개발해 안정적으로 서비스하는 슈퍼 개발자가 될 수 있겠지..? 최근들어 깨달았는데 개발공부를 할때 처음부터 기술 하나 차곡차곡 쌓고 마스터! 그건 좀 이상적인 것 같다. 개인적으로 개발공부는 거대한 퍼즐조각이라고 생각한다. 이 그림 저 그림 다 섞여있는 퍼즐조각 이라서 한개만 마스터 할 순 없고(골라내기엔 너무 방대한 조각이다) 손에 집히는 대로 이거 맞추다 저거 맞추다 하다보면 어느새 하나 둘 씩 완성되는 그런게 아닐까 생각한다..","categories":[{"name":"Logs","slug":"Logs","permalink":"https://sehajyang.github.io/categories/Logs/"}],"tags":[{"name":"weekly","slug":"weekly","permalink":"https://sehajyang.github.io/tags/weekly/"}]},{"title":"180903-180909 주간회고","slug":"2018-09-09-180903~180909","date":"2018-09-08T15:00:00.000Z","updated":"2019-07-15T14:11:55.567Z","comments":true,"path":"2018/09/09/2018-09-09-180903~180909/","link":"","permalink":"https://sehajyang.github.io/2018/09/09/2018-09-09-180903~180909/","excerpt":"","text":"이번주는 파이썬 공부에 집중한 주 였다. 장고를 하며 파이썬을 배울 생각이었지만, 장고를 조금 해보니 그냥 파이썬을 먼저 하는게 좋을 것 같다. 그래서 거의 파이썬만 주구장창 했다. 개인공부파이썬은 꽤 오래전 부터 공부하려 했었는데, 어쩌다보니 미루고 미루다 이제 시작하게 되었다. 카카오 코딩테스트 해설에서 가장 짧은 라인수를 자랑하는 언어라고 하는걸 본 적이 있다. 그땐 그렇구나 역시 인기많은 이유가 있구나 하고 넘어갔는데, 배워보니 왜 그런지 알 것 같다. 더불어 왜 배우기 쉬운 언어라는지도 어렷품히 알 것 같다. 배우면 배울수록 앞으로 알고리즘 문제는 파이썬으로 풀어야겠다는 생각이 강해진다. -Django 공부를 겁도없이 시작했다.. 아직은 아무것도 모르겠다ㅜㅜ 문법도 모르겠고 아무것도 모르겠고.. 일단 엎고 파이썬부터 하고있다.. -운영체제 공부는 그냥 대학다닐때 강의 듣는 느낌이다. 까먹어가던거 다시 복습하는 느낌이다.. 다음주 목표 파이썬 지금 보고있는 책 끝내기 알고리즘 문제 파이썬으로 깔짝거리기 운영체제 강의 나머지 수강 Django 공부시작 총평이번주는 좀 나태했던 것 같은데, 연이은 개인 프로젝트 탓으로 치부하기엔 너무 놀았던 것 같다.. 반성.. 새로운거 배울 땐 질질 끌면 안되는데 왜 파이썬만 하려고 하면 질질 끌게 되는지 알 수 없다. 자바랑은 비슷하면서도 다른점이 굉장히 많아서 배울땐 신기하게 적용할땐 쉽게 해보고있다. 몇개월 전에 만들으려다 미뤄뒀던게 있었는데 이번에 파이썬으로 두세줄만으로 만들 수 있었다 그게 굉장히 기억에 남는다. 노력을 하지만 눈에 보이지 않으면 불안해지는데 이렇게 가끔가다 발전을 확인하게 되면 다행인 것 같다. 배우는 만큼 만들 수 있는 범위가 넓어지는 것 같아 기쁘다. 다다음주엔 스프링부트 세미나가 있는데 됐으면 좋겠다. 저번에 날림으로 프로젝트 만드느라 삽질했던게 한두개가 아니라서 가서 배울 수 있으면 좋겠다… 최근들어 핫한 4차 산업혁명 기술들을 배워야 하는 생각이 든다. 내 주변에선 점점 머신러닝, 빅데이터등을 배우고 있다. 나는 아직 웹도 배워야할게 산더미인데 초보 개발자가 그러한 어려운 기술을 배워야 하는건가 하는 생각이 든다. 그래도 구인공고에서 종종 눈에 띄고 점점 모집하는 곳도 늘어나는 것 같고, 세미나도 늘 4차 산업혁명 관련 기술이고 정말 핫한건 맞는데 안 배우며 버티고 있는건 내 아집인가 싶기도 하다. 누가 초보 개발자는 4차 산업혁명 기술 안해도 된다고 해줬으면 좋겠다.. 그도 그럴게 웹 공부도 할게 너무 많고 아직도 모르겠다 엉엉..","categories":[{"name":"Logs","slug":"Logs","permalink":"https://sehajyang.github.io/categories/Logs/"}],"tags":[{"name":"weekly","slug":"weekly","permalink":"https://sehajyang.github.io/tags/weekly/"}]},{"title":"180827-180902 주간회고","slug":"2018-09-02-180827~180902","date":"2018-09-01T15:00:00.000Z","updated":"2019-07-15T14:11:55.566Z","comments":true,"path":"2018/09/02/2018-09-02-180827~180902/","link":"","permalink":"https://sehajyang.github.io/2018/09/02/2018-09-02-180827~180902/","excerpt":"","text":"이번주는 어쩌다보니(?) 여러 기술들을 많이 써보고 프로젝트도 해보는 주 였다. 당초 계획은 알고리즘과 컴퓨터 구조(운영체제 등) 공부에 집중하자! 였지만 어쩌다 보니 노드 웹 크롤링과 스프링부트 프로젝트를 하게 되었다. 생소하고 어려워서 삽질도 많이 했지만, 하다보니 하나씩 되는게 즐거웠던 것 같다. 하지만 결과물은 처참했기 때문에 아직 멀은 것 같다. 개인공부이번주는 알고리즘 문제와 웹 크롤러, 스프링부트 프로젝트를 했다. 이번 기회로 스프링과 스프링부트의 차이점을 알게되었고, 왜 많은 사람들이 스프링 부트를 찬양하는지도 알게되었다. 스프링보다 설정잡을게 적고 에러도 적게 나고 편리한 어노테이션도 있어서 굉장히 스프링 할때보다 스트레스 덜 받으며 재밌게 만들었다. 웹 크롤링은 처음 해 봤는데 간단한 홈페이지 하나 만들 수 있을 것 같아서 생각 해 두고 있다. 이번에 만든건 굉장히 초보자의 크롤러였지만, 하다보면 늘지 않을까.. 학교 다닐때 C 언어 포인터가 굉장히 어려웠었고 다 까먹었기 때문에 주말에 남궁성님의 C 언어 세미나를 갔다왔다. 확실히 옛날보단 이해가 됐지만 아직 어려워서 조금 더 공부해봐야겠다. -RESTFul 방식으로 스프링부트 웹을 만들었는데, RESTFul에 대해 대략적으로만 알고있어서 내가 이해한 대로 구현했더니 이건 아닌 것 같았다. 이건 좀 더 공부해보고 이번에 만든 스프링부트 프로젝트를 뜯어 고쳐야겠다. -드디어 운영체제 공부를 할 수 있다! 다음주는 운영체제 공부 및 알고리즘에 집중 할 예정이다. -요 일주일 내내 프로젝트를 달리면서 아직 갈 길이 멀다는걸 느꼈다. 그리고 설계의 중요성을 통감했다. 기간이 정해지면 마음이 급해져서 설계에 오랜시간이 걸리게되면 초조해진다.그렇게 설계를 날림으로 하고 나중에 뜯어고치느라 고생하는데, 좋은 방법이 없을까..? -최근들어 파이썬 공부가 필요하다고 느끼고 있다. Django로 작은 웹사이트 만들어보면 좋을 것 같은데 아직은 당장 해야할 게 많기 때문에 조금 미뤄둬야겠다.. 다음주 목표 알고리즘 문제 스터디 운영체제 강의 수강 총평어쩌다보니 이번주는 굉장히 새로운 걸 적용해서 뭔가 만들어야 했기 때문에 어느정도 스트레스 받기도 했지만, 하나씩 기능이 만들어지고 동작해서 즐겁게 할 수 있었다. RESTFul, TDD등 평소에 궁금했던걸 경험해 볼 수 있었고, 스프링부트 웹 크롤링 등 들어봤던 기술들을 사용해 뭔가 만들었기 때문에 어쩌다보니 다양한 경험과 시도를 한 주였다. 다음주엔 우분투 서울지역 세미나가 있는데 내가 컴퓨터공부를 시작하게 된 계기가 리눅스 우분투인 것 만큼 굉장히 기대된다.","categories":[{"name":"Logs","slug":"Logs","permalink":"https://sehajyang.github.io/categories/Logs/"}],"tags":[{"name":"weekly","slug":"weekly","permalink":"https://sehajyang.github.io/tags/weekly/"}]},{"title":"180820-180826 주간 회고","slug":"2018-08-26-180820~180826","date":"2018-08-25T15:00:00.000Z","updated":"2019-07-15T14:11:55.566Z","comments":true,"path":"2018/08/26/2018-08-26-180820~180826/","link":"","permalink":"https://sehajyang.github.io/2018/08/26/2018-08-26-180820~180826/","excerpt":"","text":"이번주는 저번주에 결심했다시피 기초 및 기본을 좀 더 다지려는 주였다. 미뤄왔던 알고리즘 공부도 시작했다! 그리고 웹 개발에 있어 방향을 좀 더 잡은 주였다. 스프링 프레임워크와 자바를 사용해서 웹을 만드는 것 보다 Nodejs로 구현하는 것에 크게 매력을 느끼고 있어 Node.js로 방향을 틀었다. 사실 내가 할수 있는 것과 하고 싶은 것의 고민은 있었지만 아직 시작일때 하고싶은걸 하자 라고 생각했다. 개인공부구현하고 싶은건 잔뜩 있지만 기본이 다지지 않은 상태에서 무리하게 기술을 쌓고있던게 아니였나 싶어 다시 기초를 다지고 있다. 알고리즘 문제를 풀며 좀 더 효율적으로 짤 수 없을까 고민도 많이 하게 됐다. 그 과정에서 설계를 잘못해서 다 엎거나 며칠동안 한게 헛수고가 되거나 하는 일도 있었다. 알고리즘 문제가 꿈에 나올 정도가 됐다 근데 왜 꿈에서도 못푸니… 나는 답지를 빨리 보는 스타일이라 알고리즘 문제는 나와 상극이라고 생각했었다. 하지만 막상 시작해보면 생각했던 것 만큼 거대한건 아니라는 생각이 든다. 역시 뭔가에 도전하는건 책임이 따를 경우 어렵고 무섭지만 막상 시작해보면 그렇게 무서운 게 아니였던 것 같다. -Node.js 기초를 계속 다질 예정이다. 웹 크롤링을 해서 작은 홈페이지도 하나 만들어 볼 예정이다. -최근은 바빠서 통 하지 못했지만, 다음 주 부터는 하고싶었던 운영체제 공부를 드디어 시작할 수 있을 것 같다. 학교다닐 때도 느꼈지만 나에게 있어 컴퓨터 구조라던지 그런 기초 공부는 코딩과도 같은 것 같다. 로직을 분석해서 흐름을 보고 결과를 예측하고 테스트하고 그런 모든 과정이 굉장히 유사하기 때문이다. 다음주 목표 알고리즘 문제 스터디 프로그래머스 운영체제 강의 수강 Nodejs 프로젝트 총평돋보이려 하면 조급해진다는 말이 있는데 그 말을 계기로 기초 공부를 하게 됐다. 그래서 이번주는 그간 신기술을 배우느라 못했던 기반, 기초 공부를 할 수 있어서 너무 좋았다. 늘 마음 한켠이 걸렸었는데 이번 기회에 제대로 할 수 있을 것 같아서 좋다. 기초 공부의 복습은 화려하지 않지만 꼭 필요하기 때문에 급하지 않게 하고 싶다.","categories":[{"name":"Logs","slug":"Logs","permalink":"https://sehajyang.github.io/categories/Logs/"}],"tags":[{"name":"weekly","slug":"weekly","permalink":"https://sehajyang.github.io/tags/weekly/"}]},{"title":"Study logs","slug":"2018-08-22-study-log","date":"2018-08-21T15:00:00.000Z","updated":"2019-07-15T14:11:55.564Z","comments":false,"path":"2018/08/22/2018-08-22-study-log/","link":"","permalink":"https://sehajyang.github.io/2018/08/22/2018-08-22-study-log/","excerpt":"","text":"형식: 공부내용 / 사용한 컨텐츠(ex: 책, 강의 등) [18.06.26] Host scanning Study [18.06.27] Reversing Study [18.06.27] Spring Web Project ‘Devlink’ front home,network 등 구현 [18.06.27] Docker 및 OpenStack Study [18.06.28] OpenInfraDay day1 2018 & SmartTech day2 2018 attendance로 참가 [18.06.28] Docker 설치 및 테스트 / 강의, 웹 [18.06.29] Spring Web Project ‘Devlink’ Spring Security Login 개발중 [18.06.29] OpenInfraDay 2018 에서 들은 내용 정리 / OneNote [18.06.29] Reversing Study [18.06.30] Cloud computing Service Types: Saas, IaaS, PaaS 공부 및 정리/ 책, OneNote [18.06.30] Reversing Study [18.07.01] AWS 계정생성, 암호화 학습 / 강의 [18.07.02] Docker network, Linux Oracle 설치 및 세팅 삽질 [18.07.02] Spring Web Project ‘Devlink’ 개발중 [18.07.04] Spring Web Project ‘Devlink’ 개발중 [18.07.05] Spring Web Project ‘Devlink’ 개발중 [18.07.05] Port Scanning, Vulnerability scanner Study/ 강의, OneNote [18.07.06] Spring Web Project ‘Devlink’ 개발중 [18.07.08] 개발자의 생존전략 세미나 참석 [18.07.11] Spring Web Project ‘Devlink’ AWS 배포 테스트 [18.07.13] Spring Web Project ‘Devlink’ 개발완료 [18.07.14] Node.js + Web 공부 시작 [18.07.15] 웹 취약점분석 세미나 참석 [18.07.16] Kitware, devlink Web project vulnerability analysis [18.07.17] Node.js, Express.js Study, Spring Toy Project Board Create [18.07.18] BaekJoon Algorithm Quiz 풀이, Data Structure, Algorithm /강의 [18.07.19] Node.js, Express.js Study, Spring MVC Study /강의, 책 [18.07.20] Node.js, MongoDB, WAS(Tomcat) Structure Study [18.07.22] WAS structure Study [18.07.23] Node.js, MongoDB Study (Test Web Project Start) [18.07.23] Spring MVC Study [18.07.24] Node.js Study /강의 [18.07.26] Node.js, Spring, gitLab Study [18.07.27] Seoul.js Lightning Talk 참석, Algorithm Quiz 풀이 [18.07.28] Algorithm Quiz 풀이, Java Study 및 포스팅 [18.07.29] Toy Project 기능 추가, Node.js Study, Blog comment Add & Custom [18.07.31] Node.js Study /Head First 책 [18.08.01] Node.js, Java Study, Algorithm Quiz 풀이 /Head First 책, 알고리즘 문제해결전략 [18.08.01] Node.js, React.js, Java Study /강의, 책 [18.08.02] Java Study Complete /Head First 책 [18.08.03] Node.js Study /강의 [18.08.04] React Movie Project /Nomad coders [18.08.05] Design Pattern Study / HeadFiest 책 [18.08.06] React Movie Project, Node.js Express.js Router Study /Nomad coders, 강의 [18.08.07] Node.js Study /강의 [18.08.08] React-Native DEV ENV Setting & TODO App Project Start /Nodam coder [18.08.09] Okky 오픈소스 세미나 참석 [18.08.10] React-Native ToDo App Project, Node.js passport Study [18.08.12] React.js , Node.js Study [18.08.13] React-Native Project [18.08.14] Node.js Study [18.08.15] Spring ToyProject Start, RESTful Study, 챗봇 만들기 시작(AWS Rambda, Travis CI, telegram) [18.08.16] Spring ToyProject, 챗봇 전체발송 기능 삽질 [18.08.17] Docker로 CI 구축 연습 (Gradle + Docker + Jenkins + Slack), 챗봇 삽질 [18.08.18] Docker, Jenkins 삽질 [18.08.19] Design pattern Study, Node.js 기초 Study /책 [18.08.20] Spring Toy Project, Node.js Study [18.08.21] Spring Toy Project, Node.js Study 및 정리 [18.08.22] 알고리즘 및 웹 크롤링 공부 /책 [18.08.23] 웹 크롤링 공부 /책 [18.08.24] AWS 삽질, 웹 크롤링 공부 [18.08.26] 알고리즘 공부 [18.08.27 ~ 18.08.28] Node.js Study [18.08.29] Node.js Study, SpringBoot Study Start [18.08.30] Springboot Setting Study [18.08.31] Springboot Study [18.09.01] Springboot Project, C 포인터 세미나 참석 [18.09.02] Springboot Project [18.09.04] 운영체제 공부, Python Study /강의 [18.09.05] 운영체제 공부, Python Django Study /강의 [18.09.06] 운영체제 공부, Python Study /강의 [18.09.07 ~ 18.09.12] Python Study /책 [18.09.13] Springboot Study [18.09.14 ~ 18.09.15] Java, JS, Typescript Study [18.09.16] Node Crawling Project Start [18.09.17] Java, DB Study [18.09.19] [AUSG Seminar Series] 2018 F/W 초보자를 위한 AWS 뿌시기 [18.09.20] [T academy]스프링부트를 이용한 웹 서비스 개발하기 [18.09.21] Algorithm Study, Node project CI(travis CI, Jenkins+Slack) 구축 [18.09.23 ~ 18.09.26] Algotithm Study (Python) [18.09.29~18.10.01] Algotithm Study, Springboot Study [18.10.02] Springboot 강의, Node.js project [18.10.04] Node.js project [18.10.05] Node.js project, React Study /책 [18.10.06] Node.js project, React Study, Daily Algorithm [18.10.07] Dev Django 세미나 참석 12월 이후 로그 기록 [18.12.11] springboot 수강 후 TIL 기록 [18.12.12] springboot 수강 후 TIL 기록","categories":[{"name":"Logs","slug":"Logs","permalink":"https://sehajyang.github.io/categories/Logs/"}],"tags":[{"name":"studylog","slug":"studylog","permalink":"https://sehajyang.github.io/tags/studylog/"},{"name":"daily","slug":"daily","permalink":"https://sehajyang.github.io/tags/daily/"}]},{"title":"Design Pattern 정리","slug":"2018-08-19-design-pattern","date":"2018-08-18T15:00:00.000Z","updated":"2019-08-02T14:41:53.797Z","comments":true,"path":"2018/08/19/2018-08-19-design-pattern/","link":"","permalink":"https://sehajyang.github.io/2018/08/19/2018-08-19-design-pattern/","excerpt":"","text":"디자인 원칙(SOLID) Open-Closed-Principle(개방 폐쇄 원칙) 클래스는 확장에 대해서는 열려있어야하지만, 코드변경에 대해서는 닫혀있어야한다. Dependency-Inversion-Principle(의존성 뒤집기 원칙) 추상화된것에 의존하게 만들어야한다. 구상클래스에 의존하도록 만들지 않도록 한다. 어떤 변수에도 구상클래스에 대한 레퍼런스를 저장하지않는다. 구상 클래스에서 유도된 클래스를 만들지 않는다. 베이스 클레스에 이미 구현되어있던 메소드를 오버라이드 하지 않는다. Single Responsiblity Principle(단일 책임 원칙) Liskov Subsitution Principle(리스코브 치환 원칙) Interface Segregation Principle(인터페이스 분리 원칙) Singleton Pattern특정클래스에 대해 객체 인스턴스 한개만 만들어 사용하기 위한 패턴 필요할 때만 객체를 만들기 위함 해당 클래스의 인스턴스가 하나만 만들어지고, 어디서든지 그 인스턴스에 접근할 수 있도록 하기 위한 패턴 1234public MyClass { public static MyClass getInstance(){ }} MyClass에 정적메소드가 있고 그 정적 메소드는 이렇게 호출할 수 있다. MyClass.getInstance(); 정적 메소드를 지칭할 때는 클래스 이름을 써야한다.(MyClass) new 를 사용할 수 없도록 생성자에 private를 지정하고 정적메소드를 지원해야하며 참조변수가 필요하다 동시에 접근할 경우 인스턴스 두개가 생성되게된다 따라서 synchronized 로 동기화시킨다. 인스턴스 사용하지 않는 경우에도 메모리에 있으며 그것을 방지하기위해 Volatile를 사용한다 모든 스레드에 대한 최신의 값을 읽어올 수 있게 해준다. Strategy Pattern알고리즘군을 정의하고 캡슐화해, 교환해서 사용할 수 있도록 만든다. 알고리즘을 사용하는 클라이언트와는 독립적으로 알고리즘을 변경할 수 있다. Observer PatternSubject 인터페이스와 Observer 인터페이스가 들어있는 클래스 디자인을 바탕으로 구현한다. 한 객체의 상태가 바뀌면 그 객체에 의존하는 다른 객체들한테 연락이 가고, 자동으로 내용이 갱신되는 방식이다. 일대다 의존성을 정의. Loose Coupling 이다. Loose Coupling(느슨한 결합)의 장점 => 객체 사이의 상호의존성을 최소화 했기에, 변경사항이 생겨도 무난히 처리할 수 있는 유연한 객체지향 시스템을 구축할 수 있다. Subject 인터페이스가 옵저버에 대해 아는것은 옵저버가 인터페이스를 구현한다는 것 뿐이다. 옵저버는 언제든지 새로 추가/제거 할 수 있으며 Subject를 변경하지 않아도 된다. Subject 인터페이스와 옵저버는 서로 독립적으로 재사용 할 수 있으며 서로 바뀌더라도 서로에게 영향을 주지 않는다. Decorator Pattern객체에 추가적인 요건을 동적으로 첨가한다. 서브클래스를 만드는 것 을 통해서 기능을 유연 하게 확장할 수 있는 방법 을 제공 한다. 데코레이터의 super class는 자신이 장식 하고 있는 객체의 super class와 같다. 한 객체를 여러 개의 데코레이터로 감쌀 수 있다. 데코레이터는 자신이 감싸고 있는 객체와 같은 super class를 갖고 있기 때문에, 원래 객체가 들어갈 자리에 데코레이터 객체를 집어넣어도 상관없다. 데코레이터는 자신이 장식하고 있는 객체에게 어떤행동을 위임하는 것 외에 원하는 추가적인 작업을 수행할 수 있다. 객체를 언제든지 감쌀 수 있기 때문에 실행중에 필요한 데코레이터를 마음 대로 적용할 수 있다. Factory Method Pattern객체를 생성하기위한 인터페이스를 정의하는데, 어떤 클래스의 인스턴스를 만들지는 서브클래스에서 결정하게 만든다. 즉, 클래스의 인스턴스 만드는 일을 서브클래스에게 맡긴다. **아래부터 보충 필요 Command Pattern메소드 호출을 캡슐화하는 패턴 커맨드 패턴을 이용하면 요구사항을 객체로 캡슐화 할 수 있으며, 매개변수를 써서 여러 가지 다른 요구사항을 집어넣을 수 있다. 요청 내역을 큐에 저장하거나 로그로 기록할 수 있으며, 작업취소 기능도 지원 가능하다. Adapter Pattern한 클래스의 인터페이스를 클라이언트에서 사용하고자 하는 다른 인터페이스로 변환한다. 어댑터를 이용하면 인터페이스 호환성 문제때문에 같이 쓸 수 없는 클래스들을 연결해서 쓸 수 있다. Facade Pattern어떤 서브시스템의 일련의 인터페이스에 대한 통합된 인터페이스를 제공한다. 퍼사드에서 고수준 인터페이스를 정의하기 때문에 서브시스템을 더 쉽게 사용할 수 있다. Template Method Pattern알고리즘을 캡슐화 해서 서브클래스에서 필요할 때마다 쓸 수 있게 한다. 메소드에서 알고리즘의 골격을 정의한다. 알고리즘의 여러단계 중 일부는 서브클래스에서 구현 할 수 있다. 템플릿 메소드를 이요하면 알고리즘의 구조는 그대로 유지하면서 서브클래스에서 특정 단계를 재정의할 수 있다. Iterator Pattern내부적인 구현방법을(반복작업을 별도의 객체로 캡슐화 함으로써) 외부에 노출시키지 않으면서도 그 집합체 안에 들어있는 모든 항목에 접근할 수 있게 해주는 방법을 제공한다. composite Pattern객체들을 트리 구조로 구성하여 부분과 전체를 나타내는 계층구조로 만들 수 있다. 이 패턴을 이요하면 클라이언트에서 개별 객체와 다른 객체들로 구성된 복합 객체(composite)를 똑같은 방법으로 다룰 수 있다. 복합 구조(composite structure)를 사용하면 복합객체와 개별객체에 대해 똑같은 작업을 적용할 수 있다. State Pattern객체의 내부 상태가 바뀜에 따라서 객체의 행동을 바꿀 수 있다. 마치 객체의 클래스가 바뀌는 것과 같은 결과를 얻을 수 있다. Proxy Pattern어떤 객체에 대한 접근을 제어하기 위한 용도로, 대리인이나 대변인에 해당하는 객체를 제공하는 패턴 원격객체라던가 생성하기 힘든 객체, 보안이 중요한 객체와 같은 다른 객체에 대한 접근을 제어하는 대변자 객체를 만들 수 있다. Compound Pattern두개이상의 패턴을 결합해서 사용하는 것 Bridge Pattern구현뿐만 아니라 추상화된 부분까지 변경시켜야 하는 경우에 사용 브리지 패턴을 이용하면 추상화된 부분과 추상클래스/인터페이스를 구현한 클래스를 서로 다른 클래스 계층구조에 집어넣음으로써 그 둘을 모두 변경시킬 수 있다. Builder Pattern제품 생산 단계들을 캡슐화하고싶다면 사용 복합객체가 생성되는 과정을 캡슐화한다. 여러단계와 다양한 절차를 통해 객체를 만들 수 있다. (팩토리패턴에선 한단계에서 모든걸 다 처리한다) Chain of responsibility Pattern역할사슬 패턴 주어진 요청을 검토하기 위한 객체사슬을 생성한다. 그 사슬에 속해있는 각 객체에서는 자기가 받은 요청을 검사해 직접 처리하거나 사슬에 들어있는 다른 객체에게 넘기게 된다. Flyweight Pattern어떤 클래스 인스턴스 한 개만 가지고 여러개의 가상인스턴스를 제공하고 싶을 때 사용 인스턴스는 한개만 만들어 여러 가상 객체의 상태를 한곳에 집중시켜놓을 수 있다. Interpreter Pattern어떤 언어에 대한 인터프리터를 만들 때는 인터프리터 패턴을 사용 각 문법 규칙을 클래스로 표현하기 때문에 언어를 쉽게 구현할 수 있다. 문법이 클래스에 의해 표현되기 때문에 언어를 쉽게 변경하거나 확장할 수 있다. Mediator Pattern서로 관련된 객체 사이의 복잡한 통신과 제어를 한 곳으로 집중시키고자 하는 경우에 사용 시스템하고 각 객체를 분리시킴으로써 재사용성을 향상시킬 수 있다. 제어로직을 한군데에 모아두었기 때문에 관리하기가 수월하다. Memonto Pattern객체를 이전의 상태로 복구시켜야 하는 경우에 사용 Prototype Pattern어떤 클래스의 인스턴스를 만드는것이 자원/시간을 많이 잡아먹거나 복잡한 경우에 사용 기존 인스턴스를 복사하기만 하면 새로운 인스턴스를 만들 수 있다. 클라이언트 코드에서 어떤 클래스의 인스턴스를 만드는지 모르는 상태에서도 새로운 인스턴스를 만들 수 있다. Vititor Pattern다양한 객체에 새로운 기능을 추가해야하는데 캡슐화가 별로 중요하지 않을 경우 사용 구조 자체를 변경시키지 않으면서도 복합 객체 구조에 비교적 손쉽게 새로운 기능을 추가할 수 있다. 참고 : HeadFirst Design Pattern","categories":[{"name":"Etc","slug":"Etc","permalink":"https://sehajyang.github.io/categories/Etc/"}],"tags":[{"name":"study","slug":"study","permalink":"https://sehajyang.github.io/tags/study/"}]},{"title":"180813-180819 주간 회고","slug":"2018-08-19-180813~180819","date":"2018-08-18T15:00:00.000Z","updated":"2019-07-15T14:11:55.563Z","comments":true,"path":"2018/08/19/2018-08-19-180813~180819/","link":"","permalink":"https://sehajyang.github.io/2018/08/19/2018-08-19-180813~180819/","excerpt":"","text":"이번주는 궁금했었던 Jenkin와 Sonarqube를 경험해봤고 AWS Lambda나 API Gateway등을 써보는 등 새로운 경험을 많이 한 주였다. 기존의 복잡하고 귀찮은 절차를 쉽고 빠르게 개선시킨 새로운 기술들을 써보니 정말 신세계였다. 몇개월 전에 Docker 나 AWS를 처음 들었었던게 생각난다. 그땐 처음 들어보는 생소한 단어들이 너무 많아서 언젠간 하게되겠지 라고 생각했는데, 이렇게 써보기도 하고 과거에 비해 나름대로 발전하고 있는 것 같아 기쁘다. 많은 기술들을 다 경험 해봐야 한다는 생각을 하고있었는데, 최근에 나 뿐만이 아니라 다른 사람들 역시 같은 고민을 하고 있다는걸 알게됐다. 그게 스트레스가 되면 오히려 독이라는 조언도 볼 수 있었는데, 그 말에 내가 지금 껏 해왔던 공부를 돌아보게 됐다. 사람마다 다르겠지만 나에게 있어 새 기술을 배우는건 익숙한 것을 하는 것 보다 즐겁다. 그렇게 신나서 최근 많은 기술들을 경험해보고 있었는데, 어느샌가 모든 유명한 기술을 다 경험해봐야 한다로 바뀌어서 스트레스를 받고 있지 않았나 생각했다. 그만큼, 익숙한 기술을 등한시하게 되는 부분도 분명히 있었다. 그래서 다음주는 새로운걸 배우기 보단 익숙한 기술과 새로운 기술의 기초를 복습하고 정리해야겠다. 개인공부세미나 알림봇이 있으면 좋겠다고 생각했다! 나는 주위사람들에게 세미나 정보를 매일같이 알려주고 있었는데, 다들 좋아했기 때문에 다른 사람들도 이러한 알림 서비스(?)를 필요로 하지 않을까 생각해서 만들고자 결심하게 됐다. 창천향로님의 챗봇 만들기를 보며 다양한 AWS의 서비스들을 사용해 볼 수 있었다. EC2 와 RDS 만 써봤었는데, Rambda, S3, API Gateway, IAM, DynamoDB등을 써볼 수 있었다. 깃허브와 TravisCI, AWS를 연동했는데 깃허브에 push하면 자동으로 빌드해서 서비스를 한다는게 충격이였다. /seminar를 입력하면 내가 깃허브에 push한 JSON 형태의 세미나 정보를 보여주기까진 됐지만, /subscribe기능을 추가할때 내가 뭔가 잘못한건지 반응하지 않았다. 뭔가 빠트린게 있나보다.. 며칠을 삽질하다 그냥 처음부터 다시하고있다(본격 삽질시작) -Spring 토이 프로젝트로 디X인사이드같은 그런 커뮤니티 웹을 만들어 서비스까지 할 생각을 하고있는데, 그러다보니 점점 신경쓸게 많아진다. 나름대로 많은사람이 이용할걸 염두에 두고 있는데, 그런 프로젝트를 해본적이 없어서 아직 길을 못잡겠다. 그래서 일단 하던대로 만들기 시작했는데 만들면서 내가 초보라는 사실을 뼈저리게 느끼고있다.. 흑흑…… -Head First Design Pattern책을 다 읽었다. 정리 세상은 넓고 디자인패턴은 많구나.. 들어본 패턴부터 처음듣는 패턴까지 굉장히 많은 디자인 패턴이 있었고 다 이해하진 못했지만 조금은 감이 온것 같은 느낌이 들었다. 디자인 패턴 어렵지만 나도 언젠간 적재적소에 디자인패턴을 잘 사용 할 수 있는 개발자가 됐으면 좋겠다.. 모든 디자인 패턴을 마스터한다는건 언젠간 가능할지 몰라도 지금은 절대 아닌것 같고 그냥 내가 사용해본거나 유명한거 몇개 정도는 어느정도 익히고싶다. 그래도 들어봤던 몇가지 패턴에 대해 조금이나마 알 수 있어서 되게 좋았다. -깃허브와 Jenkins와 Slack을 연동했다 창천향로님 게시글을 보고 따라해봤는데 설명이 너무 친절하셔서 성공적으로 구축할 수 있었다ㅠㅠ 물론 삽질도 좀 했지만 그래도 비교적 쉽게 구축할 수 있었다. 정말 Github에 푸쉬하자마자 빌드가 되고 로그가 딱 뜨고 알림이 슬랙으로 딱 오고 이게 정말 예술인것같다. Jenkins는 정말 예술이다 팀프로젝트때에 AWS와 연동해서 써볼걸.. 그때는 코드 한줄이라도 수정하면 war 파일만들어서 그 파일을 AWS EC2 서버로 옮기고.. webapps아래에 배포하고 그랬는데 와 에러라도 나면 다시 반복하고 그랬다. 이 좋은 Jenkins 를 진작알았더라면 그런 구석기 시대의! 빌드 작업을 하지 않았을 텐데 아쉽다.. -Sonarqube를 사용해봤다!! 저번주에 엄청 삽질하다 실패했는데, 이번엔 성공했다ㅠㅠ 버그랑 중복코드 퍼센테이지랑 다 나오는데 정말 굉장한 오픈소스다. 항상 보기만 하던걸 실제로 해보니 너무 감동이었다ㅠㅠ Jenkins와 연동하는건, window에 Docker를 설치하다 설정을 잘못만져 문제가 생겨버렸기 때문에 점점 복잡해져서 일단은 미뤄뒀다. 나는 분명 get started문서를 보고 하라는 대로 했는데 늘 어째서 오류가 나는지 알 수 없다.. 예전에 docker 설치할때 뭔가 잘못한 것 같은데 짚이는게 너무 많다. 차라리 멀티부트 해둔 리눅스로 받아서 할까 생각해봤지만 그쪽은 개발환경 셋팅을 안해놨다.. 윈도우 불편한데 리눅스도 불편하고 차라리 vmware에 예전에 해킹공부용으로 파둔 리눅스에 개발환경 셋팅해둘까 생각도 하는데 칼리 리눅스니까.. 아무튼 kitematic은 되니까 도커오류는 나중에 잡아봐야겠다. 참 괴상하게도 kitematic은 되는데 콘솔모드 도커는 에러가 난다ㅎㅎ 정말이지 알수없다.. 다음주 목표 Spring, Node.js, Javascript 기초 복습 및 공부 운영체제 강의 수강 시간이 되면 kubernetes 알아보기 총평이번주는 다양한 CI 툴을 경험해봤는데 그야말로 신세계였다. 나는 자동화가 정말 좋고, 나도 무언가를 자동화하는 걸 개발하고싶다. 나름대로 이번주 목표였던 React.js 도 Node.js도 수강을 완료했다. 학(学)을 했으니 습(習)을 할 차례라고 생각한다.","categories":[{"name":"Logs","slug":"Logs","permalink":"https://sehajyang.github.io/categories/Logs/"}],"tags":[{"name":"weekly","slug":"weekly","permalink":"https://sehajyang.github.io/tags/weekly/"}]},{"title":"180806-180812 주간 회고","slug":"2018-08-12-180806~180812","date":"2018-08-11T15:00:00.000Z","updated":"2019-07-15T14:11:55.563Z","comments":true,"path":"2018/08/12/2018-08-12-180806~180812/","link":"","permalink":"https://sehajyang.github.io/2018/08/12/2018-08-12-180806~180812/","excerpt":"","text":"이번주는 React의 주 였다고 봐도 무방할정도로 React만 한 주였다. 수많은 React.js Study의 향연 처음엔 그저 궁금해서 호기심에, 그냥 발만 살짝담궈보려고 했는데 하다보니 신기하고 재밌어서 계속하고있다. 개인공부React.js 와 함께 ReactNative도 하고있다. 간단한 ToDo앱을 만들고 있는데, 역시 새로운 걸 배울땐 일단 시작해서 작은 프로젝트 하나 만들어 보는게 좋은 것 같다. 그게, 흥미를 잃지 않고 즐겁게 계속 배울 수 있는 방법 중 하나인 것 같다. 그래서인지, 학교 다닐 땐 앱 개발은 영 재미가 없었는데 요즘은 너무 재밌다. 그냥 아직 지식도 경험도 많이 부족하기 때문에, 뭘 하든 새롭고 재밌는 것 같다.. TypeScript도 하고싶은데 일단 최근에 공부한 js들(Node.js ,React.js 등..)을 복습하는게 먼저인듯.. -운영체제 강의를 듣고 정리할 예정이다. 학교에서 배웠던 내용 다 까먹은 듯 싶어서.. 그래도 가장 좋아했던 과목이었던 만큼 기억엔 아직 조금이나마(..) 남아있는 것 같다.(아닐지도) 일단 강의는 KOCW의 운영체제를 수강 할 예정이다. 정리도 할겸 포스팅 연재하는 방식으로 할 건데, 아직 글쓰기도 정리하는 기술도 미숙해서 내 포스팅을 볼 때마다 부족한게 많구나 라는 생각이 든다.. -목요일에 오키 오픈소스 세미나를 갔다. 후기 오키 창시자이신 허광남님이 재직중이신 회사에 오픈소스 도입한 그런 내용이었는데, Jenkins 에 대해서 막연하게 알았던걸 구체적으로 써봐야겠다 고 마음먹게 되는 계기가 됐다. Jenkins + Sonarqube를 써보고 싶어서 오늘 반나절 Sonarqube 삽질만 했다.. 그러다 Gradle 삽질하고.. 나는 뭔가 새로운 걸 배울 때 일단 써보고, 에러나고, 삽질하면서 그제서야 문서를 보고 차근차근 해보는데, 이게 바로 머리가나쁘면 몸이 고생한다는건가 싶다. 그렇다고 문서부터 보면 눈에 잘 들어오지도 않아서 그냥 계속 몸이 고생하고있다. 흑흑.. 다음주 목표 React.js, React-Native 미니 프로젝트 완료 Node.js 강좌 완료(얼마 안남았다!) SonarQube 및 Jenkins 삽질기 기록 운영체제 강의 수강 총평이번주는 주말에 아파서 주말을 거의 날려버렸다.. 건강관리는 역시 중요하다.. js가 가득한 주 였던 것 같다. Node.js는 지금 껏 해오던 spring와 많이 달라서 배울때마다 놀라고있다. React 역시 마찬가지.. 지금은 지식이 얕아 새로운 기술을 즐겁게 놀라며 배울 수 있다고 긍정적으로 생각하고 있다. 대체 어느 세월에 슈퍼 개발자가 될까 싶지만… 어디서 들은건진 기억이 안나는데, 개발은 물 속에 벽돌을 쌓는 것과도 같아서 처음엔 아무리 쌓아도 눈에 보이지 않지만 어느순간이 되면 쌓아오던 벽돌이 수면 밖으로 나와, 그때부터 쑥쑥 크는게 보인다고 한다. 언젠간 그렇게 될 수 있겠지 라고 막연하게 생각한다. 요즘 구조 공부 하는것 도 개발도 배포하는 일도 테스팅도 모니터링도 다 재밌다. 많은걸 배우고 경험해서 내가 원하는걸 간결한 코드로 만들어서 배포하고대용량 트래픽을 처리하고, 안정적인 서비스를 할 수 있는 그런 개발자가 되고싶다!!","categories":[{"name":"Logs","slug":"Logs","permalink":"https://sehajyang.github.io/categories/Logs/"}],"tags":[{"name":"weekly","slug":"weekly","permalink":"https://sehajyang.github.io/tags/weekly/"}]},{"title":"오픈소스, 줘도 못 먹나 후기","slug":"2018-08-09-okky-opensource-seminar","date":"2018-08-08T15:00:00.000Z","updated":"2019-07-15T14:11:55.561Z","comments":true,"path":"2018/08/09/2018-08-09-okky-opensource-seminar/","link":"","permalink":"https://sehajyang.github.io/2018/08/09/2018-08-09-okky-opensource-seminar/","excerpt":"","text":"Okky 창시자이신 허광남(kenu)님이 오픈소스 세미나를 하신다는 글을 Okky에서 보게됐다. 세미나 소개에 내가 사용하고 있거나, 궁금했던 오픈소스들이 많이 보였다. 이번기회에 내가 사용하고있는 오픈소스에 대해서 좀 더 알고 싶었고, 허광남님이 현업에서 어떤 오픈소스를 사용하고, 어떻게 도입하셨는지 궁금해서 참석하게 되었다! [OKKY 세미나] 오픈소스, 줘도 못 먹나 - 오픈소스로 팀의 개발 생산성 높이기 by kenu Kenu님의 발표자료 창천향로님의 후기 Intro기록을 잘 남기고, 관리하는게 좋다. 테스트 자동화하면 코드의 품질이 높아진다. 어플리케이션 기능이 추가될 때마다 테스트케이스로 만들어놓으면 어디서 사이드 이펙트가 나는지 쉽게 알 수 있다. 단위테스트(TDD) (function기준)으로 만들어놓는게 좋다. 단계별 오픈 소스 오픈소스 시작하기오픈소스 경험 = 시간 + 시행착오 + 성공실패 그러니 일단 사용부터 (Getting started) 해라! default setting 문서를 보고 시작하는게 좋다. 책/블로그 보고 시작할땐 버젼 맞추기 오픈소스 함부로 수정하면 안된다! => 오픈소스 커뮤니티를 추천 버전업 주기가 빠르기 때문 버전 팁 최신보다 1, 2 낮은 버전 사용을 권장(서비스 시) LTS 권장 LTS는 우분투에서 시작된 말 => Long Term Support (2년동안은 버전을 올리지 않는다) => 최소 2년은 안심하고 써도 됨 최신 버전은 Blood Edge = > 유혈이 낭자하는(?) 최전선, 온갖 에러를 만날 수 있다. 팀에 오픈소스를 도입하고 싶을 때12341. 명분, 근거자료2. 도입 전과 후 장점 어필(적은 노력으로 많은 효과 강조)3. 영향이 적은 곳 부터 적용(실적이 잘 안나오는 부서부터 공략..)4. 메인 비즈니스에는 경험이 쌓인 후 도입 오픈소스 기여방법1234561. 일단 사용2. 블로깅 (3년을 관련 오픈소스에 대한 포스팅을 하면 주변에서 전문가라 칭한다고 한다)3. 설정 튜닝(configuration 튜닝)4. 이슈 등록(contribution)5. 문서 번역6. fork&pull request 경험했거나 현재 사용하는 오픈소스 제품들12345678910* 2000년 톰캣을 시작으로* Ant* Eclipse :에릭감마* Junit :에릭감마&캔트 백이 만듬 => 부하테스트 할때 좋음 => Java Swing UI 로 만들어져있다.* Jmeter* Yona, Git, VSCode* Jenkins, CentOS, VirtualBox* Nginx, Node.js, Express.js* MariaDB, ELK, Uptime* Mocha, SonarQube, ZAP title 을 누르면 해당 오픈소스 홈페이지로 이동합니다 Yona프로젝트 관리도구 Yona는 Git을 서버로 관리해준다. 네이버 오픈소스 였었다(지금은 나옴) 이슈트래커 + Gix(SVN) 무료 (Git private는 돈을 내야하지만 이건 무료) Email 설정을 하면 보다 깊게 사용할 수 있다. Email 설정시 imap.folder = “Inbox”로 설정되어있는지 확인할 것(꼭 “Inbox”여야한다. 소문자면 안됨) GIT분산 버전 관리 시스템 리눅스 토발즈가 만들었고 홈페이지도 운영한다. 유용하게 사용한 상황별 커맨드를 정리 https://okdevtv.com/mib/git VSCodeelectron js 기반으로 만들어진 오픈소스 편집기가 브래킷, 아톰, vscode VSCode 안의 git 기능을 강추(특히 누가 선택한 라인을 작성했는지 (git blame 기능) 볼수 있다) GitLens Plugin과 Quokka Plugin(유료)가 좋다. Quokka Plugin은 변수값 수정시 다른 곳 해당 변수명의 변수 값도 같이 수정해주는 기능이있다. https://okdevtv.com/mib/vsc https://github.com/Microsoft/vscode-tips-and-tricks <<어마어마한 vscode 팁과 트릭이있다. Jenkins허드슨 만든 개발자가 Oracle에서 나와서 Jenkins를 만들었다. 지속적인 통합(Conituous Integration) => Git과 Jeckins를 잘 사용하면 완료 한달전 파트 합칠때의 유혈 사태(?)를 방지할 수 있다. 빌드 & 모니터 자동화 Java로 만들어짐 에러 로그를 다 확인할 수 있어 좋다. https://okdevtv.com/mib/jenkins Virtualbox테스트용도 (많은 이미지가 있지만 Mac OS는 지원하지 않는다) https://okdevtv.com/mib/virtualbox Nginx아파치보다 가벼움, 설정도 가벼움 로드밸런싱 지원 https://okdevtv.com/mib/nginx MariaDBMySQL 만든 개발자가 오라클의 삽질로 오라클에서 나와서 만든 DB 둘째 딸 이름이 Maria 라 MariaDB MySQL과 굉장히 흡사하다(MySQL과 동일한 API) 심지어 프로세스 명이 mysql.exe이다 (MySQL은 mysqld.exe…) https://okdevtv.com/mib/mariadb ELK Stackelestic회사에서 만든 오픈소스 Elesticsearch(검색엔진) java 로 되어있다. ElasticSreach + Logstash + Kibana + Beats => 엑세스 로그를 모니터링(차트로 볼 수 있게 되어있다) https://okdevtv.com/mib/elk/elk6 Uptime=> 1분마다 서버를 체크해준다. 메일설정하면 서버상태 보내준다 (서버가 죽었다거나..) 굉장히 편리 MochaJunit 대신 자바 유닛테스트 하기위함 SonarQube소스 정적 분석 도구 코드의 품질을 높일 수 있다 중복 코드 퍼센테이지와 취약한 코드를 볼 수 있다. 프로젝트 root에 sonar-project.prop 두면 결과가 reporting 된다. https://okdevtv.com/mib/sonar ZAP취약점 분석 자동 툴 반드시 본인 사이트에만 할 것 (다른 사이트에 하면 큰일남) XSS, SQL Inejction등 OWASP 취약점으로 있는건 다 테스트 한다. https://www.owasp.org/index.php/OWASP_Zed_Attack_Proxy_Project https://okdevtv.com/mib/zap 추가노드 + 크롬 디버깅은 NiM inspect manager 플러그인이 좋다!","categories":[{"name":"Seminar","slug":"Seminar","permalink":"https://sehajyang.github.io/categories/Seminar/"}],"tags":[{"name":"seminar","slug":"seminar","permalink":"https://sehajyang.github.io/tags/seminar/"}]},{"title":"180730-180805 주간 회고","slug":"2018-08-05-180730~180805","date":"2018-08-04T15:00:00.000Z","updated":"2019-07-15T14:11:55.560Z","comments":true,"path":"2018/08/05/2018-08-05-180730~180805/","link":"","permalink":"https://sehajyang.github.io/2018/08/05/2018-08-05-180730~180805/","excerpt":"","text":"최근에 프론트엔드에 관심이 생겨 React, Angular, Vue를 조금씩 공부해볼 생각이다. 아! TypeScript도 개인 공부자바 복습의 필요성을 느껴서 HeadFirst Java편 을 봤다. 대화식이고, 그림이 많아서 굉장히 술술 읽을 수 있었다. 처음 기술서적을 읽을때 어느정도 내용을 이해해야만 한다는 부담을 갖는 편인데, 이 책은 그러한 부담을 많이 덜도록 되어있는 것 같다는 느낌을 받았다. Java 편 다보고 Design Pattern(정리는 이쪽)을 읽기 시작했다. 객체지향에 대해서 예전엔 흐릿하게 알았지만 이젠 조금은 알게 된 느낌이 들었다. -OKKY Kenu 님의 오픈소스 세미나를 신청했다. 평소에 알고싶었던 유명한 오픈소소의 역사에 대해서 알 수 있을 것 같아서 신청했는데, 굉장히 기대된다. 세미나에 한번 갔다 오면, 몰랐거나 어렴풋이 알고 있었던 것에 대해 관심 갖게 되는 계기가 되는 것 같아 알고 싶었던 것에 대한 세미나를 참석하는게 즐겁다. -리액트 공부를 시작했다. 원래 프론트 앤드 엔 크게 관심이 없었는데, Seoul.js 에 갔다 오고 나니 관심이 많이 생겨서 이것저것 찾아보다 시작했다. 강의는 벨로퍼트님 의초심자를 위한 리액트 핵심 강좌를 보고있다. 프론트단에선 Javascript만 조금 해 왔는데, react는 비슷하면서도 달라서 굉장히 즐겁게 배우고있다. 간단한 Movie App을 만드는 리액트 클론코딩을 하고있는데, 이번주 내로 완료하고 리액트네이티브 서울밋업에 참석할 예정이다! -Node.js 공부는 매일 두강씩 듣는데, 아직 갈길이 멀다. 하지만 재밌어서 열심히 하고있다. Node.js 웹개발로 알아보는 백엔드 자바스크립트의 이해는 절반정도 봤다. 다 들으면 Node.js 교과서 이 책 으로 간단한 웹 어플리케이션을 만들어볼 생각을 하고있다. 총평이번 주 는 이것도 해보고 저것도 해보고 그러면서 Spring 공부도 틈틈히 하느라 정신이 없었다. 회사일도 충실히 하면서 하고싶은걸 하려면 몇 배로 노력해야 하는 건 어쩔 수 없다고 생각한다. 알고리즘 공부도 꾸준히 해야하는데 어렵다.. 그래서 알고리즘 스터디를 찾아볼까 하는 생각도 하고있지만, 일단은! Spring부터 해야할 것 같다.","categories":[{"name":"Logs","slug":"Logs","permalink":"https://sehajyang.github.io/categories/Logs/"}],"tags":[{"name":"weekly","slug":"weekly","permalink":"https://sehajyang.github.io/tags/weekly/"}]},{"title":"180723-180729 주간 회고","slug":"2018-07-30-180723~180729","date":"2018-07-29T15:00:00.000Z","updated":"2019-07-15T14:11:55.559Z","comments":true,"path":"2018/07/30/2018-07-30-180723~180729/","link":"","permalink":"https://sehajyang.github.io/2018/07/30/2018-07-30-180723~180729/","excerpt":"","text":"개인 공부최근들어 자바 기초를 많이 잊은게 아닌가 하는 생각을 했다. 그래서 이번주 중반부턴 자바 기초공부를 예전에 OneNote 에 기록해뒀던 자바 문법들을 다시 보는식으로 복습 하고있다. -생각보다 코딩하는 시간이 적다는걸 깨달았다. 무언가 부족한 느낌이 들어 백준 알고리즘 풀이를 다시 시작했다. 알고리즘 문제해결 전략 을 주문했다. -개인 공부로 Node.js + MongoBD 공부를 하고있는데, 쉽지가 않다. 게다가 NoSQL인 BD를 사용해본적이 없어서 굉장히 애먹고있다. Node.js도 시작부터 너무 어려운 강좌부터 봤다가 고생한 후 할만한(?) 난이도부터 다시 하고있다. 인프런의 Node.js 웹개발로 알아보는 백엔드 자바스크립트의 이해 를 보고있는데 이전에 삽질을 너무 오래해서, 최대한 빨리 들어야겠다. -미뤄뒀던 github 블로그에 카테고리랑 댓글기능을 추가했는데 생소해서 삽질을 꽤 했다. 테마는 조금 마음에 들지 않은데 일단 여기까지.. 다음에 시간이 날때 바꿔봐야겠다. 손볼게 너무많다! 깃랩도 시작했는데 생소해서 아직 뭐가 뭔지 잘 모르겠다. -출퇴근길에 읽을 책을 두 권 빌렸다. 프로그래머의 길 멘토에게 묻다 클린 코드 유명한 책들이라 내용이 기대된다. 다 읽은 후엔 깃허브 블로그에 리뷰를 올릴예정인데 클린코드가 굉장히 두꺼워서 이번주 안에 다 볼수있을지 어떨지.. -Seoul.js Lightning Talk 세미나에 참석자로 참가했다. 굉장한 고수분들이 많으셨다! 그 분들이 하는 발표내용을 신입 백엔드 개발자인 내가 이해하긴 어려웠지만 굉장히 자극이 되었다. 신입인 내가 가도 되는걸까 고민을 많이 했지만, 막상 가니 다양한 JavaScript 프레임워크에 대해서 알 수 있어서 너무 좋았다. 게다가 취업준비할때 어떤 개발자님의 자료들에 많은 도움을 받았었는데, 그 개발자님을 실제로 만나게 돼서 굉장히 감동이었다.. 갔다오고 나니 TypeScript에 관심이 생겨 다음주부터 관련 강좌를 가볍게 조금씩 볼 예정이다. 볼 강좌는 타입스크립트 코리아 : 기초 세미나","categories":[{"name":"Logs","slug":"Logs","permalink":"https://sehajyang.github.io/categories/Logs/"}],"tags":[{"name":"weekly","slug":"weekly","permalink":"https://sehajyang.github.io/tags/weekly/"}]},{"title":"Error logs","slug":"2018-07-30-error-log","date":"2018-07-29T15:00:00.000Z","updated":"2019-07-15T14:11:55.559Z","comments":true,"path":"2018/07/30/2018-07-30-error-log/","link":"","permalink":"https://sehajyang.github.io/2018/07/30/2018-07-30-error-log/","excerpt":"","text":"에러 로그 및 해결방법 기록 [18.07.23~24] 발생한 문제) Maven build가 되지 않아서 svn 으로 받은 프로젝트를 실행할 수 없었다(애당초 컴파일부터 안됨). 시도한 방법 jdk 1.7, jre 1.7, tomcat7 로 맞춤(그 환경에선 돌아갔으므로) jdk, jre, tomcat, eclipse 전부 재설치 플러그인 오류가 뜨길래 pom.xml의 dependency 추가 후 maven install > update m2 의 repository 폴더를 날린 후(중요) maven clean > maven install 오류를 잡고 프로젝트 clean , build 함 build path 에서 jre를 jdk로 잡고 실행 해결) build path 에서 jre를 jdk로 잡고 실행 => 구글링 해보니 jre가 자잘한 오류가 많으니 jdk로 잡으면 잘 된다고 한다. [18.07.24] 발생한 문제) java.lang.NoSuchMethodException 해결) default 생성자 없어서 남 [18.07.30] 발생한 문제)java.lang.IllegalArgumentException: Mapped Statements collection does not contain value~ 원인은 mapper id가 틀린 경우 Parameter와 bean의 field명이 틀린 경우 sql.xml에서 정의된 namespace와 DAO에서 호출하는 namespace가 다를 경우 mapper가 정의가 되어 있지 않거나 Spelling이 틀린 경우 mapper에 정의된 namespace 명칭이 같은 Application 내에 중복 될 경우 라고한다. 해결) mapper 이름의 오타였다..","categories":[{"name":"Logs","slug":"Logs","permalink":"https://sehajyang.github.io/categories/Logs/"}],"tags":[{"name":"error","slug":"error","permalink":"https://sehajyang.github.io/tags/error/"},{"name":"logs","slug":"logs","permalink":"https://sehajyang.github.io/tags/logs/"}]},{"title":"빠르고 쉽게 AWS에 웹 어플리케이션 배포하기","slug":"2018-07-17-deploying-java-applications-on-aws","date":"2018-07-16T15:00:00.000Z","updated":"2019-07-15T14:11:55.557Z","comments":true,"path":"2018/07/17/2018-07-17-deploying-java-applications-on-aws/","link":"","permalink":"https://sehajyang.github.io/2018/07/17/2018-07-17-deploying-java-applications-on-aws/","excerpt":"","text":"목차 RDS 생성 및 세팅 sqldeveloper에 RDS 계정 연결 및 테이블 구성 EC2 생성 및 세팅 java 및 tomcat 설치 war 파일 배포 사용하는 프로그램Sql Developer, Putty, Eclipse, FileZila 시작하기 전 AWS 계정이 있고, 사용하는 프로그램이 미리 설치 되어 있다고 가정합니다. EC2 생성 및 세팅EC2 생성 서비스 항목에 들어가면 위와 같은 화면을 볼 수 있는데우리가 이 중 사용할건 컴퓨팅의 EC2 와 RDS 입니다EC2에는 Tomcat8을 설치할 것이고, RDS에는 oracle를 구성할 것 입니다. EC2를 클릭 후 인스턴스 시작을 누르게 되면 위와같은 화면이 나옵니다 ubuntu를 선택후 프리티어 사용가능 표시가 있는 인스턴스 유형을 선택한 후 검토및 시작을 누릅니다. 7단계로 건너뛰게 됩니다. 새 키 페어 생성을 선택후 이름을 정합니다.그 뒤 키페어 다운로드를 하게 됩니다 ~.pem 이며 분실시 재발급이 되지 않으므로 잘 보관하도록 합시다. 1~2분정도 기다리면 EC2 인스턴스를 사용할 수 있게됩니다. EC2 셋팅만들어진 EC2 인스턴스에 java나 tomcat등을 설치해줘야합니다. puttygen을 실행합니다. Load를 선택후 All file로 탐색해 아까 생성한 새로운 키 페어.pem 파일을 선택합니다. 그 후 Save private key를 선택하고 key.ppk를 저장할 위치 및 이름을 지정합니다. putty 를 실행합니다. HostName에 ubuntu@퍼블릭DNS 를 넣어줍시다. 퍼블릭DNS 는 인스턴스에서 볼 수 있습니다 Port 는 SSH, 22입니다. 왼쪽사이드바 중 Connection > SSH > Auth 를 들어갑니다. Private key file for …의 Browse 에서 아까 생성한 ppk 파일을 넣어줍니다. 초기화면으로 돌아와서 Seved Sessions을 해 접속하기 편하게 저장해두고 Open을 선택합니다. 위와 같은 화면이 뜬다면 성공입니다. Java 및 Tomcat 설치Java 설치계속해서 java와 tomcat을 설치해보도록 하겠습니다. 일단 root 권한으로 접속하겠습니다 1sudo passwd root 패스워드 설정을 합니다 1su 설정한 패스워드를 입력하고 root 권한으로 실행을 합니다. 만약을 대비해 root 권한으로 실행하기보다 sudo를 사용하는 방법이 있는데, 저는 root권한으로 진행하도록 하겠습니다. 1apt-get update 업데이트를 시켜줍니다. EC2 ubuntu 엔 java가 설치되어있지 않기 때문에 java를 설치하겠습니다. 1apt-get install openjdk-8-jre-headless 설치 후 1java -version 으로 설치가 잘 되었는지 확인해봅니다. Tomcat 설치 및 EC2 포트추가1apt-get install tomcat8 톰캣을 설치합니다. 기본 설치 path는 /var/lib/tomcat8 입니다. 8080 포트를 열어주기 위해 네트워크 및 보안> 보안그룹으로 갑니다. 보안그룹 생성을 합니다. 이름 및 설명은 자유입니다. 하는김에 80번과 1521포트도 추가합니다. 보안그룹 변경을 눌러 방금 추가한 보안그룹을 체크 후 보안그룹 할당을 눌러 추가시켜 줍니다. 그 후, 인스턴스를 재시작 후 인스턴스 IPv4 퍼블릭 IP로 접속합니다. 1http://IPv4퍼블릭IP:8080 위와같은 화면이 보인다면 성공입니다.","categories":[{"name":"DevOps","slug":"DevOps","permalink":"https://sehajyang.github.io/categories/DevOps/"}],"tags":[{"name":"AWS","slug":"AWS","permalink":"https://sehajyang.github.io/tags/AWS/"}]},{"title":"Java 정리","slug":"2018-06-20-java","date":"2018-06-19T15:00:00.000Z","updated":"2019-11-16T08:45:45.546Z","comments":true,"path":"2018/06/20/2018-06-20-java/","link":"","permalink":"https://sehajyang.github.io/2018/06/20/2018-06-20-java/","excerpt":"","text":"1. Java 란객체지향(OPP)프로그래밍 언어이다.JVM을 이용(운영체제에 독립적).자바에서 컴파일 시 바이트코드(.class)로 출력되며 그 바이트코드는 기계코드로 변경되어 실행된다.자동으로 메모리 관리(Garbage collector)를 해준다.다중 쓰레드를 제공한다. C언어와의 차이점 C하드웨어를 직접 제어가능하다.절차지향구조화된 프로그램 개발이 가능하다. java중간코드(바이트코드)를 생성해 어느 플랫폼이나 사용 가능하다.객체지향C언어에 비해 메모리와 속도가 느리다(JVM을 사용하기 때문) 2. 객체지향 프로그래밍(Object Oriented Programming)실 생활의 특징을 모델링 해 소프트웨어로 옮겨오는것객체란 실 생활의 사물에 대한 추상화 한 것이며, 그에 필요한 멤버변수와 메소드를 정의한다.추상화, 캡슐화,다형성등의 특징이 있다.이미 작성한 코드에대한 재사용성이 높다( 로직을 라이브러리로 만든다던지).라이브러리 생성시 버그를 잡기 때문에 버그가 발생할 확률이 낮아진다.(디버깅이 쉽고 유지보수가 용이)또한 라이브러리가 제공하는 기능을 사용하게되면 생산성 또한 높아진다. 추상화란?굳이 구현할 필요없는 부분을 생략하고 필요한 부분만을 나타내는 것. 다형성이란?하나의 메소드나 클래스가 다양한 방법으로 동작하게하는 요소단순한 상속이나 인터페이스가 구현이 된 클래스계층적으로 다단계 상속을 이루고 있는 클래스여려개의 인터페이스를 한번에 구현한 클래스 등으로 표현된다.Overriding, Overloading 이 있다. Overriding자식클래스에서 부모클래스 메소드를 재정의한다.super()를 쓰면 부모클래스 메소드를 사용한다. Overloading같은 이름이지만 매개변수의 종류 및 숫자가 다른 메소드같은 기능이지만 다른 인자를 수행하는 메소드 정의시 사용. 캡슐화(encapsulation)란?메소드의 기능만 알며, 어떻게 동작하는지는 알필요 없이 사용하는 것외부에서 변경 불가하게 private로 선언하고 setter getter 메소드를 통해서만 접근 가능하다.=> 무결성을 보장한다. 상속이란?부모클래스의 속성과 메소드를 자식클래스가 물려받아 사용할 수 있는 것.부모클래스에서 private로 선언시 자식클래스는 상속받아도 사용하지 못한다.다중상속(extends)이 불가능하므로 interface를 사용해 다중상속을 한다. 3. 자료형(Data type)기본 자료형사용전 선언되어야한다.생성한 변수에는 하나의 값을 저장한다.call-by-value에 의해 메소드의 인자값을 전달한다. 종류byte, char, short, int, double, long, float, boolean WrapperClass기본 데이터타입을 참조자료형으로 만든것(Class 화 한 것)참조 자료형을 매개변수로 받거나, 객체자료형으로 저장해야하거나 객체간 비교가 필요할 경우 사용 참조 자료형(Reference Data Type)주소값을 저장한다.call-by-reference에 의해 메소드의 인자값을 전달한다. 종류 class, interface, array, enum 명명 규칙알파벳 대소문자, 숫자, 한글가능.특수문자 사용 X (예외 : _ $ 가능)숫자로 시작 불가능하다.클래스는 대문자로, 메소드와 변수는 소문자로 시작.합성어의 경우 첫 문자는 대문자로예약어는 사용 불가능하다. 4. 접근제어자(Access modifire)접근 영역을 제한시 사용한다 선언 생략시엔 default 이다. 종류 description public 제한없이 사용 가능 default private + 같은 패키지 내에서 사용가능 protected default + 상속이면 사용가능 private 자신의 클래서 내 에서만 사용 가능 5. Framework소프트웨어 설계와 구현을 재사용 가능하도록 해주는 뼈대구체적, 확장 가능한 기반코드를 가지고 설계자의 의도에 따르는 여러 디자인 패턴 집합으로 구성되어있다.완성된 도구가 아니라는 점에서 라이브러리와 다르다. 6. Collection 종류 List 계열 : AbstractList, ArrayList, LinkedList, Vector Set계열 : AbstractSet, HashSet, LinkedHashSet, TreeSet Map 계열 : AbstractMap, Attributes, HashMap, Hashtable, IdentityHashMap,RenderingHints, TreeMap, WeakHashMap , Properties List순서가 있다(순차적 데이터 저장). 동일 데이터 중복 가능데이터 순차 검색시 용이하다. Vector동기화(Synchronized) ArrayList동기화 안함 Set순서 없음. 중복 불가능순차 접근을 위해 Iterator을 사용한다. MapKey와 Value 형태로 입력순서 없음, Key값 중복 안됨특정 데이터 검색시 용이하다. HashMap데이터 입출력 동기화 안됨, 처리속도 빠름 HashTable모든 입출력이 동기화(토큰을 부여받아 순차접근)되나 처리속도는 떨어진다. 7. 추상 클래스(Abstract Class)와 인터페이스(Interface)- 추상클래스(abstract)extends이용해 상속을 진행한다.단일 상속형태만 정의(미완성 메소드)함으로 자식클래스에선 미완성 메소드를 재정의 해야한다. - 인터페이스(interface)implements 를 이용해 상속을 진행한다.다중 상속추상클래스보다 추상화 정도가 높다. 기능의 재정의에 큰 의미를 둔다상수와 추상 메소드만 선언 가능하다.자식클래스에서 반드시 메소드를 재정의(overriding) 해야한다 8. 쓰레드(Thread)프로세스내에서 동시에 실행되는 독립적인 실행 단위쓰레드는 각자의 스택 메모리영역을 갖고있으며 다른 쓰레드들과 전역 메모리를 공유한다. 특징자원을 많이 사용하지않고 구현이 쉬우며 범용성이 높다. 구현방법(2가지) Thread 클래스를 상속받는다. Runnable interface를 상속받아 run 메소드 재정의 Thread의 동기화(synchronized)와 데드락(deadlock) synchronized2개이상 쓰래드가 공유자원에 접근해 값 변경하려 할 수가 있으므로 공유변수에 synchronized를 사용해야한다.synchronized를 사용하면 하나의 쓰레드가 공유자원 점유시 타 쓰레드가 대기상태에 머문다. deadlock두 쓰레드가 서로 공유변수에 lock걸고 작업중 서로의 것에 필요한 코드가 있으나각자 선점중이므로 둘다 대기상태에 계속 머무르게 되는 현상망에선 사용 가능한 버퍼가 없어 노드들이 패킷을 전송할 수 없는 상태이다. process와의 차이점쓰레드와 달리 프로세스는 자기자신의 메모리 영역을 가진다.자원쓰기시 복사(copy on write) 방식으로 자식프로레스에게 복사하여 사용하는 방식이다.thread에 비해 느린 수행능력을 보여준다. Thread 사용여부지나친 다중화는 각 스레드를 스케줄링하는데에 대부분의 CPU 타임을 소모하며Thrashing과 같은 문제가 생길 수 있다.각 스레드는 다른 스레드가 끝날 때까지 대기상태에 있기 때문에 병행적이지 않은 프로그램은 더 느려지고 복잡해질 수 있다. 사용해야하는 예병렬적으로 다수의 작업을 수행하며 다중프로세서 하드웨어등에서 동작하는 프로그램중복될 수 있는 많은 입출력을 수행하는 프로그램 9. JVM 메모리 구조class, stack, heap, native 메소드, PC 레지스터로 구성되어있다. Class 영역프레임(호출된 메소드를 위한 공간)이 생성되어 각종 값이 임시로 저장된다메소드 실행 종료시 프레임삭제가 진행된다. heap 영역new 로 생성된 객체와 배열이 저장된다.permanent geration, new, old 영역으로 나뉜다. permanent geration = 객체의 주소값 저장 new eden = 객체 최초 생성영역 survivor = 참조되는 객체 저장 영역 old = new영역에서 참조되고있는 객체 저장공간 native 메소드 영역자바 외 타 언어에서 제공되는 메소드가 저장 PC 레지스터 영역쓰레드 생성시 생성되는 영역쓰레드의 현재 실행되는 부분의 명령 및 주소를 실행할지 저장 10. Garbage Colloetiongarbage를 회수해 사용할 수 있는 메모리공간을 늘리는 것garbage collector가 수행JVM이 자동 실행해주지만 System.gc() 로 수동으로도 가비지 컬랙션을 요청할 수 있다. 11. NIO(new input-output)자바 IO(input-output)의 단점을 보완한 새로운 IO 패키지기존의 모든 IO에 대해 쓰레드를 생성하는 방식이 아닌 채널관리자(selector)를 사용해실제 IO가 발생한 채널만 쓰레드를 생성해 관리.하지만 기존의 다중쓰레드 이용한 방식보다 구현하기 어렵다. 참고JongMin Kim님 repositoryHanjaeYeop님 reposiroty","categories":[{"name":"Java","slug":"Java","permalink":"https://sehajyang.github.io/categories/Java/"}],"tags":[{"name":"Java","slug":"Java","permalink":"https://sehajyang.github.io/tags/Java/"}]}]}