<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>장수궁뎅이</title>
    <link>https://dgblog.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Wed, 15 Apr 2026 02:38:29 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>장동규</managingEditor>
    <item>
      <title>[공고] 뱅크샐러드 대규모 채용</title>
      <link>https://dgblog.tistory.com/321</link>
      <description>&lt;h1&gt;오랜만에 돌아온 뱅크샐러드 대규모 채용!&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요, 현업 개발자입니다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제가 2년간 몸담고 있는 뱅크샐러드에서 오랜만에 대규모 채용을 시작한다고 하네요!  &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[아래 링크를 통해 확인해주세요!]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://banksalad.netlify.app/BDZAZ&quot;&gt;https://banksalad.netlify.app/BDZAZ&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1763622251269&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;뱅크샐러드 전직군 대규모 채용&quot; data-og-description=&quot;성공과 성장을 위해 준비된 기회&quot; data-og-host=&quot;corp.banksalad.com&quot; data-og-source-url=&quot;https://banksalad.netlify.app/BDZAZ&quot; data-og-url=&quot;https://corp.banksalad.com?utm_source=referral&amp;amp;utm_medium=referral&amp;amp;utm_campaign=%EC%9E%A5%EB%8F%99%EA%B7%9C&amp;amp;utm_content=BDZAZ&amp;amp;utm_term=24010&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cL2LDp/hyZNMV3bEO/EGncqVmQDgZkB1MJg1mvvK/img.png?width=1600&amp;amp;height=800&amp;amp;face=0_0_1600_800&quot;&gt;&lt;a href=&quot;https://banksalad.netlify.app/BDZAZ&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://banksalad.netlify.app/BDZAZ&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cL2LDp/hyZNMV3bEO/EGncqVmQDgZkB1MJg1mvvK/img.png?width=1600&amp;amp;height=800&amp;amp;face=0_0_1600_800');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;뱅크샐러드 전직군 대규모 채용&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;성공과 성장을 위해 준비된 기회&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;corp.banksalad.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;뱅크샐러드는요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;700만 명이 사용하는 금융 마이데이터 플랫폼이에요. 자동 가계부, 금융상품 추천, 신용 관리부터 최근에는 건강 서비스까지 확장하면서 사람들의 돈과 건강을 연결하는 서비스를 만들고 있어요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;국내 최초로 금융 통합조회, 마이데이터 같은 걸 시도했고, 항상 새로운 것에 도전하는 회사예요.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;추구하는 방향은&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 기반으로 사용자들에게 진짜 필요한 서비스를 빠르게 만드는 거예요. 회의실에서 나온 아이디어가 다음 주에 앱에 반영되는 일도 종종 있을 정도로 실행 속도가 빠르고, 실패를 두려워하지 않고 계속 시도하는 문화가 있어요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발, 디자인, 마케팅, 비즈니스 등 거의 모든 직군에서 채용이 진행되고 있어요!&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;이런 분들이 오시면 좋을 것 같아요!&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터로 실제 문제를 해결하는 걸 좋아하시는 분&lt;/li&gt;
&lt;li&gt;빠른 실행력과 의사결정 문화가 맞으신 분&lt;/li&gt;
&lt;li&gt;0&amp;rarr;1을 만드는 경험을 해보고 싶으신 분&lt;/li&gt;
&lt;li&gt;함께 성장하는 걸 중요하게 생각하시는 분&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;눈여겨 보셨던 분들! 오랜만에 진행하는 대규모 채용인 만큼 좋은 기회가 될 것 같아요. 궁금한 점 있으시면 댓글 달아주세요~!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;채용 공고는 뱅크샐러드 채용 페이지에서 확인하실 수 있습니다  &lt;/p&gt;</description>
      <category>홍보/취업</category>
      <category>PM</category>
      <category>개발자</category>
      <category>기획자</category>
      <category>대규모채용</category>
      <category>디자이너</category>
      <category>백엔드</category>
      <category>뱅크샐러드</category>
      <category>뱅크샐러드 채용</category>
      <category>채용공고</category>
      <category>프론트엔드</category>
      <author>장동규</author>
      <guid isPermaLink="true">https://dgblog.tistory.com/321</guid>
      <comments>https://dgblog.tistory.com/321#entry321comment</comments>
      <pubDate>Thu, 20 Nov 2025 16:05:26 +0900</pubDate>
    </item>
    <item>
      <title>@RedisHash 이슈 트랙킹</title>
      <link>https://dgblog.tistory.com/320</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Issue&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RedisHash로 저장한 키가 expired 되지않고 남아있음, 그러나 repository에서 findAll을 하게되면 null인 상황&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;$ redis-cli MONITOR&lt;/span&gt;&lt;/b&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;save&lt;/p&gt;
