<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>corepen_.log</title>
        <link>https://velog.io/</link>
        <description>내가 느낌만알고 한줄도 설명할줄 모른다면 '모르는 것'이다. </description>
        <lastBuildDate>Wed, 07 Feb 2024 08:49:45 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>corepen_.log</title>
            <url>https://images.velog.io/images/corepen_/profile/5c79a3ec-5c3b-4c9d-80ea-757ea21afc34/20200913_153806.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. corepen_.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/corepen_" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[오늘 배운것 정리]]></title>
            <link>https://velog.io/@corepen_/%EC%98%A4%EB%8A%98-%EB%B0%B0%EC%9A%B4%EA%B2%83-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@corepen_/%EC%98%A4%EB%8A%98-%EB%B0%B0%EC%9A%B4%EA%B2%83-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Wed, 07 Feb 2024 08:49:45 GMT</pubDate>
            <description><![CDATA[<h2 id="navigator">Navigator</h2>
<pre><code>// 현재 페이지 
  Widget build(BuildContext context) {
    print(&#39;first build()&#39;);
    return Scaffold(
      appBar: AppBar(
        title: Text(&#39;First&#39;),
      ),
      body: ElevatedButton(
        child: Text(&#39;다음 페이지로&#39;),
        onPressed: () {
          final person = Person(&#39;장길산&#39;, 20);
          Navigator.push(
              context,
              MaterialPageRoute(
                  builder: (context) =&gt; SecondStateFulPage(
                        person: person,
                      )));
        },
      ),
    );

    // 다음 페이지 
      Widget build(BuildContext context) {
    print(&#39;SecondPage build()&#39;);
    return Scaffold(
        appBar: AppBar(
          title: Text(widget.person.name),
        ),
        body: ElevatedButton(
          child: Text(&#39;이전 페이지로&#39;),
          onPressed: () {
            Navigator.pop(context);
          },
        ));
  }</code></pre><p>현재 페이지에서 렌더링된 버튼을 클릭하면 다음페이지로 넘어갈 수 있다. 여기서 알게된것은 navigator.pop(context)를 통해 현재 -&gt; 다음 -&gt; 현재 -&gt; 다음 페이지를 수시로 왔다갔다 하여도 <code>Navigator.push( context, materialPageRoute(builder : (context) =&gt; [이동할 페이지]);</code>  (양쪽에서 할경우) 마치 페이지가 쌓이는 현사은 벌어지지않고 깔끔하게 현재 화면을 종료하고 이전 화면으로 돌아갈 수가 있다.</p>
<p><code>MaterialPageRoute</code> 클래스는 안드로이드와 iOS 환경에서 각각 플랫폼에 맞는 화면전환을 지원해준다. </p>
<h1 id="플러터-생명주기">플러터 생명주기</h1>
<p>네트워크 환경에서 종종 오래걸리면서 자주 호출되면 안되는 처리가 있다. build() 메서드외에 특정 타이밍에 실행되는 여러 메서드가 있다. 이런 메서드들을 생명주기라고 부른다. </p>
<p>initState() 메서드는 위젯이 생성될 때 호출된다. 
dispose() 메서드는 위젯이 완전히 종료될때 호출된다. </p>
<p>initState(), dispose() 메서드를 재정의할 수 있다. </p>
<pre><code>  @override
  void initState() {
    super.initState(); // 반드시 호출해야 합니다.
    print(&#39;First initstate()&#39;);
  }

  @override
  void dispose() {
    super.dispose();
    print(&#39;first dispose()&#39;);
  }</code></pre><p>한 페이지가 렌더링되고 종료될때, 각각 프린트에서 해당 메세지를 확인 할 수 있다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TiL - 오늘 배운것 ]]></title>
            <link>https://velog.io/@corepen_/TiL-%EC%98%A4%EB%8A%98-%EB%B0%B0%EC%9A%B4%EA%B2%83</link>
            <guid>https://velog.io/@corepen_/TiL-%EC%98%A4%EB%8A%98-%EB%B0%B0%EC%9A%B4%EA%B2%83</guid>
            <pubDate>Tue, 30 Jan 2024 14:34:27 GMT</pubDate>
            <description><![CDATA[<p>Flutter를 통해 ListView.seperated를 만든지 3번째 시간이었다. 
이제 많이해봐서 어떻게 data를 list에 뿌리고 하는것에 이골이난 상황이긴 하지만 여전히 제일 어려운 것은 list이후의 설계, &#39;정렬&#39;이었다. </p>
<p>그림은 얼추 비슷하게 모양은 만들기가 가능했지만 &#39;정렬&#39;을 효과적으로 수행하기 여간 어려운일이 아니었다. </p>
<p>어제 expanded를 배움으로써 남은 자식이 남은 부모공간을 모두 차지한다는 것엔 이해하였다. 
하지만, 그럼에도 마지막 하나, 정렬은 정말 어렵게 느껴졌다.. 요약한다면 오늘의 핵심 포인트는 
아래와 같다.</p>
<h2 id="핵심-포인트">핵심 포인트</h2>
<h3 id="1-정렬의-개념을-정말-닮도록-알아야-한다">1. 정렬의 개념을 정말 닮도록 알아야 한다.</h3>
<h3 id="2-피그마를-보더라도-임의로-height나-width크기를-주는것은-비추천이다">2. (피그마를 보더라도) 임의로 height나 width크기를 주는것은 비추천이다.</h3>
<h3 id="3-넣지안아도될-위젯은-과감히-지우자">3. 넣지안아도될 위젯은 과감히 지우자.</h3>
<h3 id="4-기본골격의-정렬을-중심으로-한-추상화">4. 기본골격의 정렬을 중심으로 한 추상화</h3>
<pre><code>    - 내가 만든 코드는 얼추 처음에 잘 들어맞긴하였으나 나중에 가면 갈수록 도저히 수습불가 수준으로 왔었다. 심지어 나중에 그 문제점을 다른 선임 개발자에게 물어보며 해결을 시도하였으나 얽히고 설킨 구조들 덕분에 파악하는데에 애를먹었다. 완성되고 난 코드와 골격을보니 정말 군더더기없이 다이어트 한게 아닐까 싶었다.. </code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[Dev log] Flutter animatedAlign ]]></title>
            <link>https://velog.io/@corepen_/Dev-log-Flutter-animatedAlign</link>
            <guid>https://velog.io/@corepen_/Dev-log-Flutter-animatedAlign</guid>
            <pubDate>Tue, 30 Jan 2024 14:27:08 GMT</pubDate>
            <description><![CDATA[<pre><code>Widget build(BuildContext context) {
return GestureDetector(
onTap : () {
setState(() {
    selected = !selected;
    });
    },  // onTap

    child : center(
    child : Container(
        width : double.infinity,
        height : 250.0,
        color : Colors.blue,
        child : AnimatedAlign(
            alignment : selected ? Alignment.topRight : Alignment.bottomLeft,
            duration : const Duration(seconds :1),
            curve : Curves.fastOutSlowIn,
            child : const FlutterLogo(size : 50),
           ) // AnimatedAligin
        ), // Container
       ), // Center
      ); // GestureDetector
     } </code></pre><p>마우스를  대면, flutter Logo가 선택될시 오른쪽아래에서 왼쪽아래로 움직이는것을 볼 수 있다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Dev log] Flutter BottomBar Item 레퍼런스 코드 ]]></title>
            <link>https://velog.io/@corepen_/Dev-log-%EA%B0%84%EA%B3%BC%ED%95%98%EA%B8%B0-%EC%89%AC%EC%9B%A0%EB%8D%98-%ED%94%8C%EB%9F%AC%ED%84%B0%EC%9D%98-%EA%B0%9C%EB%85%90</link>
            <guid>https://velog.io/@corepen_/Dev-log-%EA%B0%84%EA%B3%BC%ED%95%98%EA%B8%B0-%EC%89%AC%EC%9B%A0%EB%8D%98-%ED%94%8C%EB%9F%AC%ED%84%B0%EC%9D%98-%EA%B0%9C%EB%85%90</guid>
            <pubDate>Thu, 25 Jan 2024 23:08:53 GMT</pubDate>
            <description><![CDATA[<pre><code>`import &#39;package:flutter/material.dart&#39;;`

   Widget bottomNavigationBarWidget() {
    return BottomNavigationBar(
      // 애니메이션 고정. 고정하지 않는다면 아이콘이 커진다. 
      type: BottomNavigationBarType.fixed,
      onTap: (int index) {
        print(index);
        setState(() {
          selectedIndex = index;
        });
      },
      selectedFontSize: 12,
      selectedItemColor: Colors.black,
      selectedLabelStyle: TextStyle(color: Colors.black),
      items: [
        bottomNavigationBarItem(&quot;home&quot;, &quot;소통&quot;),
        bottomNavigationBarItem(&quot;search&quot;, &quot;검색&quot;),
        bottomNavigationBarItem(&quot;chat&quot;, &quot;채팅&quot;),
        bottomNavigationBarItem(&quot;my&quot;, &quot;마이&quot;),
      ],
    );
  }

// 위에서 아이콘 이름에 해당하는 &quot;home_off.svg&quot;,&quot;search_off.svg&quot;,&quot;chat_off.svg&quot;에 해당하는 것을 파라메터로 받아 아래에 적용해준다.
  BottomNavigationBarItem bottomNavigationBarItem(
      String iconName, String label) {
    return BottomNavigationBarItem(
      icon: Padding(
        // 아이콘과 명칭이름 서로 간격을 띄어주는 역할을 함
        padding: const EdgeInsets.only(bottom: 3),
        child: SvgPicture.asset(
          &#39;assets/icons/${iconName}_off.svg&#39;,
          width: 22,
        ),
      ),
      label: label,
    );
    // 클릭하면 다른 아이콘으로 변환 _on.svg가 있다면
    activeIcon: Padding(
        // 아이콘과 명칭이름 서로 간격을 띄어주는 역할을 함
        padding: const EdgeInsets.only(bottom: 3),
        child: SvgPicture.asset(
          &#39;assets/icons/${iconName}_on.svg&#39;,
          width: 22,
        ),
      ),
      label: label,
  }

    Widget build(BuildContext context) {
    return Scaffold(
      appBar: ...
      body: ...
      bottomNavigationBar: bottomNavigationBarWidget(),
    );
  }
</code></pre><p>BottomNavigationBarItem을 제네릭으로만 생각하였으나, </p>
<p><code>import &#39;package:flutter/material.dart&#39;;</code> 에 선언된 클래스중 하나였다. </p>
<p>그외, svg는 물감으로 된 아이콘들을 보통 쓴다. 
사진같은 이미지는 png로.. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Flutter Future ]]></title>
            <link>https://velog.io/@corepen_/Flutter-Future</link>
            <guid>https://velog.io/@corepen_/Flutter-Future</guid>
            <pubDate>Thu, 25 Jan 2024 23:05:16 GMT</pubDate>
            <description><![CDATA[<p>Future Builder는 미래에 완료될 비동기 작업에 대한 편리한 방법을 제공하는 Flutter 위젯이다. </p>
<p>자주 쓰이는 패턴</p>
<pre><code>Widget Body(){
return FutureBuilder(
        future: loadContents(),
        builder: (BuildContext context, dynamic snapshot) {
          List&lt;Map&lt;String, String&gt;&gt; datas = snapshot.data;
          if (snapshot.connectionState != ConnectionState.done) {
            return const Center(child: CircularProgressIndicator());
          }
          if (snapshot.hasError) {
            return const Center(child: Text(&#39;데이터 오류&#39;));
          }

          if (snapshot.hasData) {
            return makeDataList(datas);
          }
          return const Center(child: Text(&#39;해당지역에 데이터가 없습니다.&#39;));
        });
}</code></pre><ol>
<li>future : Future 타입의 객체를 받습니다. 현재 해야할 비동기 작업을 의미합니다. 여기선 <code>loadContents()</code>  메서드를 호출하여, <code>contentsRepository</code> 객체의 <code>loadContentsFromLocation</code> 메소드의 컨텐츠를 불러오는 역할을 합니다. </li>
</ol>
<pre><code>  loadContents() {
    return contentsRepository.loadContentsFromLocation(currentLocation);
  }</code></pre><ol start="2">
<li>Builder : 
<code>future</code>가 완료될때 호출되어 Ui를 빌드한다. <code>BuildContext</code>와 <code>AsyncSnapshot</code>를 매개변수로 받아서 비동기작업의 결과나 에러등을 가공하여 Ui를 구성하는 역할을 합니다. 
여기서는 <code>List&lt;Map&lt;String, String&gt;&gt;</code> 형태의 <code>datas</code> 라는 것을 받아 snapshot.data에 할당합니다. </li>
</ol>
<ul>
<li>데이터의 형태는 future에서 호출하고 있는 메소드에서 확인할 수 있습니다.  그리고 snapshot을 받으면 데이터의 형태를 확인가능합니다. <pre><code>...
future: loadContents(),
  builder: (BuildContext context, dynamic snapshot) {
    print(snapshot); // snapshot을 추가, 데이터 형태 확인
    List&lt;Map&lt;String, String&gt;&gt; datas = snapshot.data;
...</code></pre></li>
</ul>
<p>현재 데이터의 예외 처리로 <code>snapshot.connectionState</code>,<code>snapshot.hasError</code>,<code>snapshot.hasData</code> 각각 상황에 맞게 if구문과 함께 잘 쓰입니다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Flutter 일반] Hot Reload]]></title>
            <link>https://velog.io/@corepen_/Dev-Log-Hot-Reload</link>
            <guid>https://velog.io/@corepen_/Dev-Log-Hot-Reload</guid>
            <pubDate>Sun, 21 Jan 2024 02:53:35 GMT</pubDate>
            <description><![CDATA[<p>백엔드에서 <code>nodemon</code>의 기능처럼 코드가 바뀔경우 굳이 재시작 할 필요없이 구동할 수 있는것이 바로 flutter의 <code>Hot Reload</code>이다. 하지만 <code>Hot Reload</code>는 만능이 아니다. 다시말해 핫 리로딩이 되는것도 있지만, 핫 리로딩이 되지않는것이 있다는 뜻이다.</p>
<p>기본적으로 많은 상황에서 <code>Hot Reload</code>를 통해 즉각적으로 결과를 확인할 수 있지만 특정 케이스에서는 <code>Hot restart</code>,<code>Full restart</code>를 활용해야 할 수 있다. 동작하지 않는 경우는 다음과 같다.</p>
<h2 id="hot-reload가-작동하지-않는-경우">Hot Reload가 작동하지 않는 경우</h2>
<ul>
<li><p>앱이 종료된 경우</p>
</li>
<li><p>변경된 부분 지점에서 에러가 발생한 경우</p>
<ul>
<li>Compilation Error가 발생한 경우 동작하지 않을 수 있다. 해당 Error를 수정한다면 바로 결과를 확인 할 수 있다. </li>
</ul>
</li>
<li><p>Enumerated types(열거형 타입)</p>
<ul>
<li>열거형 타입을 클래스로 변경하여 클래스를 열거형 타입으로 변경할 경우</li>
</ul>
</li>
<li><p>폰트변경 </p>
<ul>
<li>대부분 assets에 대해 <code>Hot reload</code>를 지원하지만 font 변경의 경우 <code>Hot restart</code>를 해야한다. </li>
</ul>
</li>
<li><p>Generic Types</p>
<ul>
<li>type의 정의가 변경된 경우에 동작하지 않는다. </li>
</ul>
</li>
<li><p>Native Code</p>
<ul>
<li>스위프트, 코틀린, 자바등의 native 코드를 수정한경우 Full Restart를 진행해야한다. </li>
</ul>
</li>
</ul>
<p>최종적으로 <code>Hot Reload</code>는 <code>main()</code> 혹은 <code>initState()</code> 를 다시 실행하지 않기 때문에 MyApp 변경점은 보이지 않게된다. 다만 Hot Restart를 통해서는 <code>main()</code>을 다시 실행하기 때문에 기대와 같이 변경사항이 반영됨. </p>
<p>출처 : </p>
<p><a href="https://yojkim.medium.com/flutter%EC%97%90%EC%84%9C%EC%9D%98-hot-reload%EB%9E%80-8fb2ecdc757f">블로그</a></p>
<p><a href="https://docs.flutter.dev/tools/hot-reload?source=post_page-----8fb2ecdc757f--------------------------------">Flutter 공식</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[transform.translate]]></title>
            <link>https://velog.io/@corepen_/transform.translate</link>
            <guid>https://velog.io/@corepen_/transform.translate</guid>
            <pubDate>Thu, 18 Jan 2024 16:10:53 GMT</pubDate>
            <description><![CDATA[<p>transform.translate</p>
<pre><code>transform.translate(
  offset: Offset(50.0, 0.0),
  child: Container(
    color: Colors.blue,
    width: 100.0,
    height: 100.0,
  ),
)</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[CarouselSlider 레퍼런스 코드]]></title>
            <link>https://velog.io/@corepen_/CarouselSlider-%EB%A0%88%ED%8D%BC%EB%9F%B0%EC%8A%A4-%EC%BD%94%EB%93%9C</link>
            <guid>https://velog.io/@corepen_/CarouselSlider-%EB%A0%88%ED%8D%BC%EB%9F%B0%EC%8A%A4-%EC%BD%94%EB%93%9C</guid>
            <pubDate>Thu, 18 Jan 2024 14:53:55 GMT</pubDate>
            <description><![CDATA[<p>CarouselSlider 레퍼런스 코드 </p>
<pre><code>// 텍스트로 할 경우
final List&lt;String&gt; textList = [&#39;텍스트1&#39;, &#39;텍스트2&#39;, &#39;텍스트3&#39;];
// 임의의 이미지를 순서대로 넣어줄 경우 
final List&lt;String&gt; imagePaths = [
  &#39;assets/images/image1.png&#39;,
  &#39;assets/images/image2.png&#39;,
  &#39;assets/images/image3.png&#39;,
  &#39;assets/images/image4.png&#39;,
];
// 데이터에서 받아오는 경우
if(snapshot.hasData) {
     final List&lt;PlayingModel&gt; movieList = snapshot.data!;
return ... 

CarouselSlider(
                options: CarouselOptions(
                  autoPlay: true,
                  height: 200,
                  enlargeCenterPage: true,
                  aspectRatio: 16 / 9,
                  enableInfiniteScroll: true,
                  autoPlayAnimationDuration: const Duration(milliseconds: 800),
                  viewportFraction: 0.8,
                ),
                items: movieList.map((movie) {

               // 부모 위젯의 제약 조건 사용하여 자식 위젯을 빌드하는 데 사용되는 위젯
                // LayOutBuilder

                  return LayoutBuilder(
                    builder: (context, constraints) {
                      // constraints를 통해 Container의 크기를 확인할 수 있습니다.
                      double containerHeight = constraints.maxHeight;

                      return Container(
                        height: containerHeight,
                        decoration: BoxDecoration(
                            borderRadius: BorderRadius.circular(8)),
                        child: Column(
                          children: [
                            Expanded(

                              child: 
                              // 
                             // 백엔드에서 받아옴 
                              Image(
                                image: NetworkImage(movie.posterPath),
                                fit: BoxFit.contain,
                              ),
                            ),
                          ],
                        ),
                      );
                    },
                  );
                }).toList(),
              );</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[Dev Log] 오늘 알게 된것]]></title>
            <link>https://velog.io/@corepen_/Dev-Log-%EC%98%A4%EB%8A%98-%EC%95%8C%EA%B2%8C-%EB%90%9C%EA%B2%83</link>
            <guid>https://velog.io/@corepen_/Dev-Log-%EC%98%A4%EB%8A%98-%EC%95%8C%EA%B2%8C-%EB%90%9C%EA%B2%83</guid>
            <pubDate>Wed, 29 Nov 2023 12:23:59 GMT</pubDate>
            <description><![CDATA[<h3 id="1-오류">1. 오류</h3>
<p><img src="https://velog.velcdn.com/images/corepen_/post/ba99157a-380e-4207-abd9-5bca30992582/image.png" alt=""></p>
<p>안드로이드 에뮬레이터 실행시 위와 같은 오류가 나온다. </p>
<h3 id="2-조치한것">2. 조치한것</h3>
<p> Android Studio에 들어가 안드로이드 에뮬레이터를 삭제/재설치를 권장하긴 하였으나, 
flutter doctor를 먼저하고 나서, <code>flutter clean</code>, <code>flutter run</code>을 통한 프로젝트 리빌드 조치함. 그러고나서 해결.. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Dev Log] 플러터 입문, 개발]]></title>
            <link>https://velog.io/@corepen_/Dev-Log-%ED%94%8C%EB%9F%AC%ED%84%B0-%EC%9E%85%EB%AC%B8-%EA%B0%9C%EB%B0%9C</link>
            <guid>https://velog.io/@corepen_/Dev-Log-%ED%94%8C%EB%9F%AC%ED%84%B0-%EC%9E%85%EB%AC%B8-%EA%B0%9C%EB%B0%9C</guid>
            <pubDate>Mon, 27 Nov 2023 14:26:43 GMT</pubDate>
            <description><![CDATA[<h2 id="future">Future?</h2>
<p>플러터에서의 <code>future</code>는 지금은 없지만 미래에 요청할것들이 담긴 &#39;그릇&#39;과 같은것이다. 비동기에 자주 쓰이며 계산즉시 결과를 &#39;완료&#39;하여 반환한다. </p>
<pre><code>import &quot;dart:io&quot;;
Future&lt;bool&gt; fileContains(String path, String needle) async {
  try {
    var haystack = await File(path).readAsString();
    return haystack.contains(needle);
  } on FileSystemException catch (exception, stack) {
    _myLog.logError(exception, stack);
    return false;
  }
}</code></pre><p>함수에 <code>async</code>가 있고 내부에 <code>await</code>이 있는데 실행결과에 따라 <code>future</code>를 반환해야한다. 본 fileContains 함수는 future 문자열이 완료되어야 값을 반환하고 호출할때 했던 원래 future값을 완성하게 된다. </p>
<p>일반적으로 비동기 코드를 작성할때 future가 생성될때마다 항상 기다려야하며, 다음 비동기지연이 끝날때까지 기다리면 안된다. 이는 미래에 발생할 수 있는 모든 오류를 &#39;수신&#39;할 준비가 되어있음을 보장한다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[DevLog] Flutter 앱 개발 입문 ]]></title>
            <link>https://velog.io/@corepen_/DevLog-Flutter-%EC%95%B1-%EA%B0%9C%EB%B0%9C-%EC%9E%85%EB%AC%B8</link>
            <guid>https://velog.io/@corepen_/DevLog-Flutter-%EC%95%B1-%EA%B0%9C%EB%B0%9C-%EC%9E%85%EB%AC%B8</guid>
            <pubDate>Sat, 25 Nov 2023 16:13:58 GMT</pubDate>
            <description><![CDATA[<h1 id="dev-log-flutter-개발-입문">[Dev Log] Flutter 개발 입문</h1>
<h2 id="1-statefull-widget과-stateless-widget">1. StateFull Widget과 Stateless Widget</h2>
<p>정말 간단하게 설명하면 화면 변화가 <strong>&#39;있느냐&#39;</strong>와 <strong>&#39;없느냐 &#39;</strong>로 나눌 수 있다. <code>StateFull</code>같은 경우, 위젯이 동작하는 동안 이벤트, 사용자의 상호작용으로 상태가 바뀐것을 바로 반영하는 동적인 위젯이고 , <code>Stateless</code>는 그런 상호작용같은 것이 없으니 변할 일이 없다. 그래서 덕분에 렌더링이 <code>StateFull</code>보단 더 빠를 수 밖에 없는 구조이다. </p>
<h2 id="2-scaffold">2. Scaffold</h2>
<p><code>Scaffold</code>의 기본 뜻 부터 살펴봐야겠다. 공사장의 발판 혹은 건물의 골격을 의미하는데 <code>Flutter</code>앱의 역할에서도 마찬가지 역할을 한다. 기본적인 앱에서 &#39;디자인적인 뼈대&#39;를 제공해주며 <code>Scaffold</code>를 중심으로 다른 위젯들을 디자인할 수가 있다. 즉, 뼈대가 되는 위젯인 것이다. </p>
<pre><code>(new) Scaffold Scaffold({
  Key? key,
  PreferredSizeWidget? appBar,
  Widget? body,
  Widget? floatingActionButton,
  FloatingActionButtonLocation? floatingActionButtonLocation,
  FloatingActionButtonAnimator? floatingActionButtonAnimator,
  List&lt;Widget&gt;? persistentFooterButtons,
  AlignmentDirectional persistentFooterAlignment = AlignmentDirectional.centerEnd,
  Widget? drawer,
  void Function(bool)? onDrawerChanged,
  Widget? endDrawer,
  void Function(bool)? onEndDrawerChanged,
  Widget? bottomNavigationBar,
  Widget? bottomSheet,
  Color? backgroundColor,
  bool? resizeToAvoidBottomInset,
   bool primary = true,
  DragStartBehavior drawerDragStartBehavior = DragStartBehavior.start,
  bool extendBody = false,
  bool extendBodyBehindAppBar = false,
  Color? drawerScrimColor,
  double? drawerEdgeDragWidth,
  bool drawerEnableOpenDragGesture = true,
  bool endDrawerEnableOpenDragGesture = true,
  String? restorationId,
})</code></pre><p>속성은 다음과 같다.</p>
<h2 id="더-학습해야할것">더 학습해야할것</h2>
<p><code>Children</code> 위젯이 있다. &#39;리스트&#39;의 속성을 띄고있지만 정확히 그안에 무엇이들어가고 이용해야할지 기준은 아직 명확하진 못하다. 마찬가지로 <code>const</code>의 사용도 그러하다. 스튜디오코드에서 문제점과 픽스제인으로 픽스를 할뿐 정확히 왜 그런 문제를 띄는진 잘 이해가 되질 않고있다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Dev Log] Flutter 입문 - Flutter 설치와 에러슈팅

]]></title>
            <link>https://velog.io/@corepen_/Dev-Log-Flutter-%EC%9E%85%EB%AC%B8-Flutter-%EC%84%A4%EC%B9%98%EC%99%80-%EC%97%90%EB%9F%AC%EC%8A%88%ED%8C%85</link>
            <guid>https://velog.io/@corepen_/Dev-Log-Flutter-%EC%9E%85%EB%AC%B8-Flutter-%EC%84%A4%EC%B9%98%EC%99%80-%EC%97%90%EB%9F%AC%EC%8A%88%ED%8C%85</guid>
            <pubDate>Thu, 23 Nov 2023 09:02:11 GMT</pubDate>
            <description><![CDATA[<p>dart언어의 특성을 많이사용하고 dart의 문법을 많이 사용한다. dart를 먼저 배우길 권장한다.  진정한 크로스플랫폼. 하나의언어와 프레임워크로 모든것을 만들 수 있다. </p>
<p>플러터는 비디오게임 엔진처럼 작동한다. 운영체제와 직접소통하는것이 아니라 &#39;엔진&#39;을 통해 그린다. 네이티브완 다르게 위젯이 가짜로 생성되고 만들어진다. </p>
<p>dart코드는 프레임워크상에서만 이용된다. </p>
<ol>
<li>엔진을 통해모든 컴포넌트를 그림 ios처럼 보여지긴함. 하지만 페이크 </li>
<li>스크린과 애니메이션 효과가 아주 멋짐  오히려 우리가 ㅈㄱ접 커스터마이징한 아름다운 디자인을 만드는데에 목표를 두고있다. </li>
<li>안드로이드/iOS 앱 처럼 보이게끔 만들고 싶지 않다면 플러터가 무난하다. 화면상의 모든 픽셀을 100% 통제할 수 있어야한다.</li>
</ol>
<h2 id="flutter-설치">Flutter 설치</h2>
<p>uBuntu 22.04.3 LTS jammy 버전 환경에서 쓴다. </p>
<h3 id="1-flutter-설치">1. Flutter 설치</h3>
<p> <a href="https://docs.flutter.dev/get-started/install/linux#android-setup">&#39;Flutter 공식 홈페이지&#39;</a>에 들어가서 <code>snap</code>을 이용한 방법으로 설치하였다. 
<img src="https://velog.velcdn.com/images/corepen_/post/f4b2d9bd-e259-4634-b139-961b3dd40101/image.png" alt=""></p>
<h3 id="2-android-toolchain-error">2. Android toolchain error</h3>
<p>설치 한후 일단 <code>flutter doctor</code>을 입력한뒤 확인해 보면 <code>Android toolchain</code>이 다음과 같음을 확인할수 있음과 동시에 <code>Android Studio</code>도 설치가 되질 않다고 나와있다.
<img src="https://velog.velcdn.com/images/corepen_/post/552e10ff-3b90-42a2-b2ab-e402dbefb953/image.png" alt=""></p>
<h3 id="3-android-studio-설치">3. Android Studio 설치</h3>
<p>안드로이드 스튜디오는 <a href="https://developer.android.com/studio?hl=ko">첫번째 링크</a> 에 있는곳에 들어가 다운로드를 받을 수 있다. 일단 설치하자.  그래야 위의 에러를 해결할 수 있다. </p>
<p> <code>flutter config --android-studio-dir=/home/corepen/android-studio</code> 경로를 입력하고 studio 경로를 등록해준다. 스튜디오 설치 경로를 알 수 있는 방법은 해당폴더로 들어간뒤  마우스 오른쪽으로 <strong>&#39;터미널 열기&#39;</strong>로 해당 경로에서 진입한뒤 <code>pwd</code>를 아래와 같이 입력한다.</p>
<p><img src="https://velog.velcdn.com/images/corepen_/post/df3ee5f5-d4ba-4160-a64c-13ef0007cbe7/image.png" alt=""></p>
<p>   그러면 해당 경로가 뜨는데 그 경로를 위와같이 붙여넣어 <code>android-studio</code>의 경로를 등록한다.</p>
<h3 id="4-android-toolchain-error-슈팅---1-android-studio-실행하기">4. Android toolchain error 슈팅 - 1 (Android Studio 실행하기)</h3>
<p>하지만 공식문서에 나온대로 명령어인 <code>flutter sdk-path</code>를 입력하면 경로가 뜨지만, 그 경로대로   <code>flutter doctor --android-sdk=&quot;/PATH&quot;</code> 를 입력해도 여전히 에러가 뜬다. </p>
<p><img src="https://velog.velcdn.com/images/corepen_/post/27ec8bcf-d9ef-4efb-81ac-8b5cd12e57ec/image.png" alt="">
위와 같이 <code>bin</code>폴더에 들어간 뒤, <code>studio.sh</code>를 실행하여 스튜디오로 들어간 다음, 아래왜 같이 <code>MoreActions</code>를 클릭한뒤 SDK Manager에 들어간다.</p>
<p><img src="https://velog.velcdn.com/images/corepen_/post/3f7a6bea-d116-4820-9baf-e12272582115/image.png" alt=""></p>
<h3 id="5-4-android-toolchain-error-슈팅---2-command-line-tools-설치하기">5. 4. Android toolchain error 슈팅 - 2 (Command-line Tools 설치하기)</h3>
<p>화면과 같이 들어가서, <code>Android SDK Command-line Tools(latest)</code>를 다음과 같이 인스톨한뒤 위에 있는 <code>SDK Location</code>에 나오는 경로를 <code>flutter doctor --android-sdk=&quot;/PATH&quot;</code>의 PATH 자리에 넣어주면된다.</p>
<p><img src="https://velog.velcdn.com/images/corepen_/post/5839626f-7bbd-4f5b-84a6-b1ba7900a9dc/image.png" alt=""></p>
<h3 id="6-해결">6. 해결</h3>
<p>flutter doctor 를 입력해본다.
<img src="https://velog.velcdn.com/images/corepen_/post/358b16f7-b420-44a0-8c8b-fc900b50c753/image.png" alt=""></p>
<p>위 화면 처럼 나오는데 마지막으로 <code>flutter doctor --android-licenses</code>만 입력해주면 해결 </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Dev Log] Dart - 5 (클래스 -2)]]></title>
            <link>https://velog.io/@corepen_/Dev-Log-Dart-5-%ED%81%B4%EB%9E%98%EC%8A%A4-2</link>
            <guid>https://velog.io/@corepen_/Dev-Log-Dart-5-%ED%81%B4%EB%9E%98%EC%8A%A4-2</guid>
            <pubDate>Wed, 22 Nov 2023 12:34:00 GMT</pubDate>
            <description><![CDATA[<h2 id="기억에-남는것">기억에 남는것</h2>
<h3 id="1-casecade-notation">1. Casecade Notation</h3>
<pre><code>   class Player {
       final String name;
       int xp, age;
       String team;

   Player({
   required this.name,
   required this.xp,
   required this.team, 
   });

   // flutter 를 쓰면서 자주 쓰게될 문법
   void main() {
       var lee = Player(name : &quot;nico&quot;,xp: 1500, team : &#39;red&#39;)
       var potato = nico
       ..name = &#39;las&#39;
       ..xp = 2000
       ..team = blue;
       ..sayHello();
   }</code></pre><h3 id="2-enums">2. Enums</h3>
<p>   바보같은 실수들을 안만들게끔 도와준다.!</p>
<p>   예를 들면 team값을 잘못 넣을때 개발자들이 오타로 실수하지 않게끔 도와준다. 
   enum을 쓰기위해선 enum을 붙여주고 쓴다.</p>
<pre><code>   enum Team {red, blue}
   enum XpLevel {beginner , medium, pro}

   class Player {
       final String name;
       XpLevel xp;
       Team team;
       // String 대신에 위의 enum의 Team을 넣어준다.
   }</code></pre><p>   활용 예시</p>
<pre><code>   (.. 위와 동일 생략)

   Player({
   required this.name,
   required this.xp,
   required this.team, 
   });

   void main() {
       var lee = Player
       (name : &quot;nico&quot;,xp: XpLevel.beginner, team : &#39;red&#39;);

       var potato = nico
       ..name = &#39;las&#39;
       ..xp = XpLevel.medium
       ..team = Team.blue;
       ..sayHello();
   }</code></pre><h3 id="3-abstract-classes-추상화-메서드">3. Abstract Classes 추상화 메서드</h3>
<p>   추상화 클래스로는 객체를 생성할 수 없다.  추상화 클래스는 다른 클래스들이 직접 구현해야 하는 메소드들을 모아놓은 일종의 <code>청사진</code> 이라 보면된다. </p>
<pre><code>   abstract class Human {
       void walk();
   }

   class Player extends Human {
       final String name;
       XpLevel xp;
       Team team;

       void walk(){
           print(&#39;i m walk now&#39;)
       }
   }

</code></pre><h3 id="4-inheritance-상속-클래스">4. InHeritance 상속 클래스</h3>
<pre><code>   enum Team {red, blue}

   class Human {
       final String name;
       Human(required this.name);
       void sayHello() {
           print(&quot;Hi my name is $name&quot;)
       }
   }


   class Player extends Human {
       final Team team ; 
   }

   Player({
       required this.team,
       required String name
   }) : super(name : name);

   // 직접 만든 메소드로 대체(overrride) 한다
   @override 
   void sayHello(){
       super.sayHello();
       print(&#39;and I play for ${team}&#39;)
   }

   void main() {
       var player = Player(
           team : Team.red,
           name : &#39;nico&#39;
       )
       player.sayHello()
   }</code></pre><h3 id="5-mixins">5. Mixins</h3>
<p>   클래스에 property를 추가할 때 매우 유용하다.  <code>with</code> 라는 키워드를 사용해서 단순히 Mixin 내부의 프로퍼티와 메소드를 가져오는 것이다. </p>
<p>   조건은 생성자가 없는 클래스여야 한다</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Dev Log] Dart - 4 (클래스 - 1)]]></title>
            <link>https://velog.io/@corepen_/Dev-Log-Dart-4-%ED%81%B4%EB%9E%98%EC%8A%A4-1</link>
            <guid>https://velog.io/@corepen_/Dev-Log-Dart-4-%ED%81%B4%EB%9E%98%EC%8A%A4-1</guid>
            <pubDate>Wed, 22 Nov 2023 12:33:10 GMT</pubDate>
            <description><![CDATA[<h2 id="기억에-남는것">기억에 남는것</h2>
<p>다른 클래스도 많이 만들거라 class에 대해 제대로 배우고 문법을 마스터 하는것이 중요하다. 다른언어에서의 class와 어떻게 다른지에 대해서도 배우는 것이 중요할 것이다. </p>
<h3 id="1-first-dart-class">1. First Dart Class</h3>
<pre><code>   class Player {
       String name = &#39;lee&#39;
       // final String name = &#39;lee&#39;
       // final을 붙이면 값을 변경할 수가 없다. 
       int xp = 1500;

   void Say(){
       var name = &#39;121&#39;
       print(&quot;my name is $name&quot;);
       }
   }

   void main() {
       var player = Player();
       print(player.name);
       player.name = &#39;lalala&#39;
       print(play.name);
   }</code></pre><p>   <strong>class 를 사용할땐 타입을 꼭 명시해 줘야한다.</strong></p>
<p>   그냥 name이라고 써도 this.name이라고 쓰는 것과 같다. 일부러 함수 내에 할당된 이름을 쓰고 싶다면 <code>${this.name}</code>을 작성 해야한다. </p>
<h3 id="2-생성자-constructors">2. 생성자 (Constructors)</h3>
<pre><code>   class Player {
       String name = &#39;lee&#39;
       // final String name = &#39;lee&#39;
       // final을 붙이면 값을 변경할 수가 없다. 
       int xp;

   Player(this.name, this.xp);

   void Say(){
       var name = &#39;121&#39;
       print(&quot;my name is $name&quot;);
       }
   }

   void main() {
       var player = Player(&quot;nico&quot;, 1500);
       player();
       var player2 = player(&quot;lynn&quot;, 2500);
       player2();
   }</code></pre><h3 id="3-named-생성자-파라메터">3. Named 생성자 파라메터</h3>
<pre><code>   class Player {
       final String name 
       int xp;
       String team;
       int age;

   Player({this.name, this.xp, this.team, this.age});
   // nullable을 방지하기위해 앞에 required를 붙여주면 좋다.(필수값)

   void Say(){
       var name = &#39;121&#39;
       print(&quot;my name is $name&quot;);
       }
   }

   void main() {
       var player = Player(
       name : &quot;nico&quot;, xp : 1500,team : &#39;red&#39;, age : 12
       );

       var player2 = player(
       name : &quot;lynn&quot;, xp : 2500, team : &#39;blue&#39;,age: 12
       );
   }</code></pre><h3 id="4-named-생성자">4. Named 생성자</h3>
<pre><code>   class Player {
       final String name;
       int xp, age;
       String team;

   Player({this.name, this.xp, this.team, this.age});
   // nullable을 방지하기위해 앞에 required를 붙여주면 좋다.(필수값)

   void Say(){
       var name = &#39;121&#39;
       print(&quot;my name is $name&quot;);
       }
   }

   Player.createBluePlayer({required String name, required int age}) : 
   this.age = age,
   this.name = name,
   this.team = &#39;blue&#39;, 
   this.xp = 0;

   // &#39;:&#39;은 class를 초기화 시키는 것이다. 

   Player.createRedPlayer(String name, int age) : 
   this.age = age, 
   this.name = name,
   this.team = &#39;red&#39;,
   this.xp = 0;

   void main() {
       var player = Player.createBluePlayer(
       name : &quot;nico&quot;,  age : 12
       );

       var player2 = player.createRedPlayer(
       name : &quot;lynn&quot;, age: 12
       );
   }</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[Dev Log] Dart -3 ]]></title>
            <link>https://velog.io/@corepen_/Dev-Log-Dart-3</link>
            <guid>https://velog.io/@corepen_/Dev-Log-Dart-3</guid>
            <pubDate>Wed, 22 Nov 2023 12:32:26 GMT</pubDate>
            <description><![CDATA[<h3 id="1-named-parameters">1. Named Parameters</h3>
<pre><code>   String Hello({String name = &#39;anon, int age = 99, String country = &#39;wakanda&#39;})
   // 뒤에 잇는 것은 값이 없을경우 기본값들을 미리 정해준것이다. 
   void main() {
       print(Hello(
           age : 12,
           country : &#39;korea&#39;,
           name : &#39;lee&#39;
       ))
   }</code></pre><p>   <code>required</code>를 적어주면 호출할때마다 항상 해당 요소를 불러준다. </p>
<p>   null safety때문에 default값을 위처럼 넣어줬따. </p>
<h3 id="2-optional-positional-parameters">2. optional positional parameters</h3>
<h3 id="3-qqq-operator">3. QQQ Operator</h3>
<h3 id="4-typedef">4. Typedef</h3>
<pre><code>   typedef ListOfInts = List&lt;int&gt;;

   List&lt;int&gt; reverseListOfNumbers(List&lt;int&gt; list) {
       var reversed = list.reversed;
       return reversed.toList();
   }
   void main() {
       return &quot;&quot;
   }</code></pre><p>5. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Dev log] Dart 학습 - 2 (자료형)]]></title>
            <link>https://velog.io/@corepen_/Dev-log-Dart-%ED%95%99%EC%8A%B5-2-%EC%9E%90%EB%A3%8C%ED%98%95</link>
            <guid>https://velog.io/@corepen_/Dev-log-Dart-%ED%95%99%EC%8A%B5-2-%EC%9E%90%EB%A3%8C%ED%98%95</guid>
            <pubDate>Wed, 22 Nov 2023 12:31:33 GMT</pubDate>
            <description><![CDATA[<h2 id="기억에-남는것">기억에 남는것</h2>
<h3 id="1-리스트">1. 리스트</h3>
<pre><code>   voide main() {
       List&lt;int&gt; numbers = [1,2,3,4,5];
       numbers.add(1); 
       numbers.first; // 제일 첫번째요소
       numbers.last; // 제일 마지막요소 

   }</code></pre><p>   collection if와 collection for를 지원한다. if로 존재할수도 안할수도있는 요소를 만들어줄수 있다 . </p>
<pre><code>   var givemeFive =5;

   [1,2,3,4, if(givmeFive) 5] // 5가 없으면 5를 추가한다 </code></pre><h3 id="2-collection-if">2. collection if</h3>
<p>   UI 인터페이스만들때 아주 좋다고함. </p>
<pre><code>   voide main() {
    var name = &#39;lee&#39;
    var age = 10;
    var greeting = &#39;Hello $name, ${age +2}&#39;;

    print(greeting) 
   }</code></pre><h3 id="3-collection-for">3. collection for</h3>
<pre><code>   void main() {
       var oldFriends = [&#39;lee&#39;, &#39;park&#39;]
       var newFriends = [ 
           &#39;lewis&#39;,
           &#39;ralph&#39;,
           &#39;darren&#39;
           for (var friend in oldFriends) &quot; $friend&quot;
       ];
       print(newFriends)
   }</code></pre><p>   시간을 굉장히 아껴줌. 요소 추가 </p>
<h3 id="4-maps">4. Maps</h3>
<pre><code>   void main() {
       Map&lt;int, bool&gt; player = {
           1 : true,
           2 : false,
           3 : true
       }
   }</code></pre><p>   자료형과 값을 동시에 할당할수 있다. </p>
<h3 id="5-sets">5. Sets</h3>
<pre><code>   void main() {
       Set&lt;int&gt; numbers = {1,2,3,4,5};
       print(numbers)
   }</code></pre><p>   Set에 속한 아이템은 유니크하다.! 요소가 항상 하나씩만 있어야 한다면 Set을 사용하면된다 . 유니크할 필요가없다면 List를 사용하라.  LIst는 파이선의 list와 같고, Set은 파이썬의 튜플과 같다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Dev log] Dart 학습 - 1 ]]></title>
            <link>https://velog.io/@corepen_/Dev-log-Dart-%ED%95%99%EC%8A%B5-1</link>
            <guid>https://velog.io/@corepen_/Dev-log-Dart-%ED%95%99%EC%8A%B5-1</guid>
            <pubDate>Wed, 22 Nov 2023 12:30:13 GMT</pubDate>
            <description><![CDATA[<h1 id="dart-학습---1-변수">Dart 학습 - 1 (변수)</h1>
<h2 id="기억에-남는것">기억에 남는것</h2>
<h3 id="1-dart와-flutter는-마치-한몸이다">1. Dart와 Flutter는 마치 한몸이다.</h3>
<p>   reactJS같은 경우 JavaScript 기반으로 만들어 졌다. 하지만 빠르고 쾌적한 사용을 위해 reactJS팀은 입맛에 맞게 JavaScript를 바꿀 수 없지만, flutter와 dart는 같은회사의 가까운 협력관계이므로 원한다면 flutter에 맞게 dart를 업데이트하여 바꿀 수 있다. 그정도로 flutter와 한 몸같은 언어 이다. flutter에서 새로운 프레임워크가 필요하다면 dart에서 최적화 해주는것이 가능하단 이야기이다. </p>
<h3 id="2-dartpaddev">2. dartpad.dev</h3>
<p>   [&#39;dartpad.dev&#39;] 이곳에 들어가면 바로 별도의 설치없이 dart 에디터를 실행 할 수 있다. </p>
<h3 id="3-dart는-진정한-객체지향-언어이다">3. dart는 진정한 객체지향 언어이다.</h3>
<p>   flutter도 마찬가지로 객체지향 프레임워크이고 항상 class를 사용한다.</p>
<h3 id="4-semi-콜론을-꼭-써야-한다">4. semi 콜론을 꼭 써야 한다.</h3>
<pre><code>   voide main() {
       print(&#39;hello world&#39;);
   }</code></pre><p>   <code>;</code>을 안쓸 수도 있지만 심각한 문제를 유발하기도 한다. 그동안 자바스크립트와 타입스크립트는 굳이 달지 않아도 <code>formatter</code>나 <code>VisualStudioCode</code> 에서 자동으로 세미콜론을 달아준다. 하지만 여기선 그렇지 않다. 왜냐하면 dart에선 일부러 세미콜론을 달지 않을때가 있기에 그렇다.</p>
<h3 id="5-모든-코드는-main함수안에-포함이-된다">5. 모든 코드는 <code>main</code>함수안에 포함이 된다.</h3>
<p>   반드시 main 함수 안에 포함이 되어야 하며, 코드는 main함수 내부에 작성이 된다. </p>
<h3 id="6-변수-만들기">6. 변수 만들기</h3>
<pre><code>   void main () {
       var name = &#39;lee&#39;; 
       // name != 1 
       // 업데이트 할 수 없다 
       String name = &#39;lee&#39;
       // 타입명으로 변수를 만들어 줄수 있다.
   }</code></pre><p>   변수에는 같은 타입의 값만 들어올 수 있으며, 숫자나 다른 변수타입의 값은 할당할 수가 없다. 그리고 명시적으로 String같은 타입으로 명시적인 변수를 만들수 있다.</p>
<h3 id="7-dynamic-type">7. Dynamic Type</h3>
<pre><code>   voide main() {
        var name;  // dynamic name;
       name = &quot;lee&quot;;
       name = true;
       name = 12; 
   }</code></pre><p>   이상적으론 쓰는것을 피하는것이 맞다. </p>
<h3 id="8-nullable-변수">8. Nullable 변수</h3>
<pre><code>   voide main() {
    String? lee = &#39;lee&#39;;
    // dart가 string 혹은 null 여부가능을 말한다.
    lee = null;
    lee?.isNotEmpty;
   }</code></pre><p>   dart는 위와같이 지정해둔다면 null일수 있다는것을 알게된다. </p>
<h3 id="9-final-변수">9. final 변수</h3>
<pre><code>   voide main() {
       fianl String name = &#39;lee&#39;;
                   name = &#39;lee&#39;;
   }</code></pre><p>   <code>const</code>와 같다. final을 붙이면 변수의 값을 바꿀 수가 없다. 그리고 구체적으로 하기위해 타입도 위처럼 추가해줄 수있다. (String은 없어도 그만 있어도 그만.. )</p>
<h3 id="10-late-변수">10. late 변수</h3>
<pre><code>`late`는 아직 어떤데이터가 올지 모른다고 말해주는것이다.  

```
voide main() {
     late final String name;
    name =&#39;12&#39;   
    print(name);
}
```

그래서 데이터를 &#39;나중에&#39; 넣고 그뒤에 변수를 사용하겠다는 이야기이다.

아직 정의되지않은 late 변수에 접근할 수 없다. </code></pre><h3 id="11-const-변수">11. const 변수</h3>
<p>  자바스크립트와 타입스크립트와는 다른양상이다. 변수들은 컴파일할때 평가될것이다. 컴파이리할때 값을 알고있는 변수를 만들때 쓰는 방법이다. </p>
<h3 id="12-마지막">12. 마지막</h3>
<p>   공식적으로 <code>var</code> 사용이 권장되고 <code>String</code> 이나 <code>int</code>같은 타입을 변수로 사용하는 것은 class과 property를 사용할때 권장된다. 작은 함수나 지역변수에서는 var를 쓰는것이 더 좋다. 
변수의 수정허용을 하지않는다면 <code>final</code>을 사용한다.  <code>dynacmic</code>은 아주 조심스럽게 써야하며 자주쓰는것을 권장하지 않는다. 데이터가 무엇이 들어올지 모를때 쓴다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Dev Log 노트]]></title>
            <link>https://velog.io/@corepen_/Dev-Log-%EB%85%B8%ED%8A%B8</link>
            <guid>https://velog.io/@corepen_/Dev-Log-%EB%85%B8%ED%8A%B8</guid>
            <pubDate>Fri, 26 May 2023 11:59:05 GMT</pubDate>
            <description><![CDATA[<h2 id="dev-log-노트">Dev Log 노트</h2>
<h3 id="1-개발-방법의-선회">1. 개발 방법의 선회</h3>
<p>기존엔 공식문서를 읽어보며 CRUD부터 체득해가며 개발하려 했으나 빠른 개발기한을 맞추기 위해 기존강의를 보면서 다시 습득가능 한것들을 습득 </p>
<h4 id="현재-상황">현재 상황</h4>
<ol>
<li>NestJs설치 </li>
<li>C,R 만듬 / U,D의 부재 </li>
<li>NestJS 프레임워크 아키텍처 이해 </li>
</ol>
<h4 id="계획안">계획안</h4>
<pre><code> 1. 기존 강의 구조와 컨트롤러 패턴 부터 실전 프로젝트까지 재복습
 2. 필요하다 싶은것은 구글링을 통한검색 
 3. postgre와 graphql을 이용한 데이터베이스 관리
 4. 탈부착형 데이터베이스 
 5. Docker 활용</code></pre><h4 id="오늘-목표">오늘 목표</h4>
<pre><code> 1. 재 복습
 2. U,D 만들어둘것 </code></pre><h4 id="풀어야할-질문개념">풀어야할 질문/개념</h4>
<ol>
<li><p>컨트롤러에서 <code>@Params</code>나 <code>@Body</code>를 받아온다면, 그것을 해당 모듈 서비스에서 받아올 수 있는가 ?  어떻게 넘기는가 ? </p>
<pre><code>@Get(&#39;users/:id/:name&#39;)

​    getHello(@Req() req:Request, @Body() Body, @Param() param) : string {

​        // 아래와 같이 appService에 Body와 Param을 넘겨줄 수 있다. 

​        return this.appService.getHello(Body, Param)

​    }

// 상태 코드

@Post()
@HttpCode(204)
create() {
    return &#39;this action add a new user&#39;
}</code></pre></li>
</ol>
<p>​        </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[독서 감상]]></title>
            <link>https://velog.io/@corepen_/%EB%8F%85%EC%84%9C-%EA%B0%90%EC%83%81</link>
            <guid>https://velog.io/@corepen_/%EB%8F%85%EC%84%9C-%EA%B0%90%EC%83%81</guid>
            <pubDate>Fri, 26 May 2023 10:12:27 GMT</pubDate>
            <description><![CDATA[<h2 id="신현준의-배우의-삶이란">신현준의 배우의 삶이란?</h2>
<h3 id="1-롤-모델">1. 롤 모델</h3>
<p>롤 모델은 꼭 필요한 것일까 ? &#39;코리안 루트&#39;를 개척하기 위해 박영석 대장은 안나푸르나 남서벽 원정에 나섰다. 하지만 애석하게도 그는 실종되었고 다큐멘터리를 보면서 배우의 길도 다르지 않다는 생각을 하였다. 산 정상으로 오르는 길이 여러가지 있듯 최고의 배우가 되는 길도 여러가지다. 누군가가 밟고 지나간 길을 따라 오를 수 있고, 새로운 길을 개척할 수도있다. 새로운 길은 언제나 힘들고 험난하며 시간도 많이 걸린다. 한마디로 실패할 확률이 높다. 반면에 이미 만들어 놓은 길을 따라 올라간다면 더 쉽게 정상에 오를 수있다. </p>
<p>처음에는 누군가가 개척해 놓은 길을 따라 히말라야를 정복했다. 그 업적을 이룬다음 자신만의 루트를 만들기 위해 나섰던것이다. 롤 모델이란 바로 이런것이다. 당신이 배울만한 점이 하나라도 있다면 그를 롤모델로 삼아라. </p>
<p><strong>&quot;한 작가의 것을 훔치면 표절이지만 많은 작가의 것을 훔치면 연구다.&quot;</strong>  </p>
<p>완벽한 사람은 없다. 여러사람의 장점을 두루 공부하는 것이 좋다. 다양한 재능을 갖추려면 롤 모델 역시 다양해야 하지 않을까? 그러나 , 똑같이 흉내내는 것과 장점을 배우는 것은 엄밀히 다르다. 그의 장점을 받아들여 자신의 스타일로 녹여내야한다. 반드시 롤모델과 똑같은 길을 걷는다면 당신은 분명 실패하고 말 것이다. (제 2의 누구..) </p>
<h3 id="2-배우와-관객">2. 배우와 관객</h3>
<p>배우의 역할은 관객들에게 메세지를 전달하는 것이다. 배우의 정의를 어떻게 내리던 간에 항상 &#39;관객을 위한&#39; 이란 수식어가 들어가야한다. 관객이 있어야 배우가 있다. 시인이 멋진 시를 써도 읽어 주는 사람이 없다면 그 시는 휴지조각이다. 관객은 무언가를 얻기 위해 배우의 연기를 본다. 따라서 배우는 관객에게 &#39;무언가&#39;를 줘야 한다. 이러한 계약이 깨진다면 관객은 배우를 외면하고, 배우는 도태되고만다. </p>
<p>절망에 빠진 사람이 배우의 연기를 보고 삶의 희망을 얻거나 , 배우의 연기를 보고 활짝 웃는다거나 그렇다면 배우의 소임을 다하는 것이다. 배우란 사람의 마음을 사는 일이다. </p>
<p>기술이 좋으면 몇년은 가지만 결국 들킨다. 가장 중요한것은 &#39;진심&#39;이다. </p>
<p>*<em>준비는 적게 하면서 많은 것을 얻으려 하는 곳에 항상 한숨이 숨어있다.  - 괴테 *</em></p>
<h3 id="3-캐릭터의-몰입과-동화">3. 캐릭터의 몰입과 동화</h3>
<p>시나리오를 받고나면 캐릭터와 약속을 하고 피나는 연습과 노력을 해야한다. 자기가 맡은 역할을 위해 모든 책임을 다해야 하며, 촬영이 들어가기 전까지 배역과 완벽하게 일치되어 있어야 한다. 심지어 그 인물이 가지고 있는 비밀스러운 생각까지도 배우는 잡아내야만 한다. </p>
<p>나는 &#39;기봉이&#39;가 되기위해 몰입했다. 그는 장애를 가졌기 때문에 말투와 표정, 동작과 호흡까지 남달라야만 했다. 나는 기봉이가 되기위해 영화를 시작하기 전부터 모든것을 기봉이처럼 바꿨다. 걸을때도, 식당에서도 주문할때도 기봉이 말투로 주문했다. </p>
<p>나는 기봉이 처럼 되기위해 6개월을 뛰고 기봉이 처럼 표정지으며 말했다. 이것이 내 옷처럼 익숙해지고 편해져야 동작에 신경 쓰지 않고 연기를 할 수 있으니까. </p>
<p>배우에게 있어 캐릭터의 완성은 완벽한 몰입을 통해 이뤄진다. 그렇지만 몰입은 저절로 이뤄지지않는 것이 아니다. 캐릭터와 몰입하려면 우선 캐릭터와 동화되어야 한다. </p>
<p>강제규 감독님은 말했다.</p>
<p>&quot;배우가 이 상황을 믿지 않고 연기를 한다면 되겠는가?&quot;</p>
<p>&quot;우리도 믿지 않으면서 관객에게 믿으라고 강요하는 건가? 믿어라! 동화하라! 어떤 상황이든 배우는 이 상황을 본인에게 일어난 실제 상황이라고 생각하고 믿어야한다.&quot;</p>
<p>.. 내가 맡은 캐릭터를 연기하는게 아니다. 내가 그 캐릭터가 되는것이다. 뭐든지 상상할 때 &#39;나&#39;에서 부터 출발해야 한다는 것을 명심해야한다. &#39;내가 이 상황에 처했더라면 ?&#39; 이것이 첫번째다. </p>
<p>그리고 본인이 직접 그상황을 느끼기 때문에 감정도 자연스럽다. </p>
<p>캐릭터를 제대로 소화하고 싶다면 캐릭터와 최대한 닮아야 한다. 그리고 캐릭터와 최대한 닮으려면, 그 캐릭터와 동화되기 위해 할 수 있는 한 무엇이든 해야한다.(남에게 피해주지 않는 선에서 한함.) 머릿속으로 상상하는 감정과 실제로 부딪혀서 느낀 감정은 분명 큰 차이가 있다. 실제 촬영이 들어가면 자신이 맡은 캐릭터의 심리 상태를 계속 유지하는 것이 좋다. </p>
<p>당신이 진짜 배우의 길을 걷고 싶다면, 오늘 연기 연습을 할 때 당신이라는 인간은 잠시 잊어야 한다. 그리고 캐릭터가 되어라. 캐릭터가 회사원이면 회사원 , 캐릭터가 배달원이면 잠시 배달원이 되어 경험을 쌓아라. </p>
<p>배우는 관객들이 영화 속 캐릭터에 빠져들게 해야한다. 그러기 위해서는 내가 연기해야 할 캐릭터와 하나가 되어야 한다. 그것이 배우가 해야 할 몫이다. </p>
<h4 id="캐릭터를-정형화-시키지-마라">캐릭터를 정형화 시키지 마라</h4>
<p>현실을 살아가는 인물 중 똑같은 감정을 24시간 유지하는 사람은 없다. 사람의 감정은 순간순간 변한다. 떄로는 아주 극단적으로 변하기도 한다. 배우는 캐릭터에 몰입하고 동화되어야 한다. 하지만 그 캐릭터를 유형화하는 일에 관심을 두어서는 안된다. 캐릭터를 추상적인 울타리에 가두려고 하지마라. 섣부른 판단은 생생하게 살아 있는 캐릭터를 연기하는데 방해된다. 그리고 캐릭터에 대한 당신의 판단이 잘못될 수 있다는 것을 항상 명심해라. </p>
<p>어떤 캐릭터를 준비하다 보면 자신이 직접 체험해 볼 수 없는 경우가 생긴다. 입양아가 아닌데 어떻게 입양아를 체험해 볼 수 있겠는가 ? 그런경우 직접 인터뷰 해보는 것이 제일 좋은 방법이다. 인터뷰를 하다보면 우리가 머릿속으로 생각하고 있던 것들이 얼마나 비현실적이었는지 깨닳을 수 있다. </p>
<p>우리의 인생은 비극도, 희극도 아니다. 그것을 합쳐놓은 &#39;혼합물&#39; 이다. 캐릭터를 어느 한쪽으로만 몰아가려 한다면 당신은 치명적인 실수를 범하는 것이다. </p>
<p>하지만 인터뷰,취재,주변사람 관찰등으로 캐릭터를 창조해 낼때 조심해야할 것이 하나가 있는데, 절대 그 인물과 똑같이 흉내 내려고 하지마라. 기봉이는 실존인물이지만 내가 만든 기봉이와는 다르다. 실제 인물과 똑같이 했다면 그것은 연기가 아니라 &#39;흉내&#39;이다. 진짜 배우는 캐릭터를 자기화 시켜 새로운 인물을 창조해 낼 줄 알아야 한다. </p>
<h4 id="진짜-배우란--자기가-쌓아온-이미지를-스스로-무너뜨릴줄-알아야-한다">진짜 배우란 , 자기가 쌓아온 이미지를 스스로 무너뜨릴줄 알아야 한다.</h4>
<p>배우는 다른사람의 인생을 살아보는 특권을 가진 사람들이다. 그런 고로 진정한 배우라면 어떤 역할도 다 소화해 낼 수 있어야 한다. </p>
<p>배우는 떄로 자신이 연기해야할 캐릭터와 자기 자신사이에 어떤 공통점도 발견하지 못할 때가 있다. 실제 삶에서 만났으면 상대도 하지 않았을 인물을 연기해야 할 때가 잇다는 것이다. </p>
<p>하지만 그 인물이 되기위해 필요한 것은 무조건 훔쳐라. 배우는 뭐든 훔쳐서 자기 것으로 만드는사람이다. </p>
<p>캐릭터를 만들려면 우선 단서를 긁어 모아야한다. 우선 작가나 감독에게 캐릭터에 대한 의견을 읽고 시나리오를 읽는게 좋다. 시나리오를 읽을 때는 시나리오 밖 사건까지 상상해 봐야한다. 가령 , 그 인물이 20대 이전에는 공부를 잘했을지 , 주변인과 관계는 어땠을지, 어떤 성장과정을 거쳤을지 상상해가며 캐릭터를 잡아야 한다. </p>
<p>성동일의 천지호 역할 처럼 본인이 맡은 캐릭터와 비슷한 이미지를 가진 지인에게 힌트를 얻을 수도 있고, 본인이 살아오면서 경험한 것을 통해 통찰력을 발휘할 수도 있다. 다른 영화 속에서 다른 배우가 만든 인물중에서도 훔칠 수도 있다. 물론 훔치는 것만으로 캐릭터를 창조할 수 없다. 그것들을 잘 조합하여 당신 스스로 캐릭터를 만들어야 한다. </p>
<h4 id="그외">그외..</h4>
<p>배우는 말랑말랑한 영혼을 소유하고 있어야 한다. 외부로부터 강요된 책임감과 부담감으로 인해 어깨가 무거워지면 자유로움은 사라지고 , 자유로움이 사라지면 그저 그런 연기밖에 못 보여 주게 된다. 그러면 배우로서의 생명도 끝난다. 다시말하지만 배우는 기본적으로 자기 삶에 책임감을 느껴야 한다. 그 마음속에는 자유로운 영혼이 마음껏 뛰어 놀 수 있는 사적인 공간이 있어야 한다. 연기를 삶처럼. 삶을 연기처럼 살라.!</p>
<p>배우는 무한한 책임감을 느끼고 살아야 한다. 배우는 대중을 무시하고 제멋대로 살면 안되는 특수한 직업이다. </p>
<p>당신이 진실하다면 언젠가 그 진실은 세상에 드러나게 되어 있다. 만약 잘못을 했다면 도망치지말고 정정당당하게 죗값을 치뤄야 한다. 늘 조심해서 행동해도 다른사람들에 의해 사건이 될 수도 있고 말도 안되는 황당한 루머에 휘둘릴 때도 있다. </p>
<p>네가 아무리 운전을 안해도 상대방이 와서 받으면 그것도 교통사고다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Dev log] 싱글톤 패턴, 서비스패턴 개선]]></title>
            <link>https://velog.io/@corepen_/Dev-log-%EC%8B%B1%EA%B8%80%ED%86%A4-%ED%8C%A8%ED%84%B4-%EC%84%9C%EB%B9%84%EC%8A%A4%ED%8C%A8%ED%84%B4-%EA%B0%9C%EC%84%A0</link>
            <guid>https://velog.io/@corepen_/Dev-log-%EC%8B%B1%EA%B8%80%ED%86%A4-%ED%8C%A8%ED%84%B4-%EC%84%9C%EB%B9%84%EC%8A%A4%ED%8C%A8%ED%84%B4-%EA%B0%9C%EC%84%A0</guid>
            <pubDate>Sat, 15 Apr 2023 15:01:56 GMT</pubDate>
            <description><![CDATA[<h2 id="개선-전-appts">개선 전 (app.ts)</h2>
<pre><code>import * as express from &quot;express&quot;;
import catsRouter from &quot;./cats/cats.routes&quot;

// const app = express();
const app: express.Express = express();

// const data: Array&lt;any&gt; = [1,2,3,4];

const port: number = 8000;


// 미들웨어 접근
app.use((req:express.Request,res:express.Response,next:express.NextFunction)=&gt;{
    console.log((req.rawHeaders[1]));
    console.log(&#39;this is middleware&#39;);
    next();
})

// json 미들웨어
app.use(express.json());

app.use(catsRouter);


// 404 middleware
app.use((req:express.Request,res:express.Response, next:express.NextFunction) =&gt; {
  console.log(&quot;this is error middleware&quot;);
  res.send({ error: &quot;404 not found error&quot; });
});


app.listen(port, () =&gt; {
  console.log(`Example app listening at http://localhost:${port}/`);
});</code></pre><h2 id="개선-후">개선 후</h2>
<pre><code>import * as express from &#39;express&#39;;
import catsRouter from &#39;./cats/cats.route&#39;;

class Server {
  public app: express.Application;

  constructor() {
    const app: express.Application = express();
    const port: number = 8000;
    this.app = app;
  }

  private setRoute() {
    this.app.use(catsRouter);
  }

  private setMiddleware() {
    //* logging middleware
    this.app.use((req, res, next) =&gt; {
      console.log(req.rawHeaders[1]);
      console.log(&#39;this is logging middleware&#39;);
      next();
    });

    //* json middleware
    this.app.use(express.json());

    this.setRoute();

    //* 404 middleware
    this.app.use((req, res, next) =&gt; {
      console.log(&#39;this is error middleware&#39;);
      res.send({ error: &#39;404 not found error&#39; });
    });
  }

  public listen() {
    this.setMiddleware();
    this.app.listen(port, () =&gt; {
      console.log(&#39;server is on...&#39;);
    });
  }
}

function init() {
  const server = new Server();
  server.listen();
}

init();</code></pre><h2 id="해설">해설</h2>
<p>기존에 내가 짜던 코드 느낌보다 더 확실히 깔끔하고 간결하다. <code>server 클래스 선언</code>을 통해 상태를 관리할수 있다는것.. 생각 조차 못했다. <code>app</code>을 단 한개 고유의 외부접근을 허용하는<code>public</code> 필드로 지정하고 <code>constructor</code>를 통해 해당 클래스의 인스턴스를 생성과 초기화. 그리고 미들웨어들을 외부에서 접근불가능한 <code>priviate</code>로 지정한뒤 하나의 함수를 통한 클래스 실행.. 기존에 따로 따로 동떨어져 있던것들을 하나의 클래스로 묶어버렸다. </p>
<p>말그대로 <code>싱글톤 패턴</code>화 되었다.</p>
<h2 id="개선-전-비즈니스-로직과-route-분리">개선 전 (비즈니스 로직과 route 분리)</h2>
<pre><code>import { Cat, CatType } from &quot;./cats.model&quot;;
import { Router } from &quot;express&quot;;

const router = Router();

//  READ 고양이 데이터 전체 조회

router.get(&quot;/cats&quot;, (req, res) =&gt; {
  try {
    const cats = Cat;

    // throw new Error(&quot;db connect error&quot;)

    res.status(200).send({
      success: true,
      data: {
        cats,
      },
    });
  } catch (error: any) {
    res.status(400).send({
      succes: false,
      error: error.message,
    });
  }
});

// 특정 고양이 데이터 조회
router.get(&quot;/cats/:id&quot;, (req, res) =&gt; {
  try {
    const params = req.params;
    console.log(params);
    const cat = Cat.find((cat) =&gt; {
      return cat.id === params.id;
    });

    res.status(200).send({
      success: true,
      data: {
        cat,
      },
    });
  } catch (error: any) {
    res.status(400).send({
      succes: false,
      error: error.message,
    });
  }
});

// Creat 새로운 하나의 고양이 api 추가
router.post(&quot;/cats&quot;, (req, res) =&gt; {
  try {
    const data = req.body;
    console.log(data);
    Cat.push(data); // create

    res.status(200).send({
      success: true,
      data: { data },
    });
  } catch (error: any) {
    res.status(400).send({
      success: false,
      error: error.message,
    });
  }
});

// Update =&gt; Put
router.put(&#39;/cats/:id&#39;,(req,res)=&gt;{
    try {
        const params = req.params;
        const body = req.body;
        let result ;
        Cat.forEach((cat)=&gt;{
            if(cat.id === params.id) {
                cat = body;
                result = cat
            }
        })

        res.status(200).send({
          success: true,
          data: {
            result,
          },
        });
    } catch (error: any) {
        res.status(400).send({
          succes: false,
          error: error.message,
        });
      }
})
// 부분적인 Update =&gt; Patch
router.patch(&quot;/cats/:id&quot;, (req, res) =&gt; {
  try {
    const params = req.params;
    const body = req.body;
    let result;
    Cat.forEach((cat) =&gt; {
      if (cat.id === params.id) {
        cat = {...cat, ...body}
        result = cat;
      }
    });

    res.status(200).send({
      success: true,
      data: {
        result,
      },
    });
  } catch (error: any) {
    res.status(400).send({
      succes: false,
      error: error.message,
    });
  }
});

// Delete 삭제 =&gt; Delete

router.delete(&quot;/cats/:id&quot;, (req, res) =&gt; {
  try {
    const params = req.params;
    const newCat =
    Cat.filter((cat) =&gt; 
        cat.id !== params.id
    );

    res.status(200).send({
      success: true,
      data : newCat,
    });
  } catch (error: any) {
    res.status(400).send({
      succes: false,
      error: error.message,
    });
  }
});

export default router; </code></pre><h2 id="개선-후-catservicets-catroutets">개선 후 (cat.service.ts, cat.route.ts)</h2>
<h3 id="catservicets">cat.service.ts</h3>
<pre><code>import { Request, Response } from &#39;express&#39;;
import { Cat, CatType } from &#39;./cats.model&#39;;

//* READ 고양이 전체 데이터 다 조회 -&gt; GET
export const readAllcat = (req: Request, res: Response) =&gt; {
  try {
    const cats = Cat;
    // throw new Error(&#39;db connect error&#39;);
    res.status(200).send({
      success: true,
      data: {
        cats,
      },
    });
  } catch (error) {
    res.status(400).send({
      success: false,
      error: error.message,
    });
  }
};

//* READ 특정 고양이 데이터 조회 -&gt; GET
export const readCat = (req: Request, res: Response) =&gt; {
  try {
    const params = req.params;
    console.log(params);
    const cat = Cat.find((cat) =&gt; {
      return cat.id === params.id;
    });
    res.status(200).send({
      success: true,
      data: {
        cat,
      },
    });
  } catch (error) {
    res.status(400).send({
      success: false,
      error: error.message,
    });
  }
};

//* CREATE 새로운 고양이 추가 api -&gt; POST
export const createCat = (req: Request, res: Response) =&gt; {
  try {
    const data = req.body;
    Cat.push(data); // create
    res.status(200).send({
      success: true,
      data: { data },
    });
  } catch (error) {
    res.status(400).send({
      success: false,
      error: error.message,
    });
  }
};

//* UPDATE 고양이 데이터 업데이트 -&gt; PUT
export const updateCat = (req: Request, res: Response) =&gt; {
  try {
    const params = req.params;
    const body = req.body;
    let result;
    Cat.forEach((cat) =&gt; {
      if (cat.id === params.id) {
        cat = body;
        result = cat;
      }
    });
    res.status(200).send({
      success: true,
      data: {
        cat: result,
      },
    });
  } catch (error) {
    res.status(400).send({
      success: false,
      error: error.message,
    });
  }
};

//* UPDATE 고양이 데이터 부분적으로 업데이트 -&gt; PATCH
export const updatePartialCat = (req: Request, res: Response) =&gt; {
  try {
    const params = req.params;
    const body = req.body;
    let result;
    Cat.forEach((cat) =&gt; {
      if (cat.id === params.id) {
        cat = { ...cat, ...body };
        result = cat;
      }
    });
    res.status(200).send({
      success: true,
      data: {
        cat: result,
      },
    });
  } catch (error) {
    res.status(400).send({
      success: false,
      error: error.message,
    });
  }
};

//* DELETE 고양이 데이터 삭제 -&gt; DELETE
export const deleteCat = (req: Request, res: Response) =&gt; {
  try {
    const params = req.params;
    const newCat = Cat.filter((cat) =&gt; cat.id !== params.id);
    res.status(200).send({
      success: true,
      data: newCat,
    });
  } catch (error) {
    res.status(400).send({
      success: false,
      error: error.message,
    });
  }
};</code></pre><h3 id="catroutests">cat.routes.ts</h3>
<pre><code>import { Router } from &#39;express&#39;;
import { NextFunction } from &#39;express-serve-static-core&#39;;
import {
  createCat,
  deleteCat,
  readAllcat,
  readCat,
  updateCat,
  updatePartialCat,
} from &#39;./cats.service&#39;;

const router = Router();

router.get(&#39;/cats&#39;, readAllcat);
router.get(&#39;/cats/:id&#39;, readCat);
router.post(&#39;/cats&#39;, createCat);
router.put(&#39;/cats/:id&#39;, updateCat);
router.patch(&#39;/cats/:id&#39;, updatePartialCat);
router.delete(&#39;/cats/:id&#39;, deleteCat);

export default router;</code></pre><p>비즈니스 로직과 라우트를 분리해 둠으로 써 보다 가독성이 좋아졌다. </p>
]]></description>
        </item>
    </channel>
</rss>