&lt;pre id=&quot;code_1743129967762&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;1743129798.849147 [0 127.0.0.1:55838] &quot;DEL&quot; &quot;status:2&quot;
1743129798.850581 [0 127.0.0.1:55838] &quot;HMSET&quot; &quot;status:2&quot; &quot;_class&quot; &quot;com.test.test.Status&quot; &quot;status&quot; &quot;UNKNOWN&quot;
1743129798.851483 [0 127.0.0.1:55838] &quot;SADD&quot; &quot;status&quot; &quot;2&quot;
1743129798.851978 [0 127.0.0.1:55838] &quot;EXPIRE&quot; &quot;status:2&quot; &quot;60&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;$ &lt;span&gt;CONFIG SET notify-keyspace-events Ex&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;$redis-cli MONITOR&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1743133667024&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;3) &quot;__keyevent@0__:expired&quot;
4) &quot;status:2&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;gt;&amp;gt; set은 종료되지 않았음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;springboot$[repository] findAll() method&lt;/p&gt;
&lt;pre id=&quot;code_1743133720108&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;1743130766.192815 [0 127.0.0.1:60155] &quot;SMEMBERS&quot; &quot;status&quot;
1743130766.198055 [0 127.0.0.1:60155] &quot;HGETALL&quot; &quot;status:2&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;gt;&amp;gt; set scan 후 하나씩 hgetall을 하고 있었음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;상황 결론&lt;/p&gt;
&lt;pre id=&quot;code_1743134329342&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;1. @RedisHash의 경우 Hash에는 실제 객체정보가, Set에는 키가 저장됨
2. ttl을 지정해도 @RedisHash에는 ttl설정이되지만 set에는 되지않음
3. 만료 시 2번의 내용을 토대로 Hash는 제거되고 Set은 남아있음
4. 따라서 findAll() 호출 시 set의 결과에서 키가 조회되고 해당 값으로 Hash를 조회하게 되면 null이 리스트로 반환되는 내용&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Goal&lt;/b&gt;&amp;nbsp;&lt;br /&gt;Hash를 만료시키기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;b&gt;Plan&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. Set키에도 expire을 추가한다. (기존 데이터는?)&lt;br /&gt;2. 기존데이터 삭제를 위해 findAll() 메소드 호출이 아닌 RedisTemplate로 findAll 메소드와 같이 scan 후 키값으로 Hash를 찾아낸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Reference&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;http://redisgate.kr/redis/clients/pdf/Spring_Data_Redis_Sets.pdf&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;http://redisgate.kr/redis/clients/pdf/Spring_Data_Redis_Sets.pdf&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;http://redisgate.kr/redis/clients/spring_hashes.php&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;http://redisgate.kr/redis/clients/spring_hashes.php&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;br /&gt;Task&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2번 방안 채택&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;AS-IS&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1743464207173&quot; class=&quot;bash&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;@AllArgsConstructor
public Test { 
	RedisRepository redisRepository;

	public void method() {
		var list = redisRepository.findAll();
		// ...
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;TO-BE&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1743464274919&quot; class=&quot;bash&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@AllArgsConstructor
public Test { 
	private final StringRedisTemplate redisTemplate;

	public void method() {
		String setKey = &quot;&quot;;
		Objects.requireNonNull(redisTemplate.opsForSet().members(key))
                .stream()
                .filter(key -&amp;gt; Boolean.FALSE.equals(
				redisTemplate.opsForHash().getOperations()
					.hasKey(&quot;%s:%s&quot;.formatted(setKey, key))))
                .forEach(key -&amp;gt; redisTemplate.delete(&quot;%s:%s&quot;.formatted(setKey, key)));
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>기초/JAVA</category>
      <category>issue</category>
      <category>lettuce</category>
      <category>redishash</category>
      <category>RedisTemplate</category>
      <author>장동규</author>
      <guid isPermaLink="true">https://dgblog.tistory.com/320</guid>
      <comments>https://dgblog.tistory.com/320#entry320comment</comments>
      <pubDate>Tue, 1 Apr 2025 08:41:31 +0900</pubDate>
    </item>
    <item>
      <title>계속 바뀌었던 제휴사 연동 모듈의 로그 적용기</title>
      <link>https://dgblog.tistory.com/319</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;PM: Production에는 로그를 적재하고 있지않아요! p4..쯤 안정화되면 적용할께요!!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예..?&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Q. staging 에는 로그가 있는데요? 그대로 쓰면 안되나요..?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Team: 아... 로그 보안정책을 다 제대로 체크하지 못했어요..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Q. staging 서버는 어떻게 적용이 됐나요..?&lt;br /&gt;PM: 데이터독 서버가 해외라 staging은 암호화처리를 하고 production은 적재하지 않는 방식으로 가기로 했어요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터독 서버는 &lt;span style=&quot;background-color: #1f1f1f; color: #000000; text-align: left;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #1f1f1f; color: #bfbfbf; text-align: left;&quot;&gt;&lt;b&gt;2019년 9월에 9조 이상 가치로 미국 나스닥 시장에 상장한&lt;/b&gt; &amp;nbsp;&lt;/span&gt;해외서버였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 제휴사를 붙이고 제휴사마다의 규격을 통일화 한뒤 코드의 모듈자체에 로그 컨벤션을 완성했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;production의 로그는 휘발성으로 남겨둔채로 DB에 적재된 통신로그에러메세지만 보다가 한계가 오기 시작하면서 다시 production 로그 적용이 p1까지 올라왔다..&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;p0 ~ p5는 로그 기준이다&lt;br /&gt;급한순으로 p에 0 ~ 5를 붙여 작업 순위를 지정한다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로그를 다시 데이터독에 적재하자니 로그를 적재하는 데이터들의 상당수가 해외서버의 규제에 걸렸다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1288&quot; data-origin-height=&quot;1562&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BWXSU/btsKTzqaxBj/VzO1W7MxWbvnZAfZCPy4Lk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BWXSU/btsKTzqaxBj/VzO1W7MxWbvnZAfZCPy4Lk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BWXSU/btsKTzqaxBj/VzO1W7MxWbvnZAfZCPy4Lk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBWXSU%2FbtsKTzqaxBj%2FVzO1W7MxWbvnZAfZCPy4Lk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;566&quot; height=&quot;686&quot; data-origin-width=&quot;1288&quot; data-origin-height=&quot;1562&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회의중..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Infra Team: 그러면 Cloudwatch Seoul Region에 적재하는 방법은 어떠세요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유레카..!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서울리전은 한국서버이므로 몇가지 제약사항이 해소되는것이였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 Datadog으로 작성하던 로깅방법을 Cloudwatch로 바꾸는 작업을 진행햇다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring boot &amp;amp; k8s 환경에서 Cloudwatch를 적용하는 방법은 여러가지가 있었지만 그중에서 메인 Pod에서 로깅을 위한 Fluent Bit Pod를 생성하는 Sidecar Pattern을 사용하여 로깅을 적용하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. Cloudwatch agent: Fluent Bit 가 훨씬 가벼움&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. Application AWS Logging Gradle:&amp;nbsp; Application의 상태까지도 적재하길 원하여 Application이 아닌 외부에서 로깅을 적재해야됨&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. FluentBit demonset: 현재도 다른 팀에서 쓰고 있었지만 이 신규 제휴사연동모듈을 위해 Demonset을 올리는건 리소스가 너무크다고 생각함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 FluentBit를 사이드카 패턴으로 올리고 작업을 진행했다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: #f8f8f8; color: #1d1c1d; text-align: left;&quot; data-border=&quot;0&quot; data-indent=&quot;0&quot; data-list-tree=&quot;true&quot; data-stringify-type=&quot;ordered-list&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;list-style-type: unset;&quot; data-stringify-border=&quot;0&quot; data-stringify-indent=&quot;0&quot;&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://docs.aws.amazon.com/ko_kr/AmazonCloudWatch/latest/monitoring/Install-CloudWatch-Agent.html&quot; data-sk=&quot;tooltip_parent&quot; data-stringify-link=&quot;https://docs.aws.amazon.com/ko_kr/AmazonCloudWatch/latest/monitoring/Install-CloudWatch-Agent.html&quot;&gt;Cloudwatch agent&lt;/a&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: unset;&quot; data-stringify-border=&quot;0&quot; data-stringify-indent=&quot;0&quot;&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://docs.aws.amazon.com/ko_kr/AmazonCloudWatch/latest/monitoring/Container-Insights-setup-logs-FluentBit.html&quot; data-sk=&quot;tooltip_parent&quot; data-stringify-link=&quot;https://docs.aws.amazon.com/ko_kr/AmazonCloudWatch/latest/monitoring/Container-Insights-setup-logs-FluentBit.html&quot;&gt;Fluent Bit&lt;/a&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: unset;&quot; data-stringify-border=&quot;0&quot; data-stringify-indent=&quot;0&quot;&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://docs.aws.amazon.com/sdk-for-java/&quot; data-sk=&quot;tooltip_parent&quot; data-stringify-link=&quot;https://docs.aws.amazon.com/sdk-for-java/&quot;&gt;AWS SDK v2&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;figure id=&quot;og_1732329791298&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;https://docs.aws.amazon.com/sdk-for-java/&quot; data-og-description=&quot;&quot; data-og-host=&quot;docs.aws.amazon.com&quot; data-og-source-url=&quot;https://docs.aws.amazon.com/sdk-for-java/&quot; data-og-url=&quot;https://docs.aws.amazon.com/sdk-for-java/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.aws.amazon.com/sdk-for-java/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.aws.amazon.com/sdk-for-java/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;https://docs.aws.amazon.com/sdk-for-java/&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.aws.amazon.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1732329789962&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Fluent Bit를 DaemonSet로 설정하여 CloudWatch Logs에 로그 전송 - Amazon CloudWatch&quot; data-og-description=&quot;Container Insights에 이미 FluentD가 구성되어 있고 FluentD DaemonSet가 예상대로 실행되지 않는 경우(containerd 런타임을 사용하는 경우 발생할 수 있음), Fluent Bit를 설치하기 전에 Fluent Bit를 제거해야 Fluent &quot; data-og-host=&quot;docs.aws.amazon.com&quot; data-og-source-url=&quot;https://docs.aws.amazon.com/ko_kr/AmazonCloudWatch/latest/monitoring/Container-Insights-setup-logs-FluentBit.html&quot; data-og-url=&quot;https://docs.aws.amazon.com/ko_kr/AmazonCloudWatch/latest/monitoring/Container-Insights-setup-logs-FluentBit.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.aws.amazon.com/ko_kr/AmazonCloudWatch/latest/monitoring/Container-Insights-setup-logs-FluentBit.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.aws.amazon.com/ko_kr/AmazonCloudWatch/latest/monitoring/Container-Insights-setup-logs-FluentBit.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Fluent Bit를 DaemonSet로 설정하여 CloudWatch Logs에 로그 전송 - Amazon CloudWatch&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Container Insights에 이미 FluentD가 구성되어 있고 FluentD DaemonSet가 예상대로 실행되지 않는 경우(containerd 런타임을 사용하는 경우 발생할 수 있음), Fluent Bit를 설치하기 전에 Fluent Bit를 제거해야 Fluent&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.aws.amazon.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1732329787859&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;CloudWatch 에이전트를 사용하여 지표, 로그, 추적 수집 - Amazon CloudWatch&quot; data-og-description=&quot;이 페이지에 작업이 필요하다는 점을 알려 주셔서 감사합니다. 실망시켜 드려 죄송합니다. 잠깐 시간을 내어 설명서를 향상시킬 수 있는 방법에 대해 말씀해 주십시오.&quot; data-og-host=&quot;docs.aws.amazon.com&quot; data-og-source-url=&quot;https://docs.aws.amazon.com/ko_kr/AmazonCloudWatch/latest/monitoring/Install-CloudWatch-Agent.html&quot; data-og-url=&quot;https://docs.aws.amazon.com/ko_kr/AmazonCloudWatch/latest/monitoring/Install-CloudWatch-Agent.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.aws.amazon.com/ko_kr/AmazonCloudWatch/latest/monitoring/Install-CloudWatch-Agent.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.aws.amazon.com/ko_kr/AmazonCloudWatch/latest/monitoring/Install-CloudWatch-Agent.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;CloudWatch 에이전트를 사용하여 지표, 로그, 추적 수집 - Amazon CloudWatch&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;이 페이지에 작업이 필요하다는 점을 알려 주셔서 감사합니다. 실망시켜 드려 죄송합니다. 잠깐 시간을 내어 설명서를 향상시킬 수 있는 방법에 대해 말씀해 주십시오.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.aws.amazon.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이게 무엇인가..&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전체 로깅을 적재하다보니 한줄씩 찍히는 기이한 현상이 발생하여 Datadog에서 사용되던 방식을 그대로 사용하기엔 가독성이 너무 떨어졌다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;778&quot; data-origin-height=&quot;486&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KQmYc/btsKTnwHXq5/Vt3kANGlOKYJOrJw9BAitK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KQmYc/btsKTnwHXq5/Vt3kANGlOKYJOrJw9BAitK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KQmYc/btsKTnwHXq5/Vt3kANGlOKYJOrJw9BAitK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKQmYc%2FbtsKTnwHXq5%2FVt3kANGlOKYJOrJw9BAitK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;584&quot; height=&quot;365&quot; data-origin-width=&quot;778&quot; data-origin-height=&quot;486&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;dust&quot;&gt;&lt;code&gt;&amp;lt;appender name=&quot;FILE&quot; class=&quot;ch.qos.logback.core.FileAppender&quot;&amp;gt;
    &amp;lt;file&amp;gt;/data/logs/application.log&amp;lt;/file&amp;gt; &amp;lt;!-- Fluent Bit에서 모니터링하는 경로 --&amp;gt;
    &amp;lt;encoder&amp;gt;
        &amp;lt;pattern&amp;gt;
            %d{yyyy-MM-dd HH:mm:ss} %thread ${NODE_NAME} ${POD_NAME} [Lenderconnector Log]
            {
            Level: %level,
            Logger: %logger,
            HTTP_Method: %X{http_method},
            Request_URL: %X{request_url},
            Request_Headers: %X{request_headers},
            Request_Body: %X{request_body},
            HTTP_Status: %X{http_status},
            Response_Headers: %X{response_headers},
            Response_Body: %X{response_body},
            Message: %message
            }%n
        &amp;lt;/pattern&amp;gt;
    &amp;lt;/encoder&amp;gt;
&amp;lt;/appender&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 fluent bit설정중 멀티라인을 추가하여 해당 내용을 작성했다.&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;fluent-bit.conf: |
  [SERVICE]
      Flush        1
      Log_Level    info
      Daemon       Off
      Parsers_File parsers.conf

  [INPUT]
      Name                tail
      Path                /data/logs/*.log
      Tag                 *
      Refresh_Interval    10
      Mem_Buf_Limit       50MB
      Skip_Long_Lines     On
      Multiline     On
      Parser_Firstline     logback_multiline
      Multiline_Flush     5

  [OUTPUT]
      Name        cloudwatch_logs
      Match       *
      region      ap-northeast-2
      log_group_name   {{ $service_name }}
      log_stream_prefix {{ $service_name }}
      auto_create_group false

parsers.conf: |
  [PARSER]
      Name        logback_multiline
      Format      regex
      Regex       (?&amp;lt;title&amp;gt;^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}.*\[Lenderconnector Log\])
      Time_Key     time
      Time_Format  %Y-%m-%d %H:%M:%S
      Decode_Field_As       escaped message

  [PARSER]
      Name        logback_continued
      Format      regex
      Regex       (.|\n|\s|\S)*&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;암호화는 추가로 정규식을 작성하여&amp;nbsp; Infra Team 에게 보낸뒤 재환님이 작업을 진행해주셨다.&lt;/p&gt;
&lt;pre id=&quot;code_1732330319663&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;- Name: &quot;phoneNumber&quot;
  Regex: &quot;01\\d{8,9}&quot;
- Name: &quot;userRrn&quot;
  Regex: &quot;\\d{6}?[1234]\\d{6}&quot;
- Name: &quot;address&quot;
  # Regex: &quot;(서울특별시|서울|부산광역시|부산|대구광역시|대구|인천광역시|인천|광주광역시|광주|대전광역시|대전|울산광역시|울산|세종특별자치시|세종|경기도|경기|강원특별자치도|강원|충청북도|충북|충청남도|충남|전라북도|전북|전라남도|전남|경상북도|경북|경상남도|경남|제주특별자치도|제주)\\s([가-힣]+(시|군|구|시 [가-힣]+(군|구)))\\s([가-힣0-9\\-]+(?:읍|면|동|로|길|번길)?)\\s(\\d+)(?:-(\\d+))?(?:,\\s?(\\d+층)?\\s?(\\d+호)?)?(?:\\s?\\(([^)]+)\\))?&quot;
  Regex: &quot;([가-힣]+(시|군|구|시 [가-힣]+(군|구)))\\s([가-힣0-9\\-]+(?:읍|면|동|로|길|번길)?)\\s(\\d+)(?:-(\\d+))?(?:,\\s?(\\d+층)?\\s?(\\d+호)?)?(?:\\s?\\(([^)]+)\\))?&quot;
- Name: &quot;name&quot;
  Regex: &quot;[가-힣]{2,5}&quot;
- Name: &quot;accountNumber&quot;
  Regex: &quot;\\d{10,14}&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 production의 우당탕탕 로그 적용이 끝났다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Todo list는 아직 pretty한 로깅이 적재되지않지만 한줄로 체크되는 부분을 확인했으니..&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. pretty logging&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 불필요한 로그 제거&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가 p3으로 올라왔다.&lt;/p&gt;</description>
      <category>학습/회고록</category>
      <category>CloudWatch</category>
      <category>Datadog</category>
      <category>logging</category>
      <category>spring boot logging</category>
      <category>오블완</category>
      <category>전환</category>
      <category>티스토리챌린지</category>
      <author>장동규</author>
      <guid isPermaLink="true">https://dgblog.tistory.com/319</guid>
      <comments>https://dgblog.tistory.com/319#entry319comment</comments>
      <pubDate>Sat, 23 Nov 2024 11:59:28 +0900</pubDate>
    </item>
    <item>
      <title>[회고] 제휴사 연동 서버 개발</title>
      <link>https://dgblog.tistory.com/318</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;신규 제휴사 연동이 많아지면서 대출 처리 서버에서 제휴사 연동 모듈서버를 따로 분리하는 작업을 맡게되었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;개발스펙은 기존 프로젝트는 Go Lang을 사용하고 있었으나, 제휴사 연동 모듈은 Spring Boot + Java 로 개발된다고 하여 투입을 진행했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;MSA 환경답게 쿠알못인 나에게 &lt;b&gt;쿠버네티스&lt;/b&gt;를 접할기회가 생겼고 &lt;b&gt;데이터독과 AWS&lt;/b&gt;를 다룰 수 있는 기회도 생겼다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;그 밖에도 회사는 스타트업 답게 데이터독 대시보드와 스노우플레이크를 잘 활용하고 메인 언어를 golang 으로 가져가고 있었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;처음 계약 3개월동안은 대출 도메인을 공부하면서 코드스타일을 맞춰가려고 노력했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;가장 좋은점은 팀원들의 빠른 &lt;b&gt;리뷰문화&lt;/b&gt;와(리뷰먼저 처리) &lt;b&gt;슬랙&lt;/b&gt;을 사용한 업무소통이 빠른 업무처리를 만들어내는 조직으로 자리잡고 있다는 생각이 들었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3개월의 프리랜서의 기간이 끝나고 연장을 진행하는 과정에서 보안에 관련하여 계약직으로 전환하여 업무를 진행하게됐다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비록 하나의 모듈서버를 담당하여 개발했지만 이 과정에서 grpc, aws event, restful 다양한 방식으로 개방하며 이슈를 처리하는 과정이 굉장히 재밌었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;계약이 1년이 넘어가게되면 되면 변경되는 점이 있다고 하시는 걸봐서는 아마 재계약은 없을듯한데 재밌고 보람찬 1년을 보내고 가는것 같아서 시원섭섭하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>학습/회고록</category>
      <author>장동규</author>
      <guid isPermaLink="true">https://dgblog.tistory.com/318</guid>
      <comments>https://dgblog.tistory.com/318#entry318comment</comments>
      <pubDate>Sat, 23 Nov 2024 11:21:37 +0900</pubDate>
    </item>
    <item>
      <title>[프로젝트] 클라우드 로컬에서 실행되도록 만들기</title>
      <link>https://dgblog.tistory.com/317</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;# 프로젝트 환경&lt;/b&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;쿠버네티스&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;# 외부 연결된 어플리케이션&lt;/b&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;- 메세지 큐 [ sqs, sns ]&lt;br /&gt;- Grpc&amp;nbsp;&lt;br /&gt;- 로깅 DataDog / Cloud watch&lt;br /&gt;- rds mysql&lt;br /&gt;- apn2 redis&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;# TODO&lt;/b&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;프로젝트를 로컬에서 실행되도록 개선&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;# 외부 연결된 어플리케이션&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 로컬에서 연결이 가능한 외부 어플리케이션 정리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 데이터베이스 (redis, mysql)&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Grpc (다른 프로젝트)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 로컬에서 대체가능한 어플리케이션 정리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 로깅 -&amp;gt; 로컬에서 쓰도록 설정 추가&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 대체가 안되는 어플리케이션 정리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- AWS의 모든 어플리케이션&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;# logback에 로컬 로깅 적용&lt;/b&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;# logback-spring.xml&amp;nbsp;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;# AWS 모킹&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;테스트 코드에서만 정상적으로 작동되도록 aws 설정을 모킹 후 결과값을 반환하도록 작성되어 있엇음&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 변경&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 로컬 aws 설정을 위한 localstack 사용&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>학습/프로젝트</category>
      <author>장동규</author>
      <guid isPermaLink="true">https://dgblog.tistory.com/317</guid>
      <comments>https://dgblog.tistory.com/317#entry317comment</comments>
      <pubDate>Fri, 5 Jul 2024 15:51:14 +0900</pubDate>
    </item>
    <item>
      <title>[SAP 시험관리] 프로젝트 DEV 서버 구축일기.</title>
      <link>https://dgblog.tistory.com/316</link>
      <description>&lt;h2 style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;프로젝트 구축 회고: 팀 작업과 기술 선택의 중요성&lt;/h2&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;프로젝트 개요&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;프로젝트는 테스트 응시자 관리 시스템을 개발&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;응시자의 계정 발급, 시험 성적 관리, 시험 문제 관리 등 백오피스 개발&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;팀 구성과 역할&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;퍼블리셔&lt;/b&gt;: UI 구현&lt;/li&gt;
&lt;li&gt;&lt;b&gt;프론트엔드 개발자&lt;/b&gt;: React를 사용한 클라이언트 사이드 로직 구현&lt;/li&gt;
&lt;li&gt;&lt;b&gt;백엔드 개발자 (나)&lt;/b&gt;: 서버 사이드 로직 및 데이터베이스 관리&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;기술스택&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;프론트엔드&lt;/b&gt;: &lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;React(&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;프론트엔드)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;백엔드&lt;/b&gt;: &lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;Spring Boot 3, &lt;/span&gt;&lt;span&gt; &lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;Mybatis&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;DB&lt;/b&gt;: &lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;MySQL&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;기술 선택 이유&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;프론트엔드&lt;/b&gt;: 팀원 중 React에 능숙한 개발자가 있어 선택.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;백엔드&lt;/b&gt;: 복잡한 도메인 로직 관리가 필요 없어 JPA 대신 MyBatis 선택.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;JWT 토큰&lt;/b&gt;: 시스템 간 통신과 인증에 JWT를 사용하여 보안 강화.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;기술 스택 축소&lt;/b&gt;: 초기에는 Redis와 Nginx를 고려했으나, 서버 용량 및 간소화를 위해 배제&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;서버 구조 및 배포 전략&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;초기 계획: Nginx, React, Spring Boot 3개의 서버와 Redis, Mysql 2개의 DB 운용&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;상용: 서버 용량의 제약으로 인해 React 애플리케이션을 Spring Boot 내부에 포함시켜 배포하는 방식으로 전환&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;위 과정에서 반복되는 작업을 찾을 수 있었다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;2.1 git pull&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;2.2 react 폴더 이동 (/frontend)&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;2.3 react npm build ( npm run build)&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;2.4 기존 static 삭제 ( ../src/main/resource/static/* )&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;2.5 빌드파일 이동 ( mv .. .. )&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;2.6 java version 충돌로 인한 자바 설정 ( export JAVA_HOME=/dir/java/jdk21/Contents/Home )&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;2.7 spring boot build ( ../gradlew bootJar )&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;2.8 깃으로 커밋 배포 (git add . -&amp;gt; git commit -m &quot;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;[&lt;/span&gt;Auto build]&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;react build and spring boot&quot; -&amp;gt; git push)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;프로젝트 재실행&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;배포는 끝났는데...&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이걸 scp로 파일을 전송해야되나.. 깃 훅을 사용해야되나 하다가 일단 ec2에서 직접접근해 쉘스크립트를 작성해서 사용하기로 했다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1. 기존 프로젝트 kill (build.jar kill ( ps HEAD^1 -&amp;gt; kill ))&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;2. git pull&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;3. 프로젝트 재실행 ( sudo nohup java -jar ./build.jar &amp;amp; )&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;회고&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;jenkins를 사용하다는게 너무 편하다는 걸 느꼇고, 좀 더 dev서버 간소화하는 방법을 고민해야겠다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;인증과 인가&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;Spring Boot 내의 인터셉터로 처리&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Security를 사용하기에는 Security에서 제공하는 기능이 부담스러워 제거하였으며, Spring내 interceptor로 처리&lt;/p&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;협업 과정&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;나와 프론트엔드 개발자 모두 본업을 하고 있어서 모든 작업에 대해 컨택하기가 힘든 상황&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;따라서 외주담당자, 프론트엔드 개발자, 백엔드 개발자 (나) 세명이서 기획협의를 zoom으로 3차례 진행하였고, 해당 내용을 PPT로 만들어 구글드라이브로 공유하였고, 프로토타입(알파버전)을 만들어 사용하면서 수정사항을 반영하기로 협의&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;회고 및 배운 점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;기술 선택의 중요성&lt;/b&gt;: JPA, Spring Security에 너무 신경안썼으면 좋겠다. 최근 JPA, JWT, Spring Security에 대해 많은 질문이 들어왔지만, 나도 무분별하게 위의 기능을 사용했던 것 같다. 이번 최소사양의 서버를 사용하게 되면서 불필요한 기능을 삭제하다 보니 통신시 필요한 내용을 이해하는게 핵심 기술을 사용하는 것 보다 우선이라는 생각이 들었다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;팀워크와 커뮤니케이션&lt;/b&gt;: 문서화와 반복적인 작업은 자동화하며, 받아드리는 자세로 커뮤니케이션 한다면 개발이 실패하는 부분은 없다고 생각한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;코드리뷰&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;: 코드리뷰가 없었던 점이 아쉽다. 정규화되지 않은 API들이 많이 배포되어 이번 프로젝트를 유지보수하며 다듬을 생각이다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>학습/프로젝트</category>
      <author>장동규</author>
      <guid isPermaLink="true">https://dgblog.tistory.com/316</guid>
      <comments>https://dgblog.tistory.com/316#entry316comment</comments>
      <pubDate>Wed, 24 Apr 2024 08:36:21 +0900</pubDate>
    </item>
    <item>
      <title>[JS] Map, Filter, Reduce</title>
      <link>https://dgblog.tistory.com/303</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;인프런 강의 정리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수형 프로그래밍과 Javascript ES6+&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*custom Map 함수&lt;/p&gt;
&lt;pre id=&quot;code_1671251858063&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/**
 f : 맵 속성을 위임할 함수
 iter : 이터러블을 반환하는 제너레이터
 function : 이터러블을 받아 맵을 생성하는 함수
**/
const map = (f, iter) =&amp;gt; {
  let res = [];
  for (const a of iter) {
    res.push(f(a));
  }
  return res;
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*원하는 value만 맵으로 생성&lt;/p&gt;
&lt;pre id=&quot;code_1671209152287&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;console.log(map(p =&amp;gt; p.name, products));
console.log(map(p =&amp;gt; p.price, products));

/**
let names = [];
for (const p of products) {
 names.push(p.name);
}
console.log(names);

let prices = [];
for (const p of products) {
  prices.push(p.price);
}
console.log(prices);
**/&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이터러블 프로토콜을 따른 map의 다형성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 기존 이터러블을 이용한 맵 객체 생성&lt;/p&gt;
&lt;pre id=&quot;code_1671252011683&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/**
 document.querySelectorAll('*')[Symbol.iterator](); //Array Iterator&amp;nbsp;{}
**/
console.log([1, 2, 3].map(a =&amp;gt; a + 1)); // [2, 3, 4]
console.log(map(el =&amp;gt; el.nodeName, document.querySelectorAll('*'))); // [ tag list ... ]

function* gen() {
  yield 2;
  if (false) yield 3;
  yield 4;
}

console.log(map(a =&amp;gt; a * a, gen())); // [4, 16]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 기존 맵을 이용한 맵 객체 생성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 맵의 값을 변경하여 사용할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1671252250403&quot; class=&quot;javascript&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let m = new Map();
m.set('a', 10);
m.set('b', 20);
console.log(new Map(map(([k, a]) =&amp;gt; [k, a * 2], m))); //Map(2)&amp;nbsp;{'a' =&amp;gt; 20, 'b' =&amp;gt; 40}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*Filter&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조건에 맞는 Value만 맵으로 생성&lt;/p&gt;
&lt;pre id=&quot;code_1671261159210&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/**
 f : 조건
 iter : 이터러블
 function : 조건에 맞는 이터러블 집합을 맵으로 생성
**/
const filter = (f, iter) =&amp;gt; {
  let res = [];
  for (const a of iter) {
    if (f(a)) res.push(a);
  }
  return res;
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1671262477963&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const products = [
  {name: '짜장', price: 10000},
  {name: '짬뽕', price: 12000},
  {name: '볶음밥', price: 15000},
  {name: '탕수육', price: 25000}
];

// 원하는 결과만 가져오기
console.log(...filter(p =&amp;gt; p.price &amp;lt; 20000, products));
// {name: '짜장', price: 10000} {name: '짬뽕', price: 12000} {name: '볶음밥', price: 15000}

console.log(...filter(p =&amp;gt; p.price &amp;gt;= 20000, products));
// {name: '탕수육', price: 25000}

console.log(filter(n =&amp;gt; n % 2, [1, 2, 3, 4])); // [1, 3]

// 제너레이터를 바로 사용할 수 있다.
console.log(filter(n =&amp;gt; n % 2, function* () {
  yield 1;
  yield 2;
  yield 3;
}())); // [1, 3]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*reduce&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;집합을 요약&lt;/p&gt;
&lt;pre id=&quot;code_1671265095923&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/** 
f : 연산함수
acc : 집합의 초기값
iter : 집합
function : 집합을 연산함수에 따라 요약하는 함수
**/
const reduce = (f, acc, iter) =&amp;gt; {
  //iter가 생략된 경우
  if (!iter) {
    iter = acc[Symbol.iterator]();
    acc = iter.next().value;
  }
  
  for (const a of iter) {
    acc = f(acc, a);
  }
  return acc;
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-사용&lt;/p&gt;
&lt;pre id=&quot;code_1671265716676&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const add = (a, b) =&amp;gt; a + b;
console.log(reduce(add, 0, [1, 2, 3, 4, 5])); // 15
console.log(add(add(add(add(add(0, 1), 2), 3), 4), 5)); // 15
console.log(reduce(add, [1, 2, 3, 4, 5])); // 15&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-사용2&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-이터러블 함수들을 다양하게 사용&lt;/p&gt;
&lt;pre id=&quot;code_1671548626479&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const products = [
  {name: '짜장', price: 10000},
  {name: '짬뽕', price: 12000},
  {name: '볶음밥', price: 15000},
  {name: '탕수육', price: 25000}
];

const add = (a, b) =&amp;gt; a + b;

const map = (f, iter) =&amp;gt; {
  let res = [];
  for (const a of iter) {
    res.push(f(a));
  }
  return res;
};

const filter = (f, iter) =&amp;gt; {
  let res = [];
  for (const a of iter) {
    if (f(a)) res.push(a);
  }
  return res;
};

/**
 reduce, add, map &amp;gt; filter 
**/
console.log(
  reduce(
    add,
    map(p =&amp;gt; p.price,
      filter(p =&amp;gt; p.price &amp;lt; 20000, products)))); //37000

/**
 reduce, add, filter &amp;gt; map
**/
console.log(
  reduce(
    add,
    filter(n =&amp;gt; n &amp;gt;= 20000,
      map(p =&amp;gt; p.price, products)))); //25000&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;읽기 좋은 코드로 변경하는 방법&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 값과 함수를 반환하는 함수 만들기&lt;/p&gt;
&lt;pre id=&quot;code_1671612129445&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/**
 (a, f) : 값과 함수로 이뤄진 파라매터 리스트
 args : 파라매터 리스트 
 go : 순차적으로 함수를 처리해 값을 반환하는 함수
 
 첫번째 값 &amp;gt;&amp;gt; 두번째 함수의 파라매터
 두번째 함수의 결과값 &amp;gt;&amp;gt; 세번째 함수의 파라매터 ...
**/
const go = (...args) =&amp;gt; reduce((a, f) =&amp;gt; f(a), args);

/**
 (...as) : 아규먼트 리스트
 f : 첫번째 함수
 fs : 함수리스트
 pipe : 내부적으로 go를 사용하는 함수 리스트
**/

const pipe = (f, ...fs) =&amp;gt; (...as) =&amp;gt; go(f(...as), ...fs);&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1671612491984&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/**
사용2 함수

console.log(
  reduce(
    add,
    map(p =&amp;gt; p.price,
      filter(p =&amp;gt; p.price &amp;lt; 20000, products)))); //37000
      
  **/
 
 /**
  위의 함수를 더 간편하게 보기위해 go함수를 사용한 리펙토링 
 **/
go(
    products,
    products =&amp;gt; filter(p =&amp;gt; p.price &amp;lt; 20000, products),
    products =&amp;gt; map(p =&amp;gt; p.price, products),
    prices =&amp;gt; reduce(add, prices),
console.log);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;#curry&lt;/p&gt;
&lt;pre id=&quot;code_1671612974347&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/**
 f = (a, ..._) 함수를 받아서 함수를 리턴
 f(a, ..._) : 리턴된 함수가 2개 이상일 때 즉시 실행
 (..._) =&amp;gt; f(a, ..._) : 리턴된 함수가 2개 미만일 때 인자를 받도록 대기하는 함수를 리턴하고
                        이 후에 받은 함수와 합쳐서 실행
**/

const curry = f =&amp;gt;
  (a, ..._) =&amp;gt; _.length ? f(a, ..._) : (..._) =&amp;gt; f(a, ..._);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- filter, map, reduce함수 에 curry함수를 적용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-기존 map, reduce, filter&lt;/p&gt;
&lt;pre id=&quot;code_1671613765365&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const map = (f, iter) =&amp;gt; {
  let res = [];
  for (const a of iter) {
    res.push(f(a));
  }
  return res;
};
const filter = (f, iter) =&amp;gt; {
  let res = [];
  for (const a of iter) {
    if (f(a)) res.push(a);
  }
  return res;
};


const reduce = (f, acc, iter) =&amp;gt; {
  //iter가 생략된 경우
  if (!iter) {
    iter = acc[Symbol.iterator]();
    acc = iter.next().value;
  }
  
  for (const a of iter) {
    acc = f(acc, a);
  }
  return acc;
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- curry가 적용된 함수&lt;/p&gt;
&lt;pre id=&quot;code_1671613870091&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const map = curry((f, iter) =&amp;gt; {
  let res = [];
  for (const a of iter) {
    res.push(f(a));
  }
  return res;
});

const filter = curry((f, iter) =&amp;gt; {
  let res = [];
  for (const a of iter) {
    if (f(a)) res.push(a);
  }
  return res;
});

const reduce = curry((f, acc, iter) =&amp;gt; {
  if (!iter) {
    iter = acc[Symbol.iterator]();
    acc = iter.next().value;
  }
  for (const a of iter) {
    acc = f(acc, a);
  }
  return acc;
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-적용된 함수&lt;/p&gt;
&lt;pre id=&quot;code_1671613939682&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; /**
  위의 함수를 더 간편하게 보기위해 go함수를 사용한 리펙토링 
go(
    products,
    products =&amp;gt; filter(p =&amp;gt; p.price &amp;lt; 20000, products),
    products =&amp;gt; map(p =&amp;gt; p.price, products),
    prices =&amp;gt; reduce(add, prices),
console.log);
 **/
 
go(
  products,
  filter(p =&amp;gt; p.price &amp;lt; 20000),
  map(p =&amp;gt; p.price),
  reduce(add),
  console.log);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-pipe 함수를 사용해 공통부분 추출 및 함수 의미부여&lt;/p&gt;
&lt;pre id=&quot;code_1671614498522&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const total_price = pipe(
    map(p =&amp;gt; p.price),
    reduce(add)); // (...as) =&amp;gt; go(f(...as), ...fs)

const base_total_price = predi =&amp;gt; pipe(
    filter(predi),
    total_price);

/**
 console.log(base_total_price(p =&amp;gt; p.price &amp;lt; 20000)(products))
**/
go(
    products,
    base_total_price(p =&amp;gt; p.price &amp;lt; 20000), // (...as) =&amp;gt; go(f(...as), ...fs)
    console.log); // 37000&lt;/code&gt;&lt;/pre&gt;</description>
      <category>기초/자바스크립트</category>
      <author>장동규</author>
      <guid isPermaLink="true">https://dgblog.tistory.com/303</guid>
      <comments>https://dgblog.tistory.com/303#entry303comment</comments>
      <pubDate>Sat, 17 Dec 2022 02:53:22 +0900</pubDate>
    </item>
    <item>
      <title>[JS] 제너레이터</title>
      <link>https://dgblog.tistory.com/302</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;인프런 강의 정리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수형 프로그래밍과 Javascript ES6+&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반함수 이름에 *을 붙여 제너레이터 함수를 만든다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제너레이터 함수 : 이터레이터를 만들어준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막 return 값은 done을 할 때 반환되는 값이다.&lt;/p&gt;
&lt;pre id=&quot;code_1671195275634&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function *func() {
    yield 1;
    if ( false ) yield 2;
    yield 3;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제너레이터는 문장을 순회할 수 있는 값으로 만들 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제너레이터를 통해 순회할 수 있는 이터러블을 쉽게 만들 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;//제너레이터 코드를 이용한 홀 수 이터러블 만들기&lt;/p&gt;
&lt;pre id=&quot;code_1671190243521&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//1씩 무한하게 증가시키는 함수
function* infinity(i = 0) {
  while (true) yield i++;
}

//1씩 무한하게 감소시키는 함수
function* infinity2(i = 0) {
  while (true) yield i--;
}

// 입력된 l까지 입력된 iter를 통해 생성하는 함수
function* limit(l, iter) {
  for (const a of iter) {
    yield a;
    if (a == l) return;
  }
}

// odds paramter : value &amp;gt; 0
// 1부터 입력된 양수 l까지 홀수만 생성하는 함수
function* odds(l) {
  for (const a of limit(l, infinity(1))) {
    if (a % 2) yield a;
  }
}

// odds2 paramter : value &amp;lt; 0
// -1부터 입력된 음수 l까지 홀수만 생성하는 함수
function* odds2(l) {
  for (const a of limit(l, infinity2(-1))) {
    if (a % 2) yield a;
  }
}

for (const a of odds(40)) console.log(a); // 1 3 5 ... 39
for (const a of odds2(-40)) console.log(a); // 1 3 5 ... 39&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;# for of, 전개 연산자, 구조 분해, 나머지 연산자&lt;/p&gt;
&lt;pre id=&quot;code_1671195965276&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;console.log(...odds(10)); // 1 3 5 7 9
console.log([...odds(10), ...odds(20)]); // [1, 3, 5, 7, 9, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19]

const [head, ...tail] = odds(5);
console.log(head); // 1
console.log(tail); // 3 5

const [a, b, ...rest] = odds(10);
console.log(a); // 1
console.log(b); // 3
console.log(rest); // 5 7 9&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>기초/자바스크립트</category>
      <author>장동규</author>
      <guid isPermaLink="true">https://dgblog.tistory.com/302</guid>
      <comments>https://dgblog.tistory.com/302#entry302comment</comments>
      <pubDate>Sat, 17 Dec 2022 00:40:31 +0900</pubDate>
    </item>
    <item>
      <title>[JS] Symbol.iterator</title>
      <link>https://dgblog.tistory.com/301</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인프런 강의 정리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수형 프로그래밍과 Javascript ES6+&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이터러블/이터레이터 프로토콜&lt;br /&gt;-&amp;nbsp;이터러블:&amp;nbsp;이터레이터를&amp;nbsp;리턴하는&amp;nbsp;[Symbol.iterator]()&amp;nbsp;를&amp;nbsp;가진&amp;nbsp;값&lt;br /&gt;-&amp;nbsp;이터레이터:&amp;nbsp;{&amp;nbsp;value,&amp;nbsp;done&amp;nbsp;}&amp;nbsp;객체를&amp;nbsp;리턴하는&amp;nbsp;next()&amp;nbsp;를&amp;nbsp;가진&amp;nbsp;값&lt;br /&gt;-&amp;nbsp;이터러블/이터레이터&amp;nbsp;프로토콜:&amp;nbsp;이터러블을&amp;nbsp;for...of,&amp;nbsp;전개&amp;nbsp;연산자&amp;nbsp;등과&amp;nbsp;함께&amp;nbsp;동작하도록한&amp;nbsp;규약&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Collection[Symbol.iterator]&lt;/p&gt;
&lt;pre id=&quot;code_1671098542283&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;- Array[Symbol.iterator] // values() { [native code] }
- Set[Symbol.iterator] // values() { [native code] }
- Map[Symbol.iterator] // entries() { [native code] }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;// Java vs Javscript For문과 비교&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;// 이터러블은 for (const a of iterable) log(a); 로 순회참조가 가능하다.&lt;/p&gt;
&lt;pre id=&quot;code_1671105550923&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//java
//string
String[] striings = [];
for( String str : striings ) {}

//hashMap
Iterator&amp;lt;Map.Entry&amp;lt;String, Integer&amp;gt;&amp;gt; iterator = map.entrySet().iterator();

while(iterator.hasNext()) {
    Map.Entry&amp;lt;String, Integer&amp;gt; entry = iterator.next();
    System.out.println(&quot;key&quot; + entry.getKey());
    System.out.println(&quot;value&quot; + entry.getValue());
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1671105582333&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//javascript Iterator

const strings = [];

const collections = strngs[Symbol.iterator]();
//const collections = new Set([]);
//const collections = new Map([]);

for (const collection of collections) {
	log(collections); // strings, set, map value
}

//map일 경우 
//아래의 경우도 모두 Symbol.iterator로 반환된다.
map.keys();
map.values();
map.entries();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Iterator를 반환하기위해 return에 [Symbol.iterator] 추가&lt;/p&gt;
&lt;pre id=&quot;code_1671114108490&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  const iterable = {
    [Symbol.iterator]() {
      let i = 1;
      return {
        next() {
          return i == 0 ? {done: true} : {value: i--, done: false};
        },
        [Symbol.iterator]() { //추가된부분
          return this;
        }
      }
    }
  };&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같이 사용이 가능해짐&lt;/p&gt;
&lt;pre id=&quot;code_1671114213700&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  let iterator = iterable[Symbol.iterator]();
  iterator.next();
  for (const a of iterator) log(a);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전개 연산자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;... 키워드를 붙이면 전체를 확인가능&lt;/p&gt;
&lt;pre id=&quot;code_1671114472608&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;console.log(...collections() )&lt;/code&gt;&lt;/pre&gt;</description>
      <author>장동규</author>
      <guid isPermaLink="true">https://dgblog.tistory.com/301</guid>
      <comments>https://dgblog.tistory.com/301#entry301comment</comments>
      <pubDate>Thu, 15 Dec 2022 23:31:26 +0900</pubDate>
    </item>
    <item>
      <title>[JS] 일급 함수와 고차함수</title>
      <link>https://dgblog.tistory.com/300</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;인프런 강의 정리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수형 프로그래밍과 Javascript ES6+&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일급함수&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 함수를 값으로 다룰 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 조합성과 추상화의 도구이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 함수가 값으로 다뤄질 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;고차함수&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 함수를 값으로 다루는 함수&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 함수를 인자로 받아서 실행하는 함수&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-일급함수 예제&lt;/p&gt;
&lt;pre id=&quot;code_1671010221862&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const inc = x = x + 1;
log( inc ); // x = x + 1
log( inc(10) ); // 11

const func1 = () = () =&amp;gt; 1;
const func2 = func1();

log( func1() ); // () =&amp;gt; 1
log( func2 ); // () =&amp;gt; 1
log( func2() ); // 1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;고차함수 - 함수를 인자로 받아서 실행하는 함수&lt;/p&gt;
&lt;pre id=&quot;code_1671011951243&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const apply = func =&amp;gt; func(1);
const inc = x = x + 1;

const repeat = (func, n) =&amp;gt; {
	let i = -1;
    while(++i &amp;lt; n) func(i);
}

repeat(log, 5); // 0 1 2 3 4 
repeat(a =&amp;gt; log(a + 10), 3); // 10 11 12 13 14&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;고차함수 - 함수를 만들어 리턴하는 함수 ( 클로저를 만들어 리턴하는 함수 )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- addMaker&lt;/p&gt;
&lt;pre id=&quot;code_1671012044289&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const addMaker = a = b = a + b;
const add10 = addMaker(10);
log(addMaker); // b = a + b ( 클로저가 리턴됨 )
log(add10(5)); // 15
log(add10(10)); // 20&lt;/code&gt;&lt;/pre&gt;</description>
      <category>기초/자바스크립트</category>
      <author>장동규</author>
      <guid isPermaLink="true">https://dgblog.tistory.com/300</guid>
      <comments>https://dgblog.tistory.com/300#entry300comment</comments>
      <pubDate>Wed, 14 Dec 2022 19:04:22 +0900</pubDate>
    </item>
  </channel>
</rss>