<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>wg_cat.log</title>
        <link>https://velog.io/</link>
        <description>늦깎이 애아빠 개발지망생</description>
        <lastBuildDate>Thu, 06 Feb 2025 02:01:33 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>wg_cat.log</title>
            <url>https://velog.velcdn.com/images/wg_cat/profile/ec8c9e10-0bd6-425b-abfc-1dc294c799f6/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. wg_cat.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/wg_cat" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[타입스크립트 관점에서 바라보는 Vue와 React]]></title>
            <link>https://velog.io/@wg_cat/%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8</link>
            <guid>https://velog.io/@wg_cat/%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8</guid>
            <pubDate>Thu, 06 Feb 2025 02:01:33 GMT</pubDate>
            <description><![CDATA[<p>타입스크립트는 마이크로소프트에서 2012년 10월에 발표되어 개발, 유지하고 있는 오픈소스 프로그래밍 언어이다.
자바스크립트의 라이브러리 이자 또다른 독자적인 언어이기도 하며 자바스크립트 문법 그대로 이용 가능하다.</p>
<p>타입스크립트는 엄격한 문법을 지원하는것이 특징인데 자바스크립트와 비교해보자.</p>
<p>자바스크립트는 동적 타입 언어(Dynamic Type Language)이다. 이게 무슨말이냐면 타입이 어긋나도 자기가 알아서 판단해서 타입을 바꿔서 실행시켜준다. 예를들면
<img src="https://velog.velcdn.com/images/wg_cat/post/6e40677d-0e57-45f3-942d-01d0ce7e1bae/image.png" alt="">
위의 계산을 console.log 해보면
<img src="https://velog.velcdn.com/images/wg_cat/post/608cb74d-87f8-40a5-8b5d-750f97f04fa8/image.png" alt=""></p>
<p>이렇게 자바스크립트가 지레짐작하여 타입을 바꿔서 연산해버린다.</p>
<p>이는 개발속도 면에서 생산성 확대라는 장점이 있겠지만 프로젝트의 규모가 커지고 유지보수 할 일이 생겨 남이 짠 자바스크립트를 수정할 일이 생기면 골치아파진다. 의도치 않는 버그들이 생겨나고 실행하기 전까지 타입 관련 에러를 찾기도 어렵다.</p>
<p>하지만 타입스크립트라면 어떨까?
타입스크립트는 변수와 데이터의 형식을 전부 명확히 지정하기 때문에 위와 같은 단점이 보완된다.
추가로 컴파일 단계에서 에러를 잡아준다. 이게 무슨뜻이냐면 자바스크립트는 코드를 실행해서 콘솔창에서 직접 에러를 확인해야 하지만 타입스크립트는 코드 편집기 안에서 미리 에러를 띄워줘 경고를 해준다.
에러메시지도 더 정확해진다.</p>
<p>비유를 하자면
동네에서 성인남성 두명이서 고성방가를 하며 싸우기 시작하는데
자바스크립트와 타입스크립트가 경찰에 신고를 한다.</p>
<blockquote>
<p>자바스크립트 : 이 동네가 시끄러운데요?
타입스크립트 : 지금 어느골목에서 성인남성 두명이 싸우려고해요. 일이 커질거같아요.</p>
</blockquote>
<p>라고 볼 수 있다.</p>
<p>정리하면
타입스크립트는 정적 타입 언어이며 개발자의 실수를 줄이고, 유지보수를 더 쉽게 만들어준다. 특히 규모가 큰 프로젝트나 협업이 필요한 환경에서 안정성이 더 높아진다.</p>
<p>타입스크립트를 지원하는 웹 프론트엔드 중 인기가 많은건 React와 Vue라고 생각한다.</p>
<p>React는 타입스크립트와 궁합이 좋다고 알려져 둘의 조합이 인기있다.
Vue는 2버전에서 타입스크립트를 일부분 지원했지만 23년 12월에 2버전의 지원이 종료되었다. 3버전에서 타입스크립트의 지원이 강화되어 사용되고 있지만 React만큼 강력하진 않다.</p>
<p>프로젝트의 규모가 커져 복잡도가 증가할 경우 React의 컴포넌트 타입을 지정해 복잡한 상태관리를 통해 타입스크립트가 진가를 발휘하기 때문이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Devfest 2024 Seoul 후기 (2024.12.14)]]></title>
            <link>https://velog.io/@wg_cat/Devfest-2024-Seoul-%ED%9B%84%EA%B8%B0-2024.12.14</link>
            <guid>https://velog.io/@wg_cat/Devfest-2024-Seoul-%ED%9B%84%EA%B8%B0-2024.12.14</guid>
            <pubDate>Sat, 04 Jan 2025 06:12:30 GMT</pubDate>
            <description><![CDATA[<p><a href="https://festa.io/events/6361">https://festa.io/events/6361</a></p>
<p>이번엔 삼성역이다. Devfest 2024 Seoul로 출발.</p>
<p><img src="https://velog.velcdn.com/images/wg_cat/post/895dd820-2bfe-41be-b935-04757520d489/image.png" alt=""></p>
<p>요즘 치킨모임때도 그렇고 AI에 관심이 부쩍 많아졌는데 이번 페스타는 내 갈망을 채워줄 수 있기를..</p>
<p><img src="https://velog.velcdn.com/images/wg_cat/post/5a2f850a-a1d4-4124-aa33-a3f6e2ba7d78/image.png" alt=""></p>
<p>제공해주신 점심메뉴</p>
<p><img src="https://velog.velcdn.com/images/wg_cat/post/67fbf553-a335-4b82-9a5e-a8f6fc0de225/image.png" alt=""></p>
<p>장소는 생각보다 좁았고 자리도 충분치 않아서 점심을 먹기가 애매했다.</p>
<p>여러가지 AI관련 발표가 있었다.
SAIF의 보안이슈
AutoRAG 오픈소스 성장과정
Gemini 소개 등등</p>
<p>AI의 특징, 위험성, 잘 다루는법 등의 발표가 오갔고 AI가 조금 더 친근해진 느낌이였다.
다른 발표들도 흥미있었지만 &#39;AutoRAG 오픈소스 성장과정&#39;을 이야기해보려 한다.</p>
<p>RAG란 LLM이 훈련되지 않은 정보에 대해서도 정확히 답변이 가능한 기술이다.
RAG기술이 도입되기 전에는 AI에게 질문을 해도 자세한 정보까지는 답변을 해주지 않았는데, 후에는 자세한 정보까지 답변이 가능해졌다. LLM이 알았으면 하는 문서를 RAG에 넣어주면 사용자의 질문에 따라 알맞은 문서를 RAG가 찾아 LLM에 제공한다.</p>
<p>이분들은 오픈소스를 제작했는데 최대한 빠르게 런칭하고 홍보와 버그수정을 뒤로 미루는 전략을 펼쳤다. 이 전의 기술도 런칭을 시도했다가 이것 저것 기능을 추가하다 보니 느린 런칭으로 다른 사람들의 기술 홍보에 밀려 실패를 했다고.</p>
<p>이를 보며 그간 프로젝트를 하면서 완벽하게 하려고 했던 부분이 생각났다.
실행만 되게끔 완성하고 디버그를 나중에 하는 전략을 썼다면 더 효율적인 프로젝트 개발이 되지 않았을까 생각이 되는 전략이였다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[C# 비동기 (async, await)]]></title>
            <link>https://velog.io/@wg_cat/C-%EB%B9%84%EB%8F%99%EA%B8%B0-async-await</link>
            <guid>https://velog.io/@wg_cat/C-%EB%B9%84%EB%8F%99%EA%B8%B0-async-await</guid>
            <pubDate>Sat, 04 Jan 2025 05:32:41 GMT</pubDate>
            <description><![CDATA[<h2 id="1-비동기-프로그래밍">1. 비동기 프로그래밍</h2>
<p>C#의 비동기 프로그래밍 지원은 고성능, 응답성이 중요한 애플리케이션 개발을 간소화하는 강력한 도구를 제공한다. 이를 가능하게 하는 주요 요소는 <code>async</code>와 <code>await</code> 키워드를 중심으로 한 Task 기반 비동기 프로그래밍 모델(TAP, Task-based Asynchronous Pattern)이다. </p>
<hr>
<h2 id="2-기본원리-정의">2. 기본원리 정의</h2>
<h3 id="1-동기synchronous">1) 동기(Synchronous)</h3>
<p>동기(Synchronous) 방식의 코드는 코드가 실행되고 다음코드 실행되고 그다음코드 실행되고의 방식이다. 메서드를 호출한 이후 그 메서드가 완료될 때까지 코드 실행이 차단된다.
작업은 순서대로 실행되어 하나의 작업이 끝날 때까지 다른 작업을 수행하지 않고 작업이 완료될 때까지 기다리게 되므로 프로그램이 멈추게된다.
네트워크 요청, 데이터베이스 조회 등 시간이 오래걸리는 작업이라면 비효율적이 된다.</p>
<blockquote>
</blockquote>
<p>길을 걷다가 핸드폰을 보기 위해 제자리에 서서 핸드폰을 확인하고 다시 걷는다.</p>
<h3 id="2-비동기asynchronous">2) 비동기(Asynchronous)</h3>
<p>비동기(Asynchronous) 프로그래밍은 코드1, 코드2, 코드3의 순서로 작성된 코드들이 서로 끝나는 것을 기다리지 않고 실행하난 방식이다. 코드들은 먼저 완료가 된 순서대로 결과를 반환하며 메서드를 호출한 이후 해당 메서드가 완료되기를 기다리지 않고 다름 코드를 실행한다.</p>
<p>비동기 메서드는 백그라운드 스레드처럼 긴 시간이 소요되는 작업에서 수행되므로, 메인 스레드(ui및 이벤트처리 등의 프로그램의 중요한 처리)는 다른 작업을 수행할 수 있다.</p>
<blockquote>
</blockquote>
<p>핸드폰을 보며 길을 걸어갈 수 있다.</p>
<hr>
<h2 id="3-윈폼으로-구현해보기">3. 윈폼으로 구현해보기</h2>
<h3 id="1-동기synchronous-1">1) 동기(Synchronous)</h3>
<h4 id="①-form">① Form</h4>
<p><img src="https://velog.velcdn.com/images/wg_cat/post/8cb695f0-e0a8-49de-b418-46dc45d4d158/image.png" alt=""></p>
<hr>
<h4 id="②-코드">② 코드</h4>
<pre><code class="language-cs">namespace asynchronous
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void RunAnything(Label lbl)
        {
            for (int i = 0; i &lt; 50; i++)
            {
                Thread.Sleep(50);
                lbl.Text = i.ToString();
                lbl.Refresh();
            }
        }

        private void btnWalking_Click(object sender, EventArgs e)
        {
            RunAnything(lblWalking);
        }

        private void btnPhone_Click(object sender, EventArgs e)
        {
            RunAnything(lblPhone);
        }

        private void btnTalking_Click(object sender, EventArgs e)
        {
            RunAnything(lblTalking);
        }
    }
}</code></pre>
<hr>
<h4 id="③-구현화면">③ 구현화면</h4>
<p><img src="https://velog.velcdn.com/images/wg_cat/post/5096a84b-1201-40c1-91fa-4532d376c901/image.png" alt=""></p>
<p>버튼을 누르면 해당버튼의 우측에 있는 lable이 카운트된다.</p>
<p><img src="https://velog.velcdn.com/images/wg_cat/post/957cc769-6832-4f64-8949-a666dde66caf/image.png" alt=""></p>
<p>걷기버튼을 누르면 lable1이 카운트된다.
걷기버튼이 동작하고 있는 도중에 휴대폰보기 버튼을 눌러도 동작하지 않는다.</p>
<p><img src="https://velog.velcdn.com/images/wg_cat/post/904e3e31-f84a-4181-b426-abc17c39428a/image.png" alt=""></p>
<p>걷기버튼이 끝난 후 작동한다. 이것이 동기이다.</p>
<h3 id="2-비동기asynchronous-1">2) 비동기(Asynchronous)</h3>
<h4 id="①-form-1">① Form</h4>
<hr>
<h4 id="②-코드-1">② 코드</h4>
<pre><code class="language-cs">namespace asynchronous
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        // 비동기
        private async void RunAnythingAsync(Label lbl)
        {
            for (int i = 0; i &lt; 50; i++)
            {
                await Task.Delay(50);
                lbl.Text = i.ToString();
                lbl.Refresh();
            }
        }

        private void btnWalking_Click(object sender, EventArgs e)
        {
            RunAnythingAsync(lblWalking);
        }

        private void btnPhone_Click(object sender, EventArgs e)
        {
            RunAnythingAsync(lblPhone);
        }

        private void btnTalking_Click(object sender, EventArgs e)
        {
            RunAnythingAsync(lblTalking);
        }
    }
}
</code></pre>
<hr>
<h4 id="③-구현화면-1">③ 구현화면</h4>
<p><img src="https://velog.velcdn.com/images/wg_cat/post/e58e2ee2-a3ce-4203-837a-ca4c2be6b3b1/image.png" alt="">
걷기가 50 가기도 전에 휴대폰보기를 누르면 작동이 된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[C#과 OOP]]></title>
            <link>https://velog.io/@wg_cat/C%EA%B3%BC-OOP</link>
            <guid>https://velog.io/@wg_cat/C%EA%B3%BC-OOP</guid>
            <pubDate>Fri, 03 Jan 2025 07:52:13 GMT</pubDate>
            <description><![CDATA[<p>C#을 공부하며 객체지향프로그래밍에서</p>
<ul>
<li>캡슐화</li>
<li>상속</li>
<li>다형성</li>
</ul>
<p>을 구현해보겠다.</p>
<hr>
<h3 id="1-캡슐화-encapsulation">1. 캡슐화 (Encapsulation)</h3>
<p>캡슐화의 주된 목적은 &quot;데이터의 은닉&quot;이다. 민감한 데이터를 <code>private</code>로 감추어서 <code>public</code>의 함수로만 접근/변경 가능하다.
따라서 이러한 <code>private</code>변수에 <code>read-only(읽기전용)</code> 또는 <code>write-only(변경전용)</code>한 선택접 접근을 제어할 수 있게된다.</p>
<pre><code class="language-cs">using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace C_study
{
    internal class Car
    {
        // 캡슐화 
        public string handle = &quot;ABC&quot;;
        private string hidden = &quot;HIDE&quot;;
        protected string a = &quot;QQQ&quot;;

        // Read Only
        public string getCar1()
        {
            return hidden;
        }

        // Write Only
        public void setCar1(string str)
        {
            hidden = str;
        }

        public void getCar2()
        {
            Console.WriteLine(handle);
        }


    }
}

</code></pre>
<pre><code class="language-cs">using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace C_study
{
    internal class Program
    {
        static void Main(string[] args)
        {
            // 캡슐화
            // 생성자 car1 선언
            Car car1 = new Car();
            // hidden string 변수에 &quot;HIDE Write Only&quot; 저장
            car1.setCar1(&quot;HIDE Write Only&quot;);
            // getCar2()함수를 실행해서 handle 출력
            car1.getCar2();
            // handle값 출력
            Console.WriteLine(car1.handle);
            // getCar1()함수를 실행해서 반환값 hidden 출력
            Console.WriteLine(car1.getCar1());    


        }
    }
}</code></pre>
<p>출력결과</p>
<pre><code>ABC
ABC
HIDE Write Only</code></pre><hr>
<h3 id="2-상속-inheritance">2. 상속 (Inheritance)</h3>
<p>부모클래스에 함수나 변수를 선언하고 아이클래스에는 아무것도 없어도 상속만 해주면 다른클래스에서 아이클래스의 생성자를 만든 후 가져다 쓸 수 있다.</p>
<pre><code class="language-cs">using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace C_study
{
    internal class Suv : Car
    {
        // 상속
        public void getA()
        {
            Console.WriteLine(a);
        }
    }
}
</code></pre>
<pre><code class="language-cs">using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace C_study
{
    internal class Program
    {
        static void Main(string[] args)
        {
            // 상속
            // 생성자 suv 선언
            Suv suv = new Suv();
            // handle 변수에 &quot;ZXC&quot; 저장
            suv.handle = &quot;ZXC&quot;;
            // getCar2()함수를 실행해서 handle의 값을 가져와 출력
            suv.getCar2();
            // handle의 값을 가져와 출력
            Console.WriteLine(suv.handle);
            // 접근제한자 protected의 변수를 가져와 출력
            suv.getA();
        }
    }
}
</code></pre>
<p>출력결과</p>
<pre><code>ZXC
ZXC
QQQ</code></pre><hr>
<h3 id="3-다형성-polymorphism">3. 다형성 (Polymorphism)</h3>
<p>여러가지 자료형을 가질 수 있는것. 부모클래스에서 <code>virtual</code>을 입력하여 아이클래스에서 함수의 재정의가 가능해진다. 객체만 변경하면 작동될 수 있다.</p>
<pre><code class="language-cs">using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace C_study
{
    internal  class CarType
    {
        public virtual void carType()
        {
            // virtual : 오버라이딩
            Console.WriteLine(&quot;모든차&quot;);
        }
    }
}
</code></pre>
<pre><code class="language-cs">using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace C_study
{
    internal class Embulance : CarType
    {
        public void carType()
        {
            Console.WriteLine(&quot;구급차&quot;);
        }
    }
}
</code></pre>
<pre><code class="language-cs">using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace C_study
{
    internal class FireCar : CarType
    {
        public void carType()
        {
            Console.WriteLine(&quot;소방차&quot;);
        }
    }
}
</code></pre>
<pre><code class="language-cs">using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace C_study
{
    internal class PoliceCar : CarType
    {
        public void carType()
        {
            Console.WriteLine(&quot;경찰차&quot;);
        }
    }
}
</code></pre>
<pre><code class="language-cs">using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace C_study
{
    internal class Program
    {
        static void Main(string[] args)
        {
            // 다형성
            CarType carType = new CarType();
            Embulance embulance = new Embulance();
            PoliceCar policeCar = new PoliceCar();
            FireCar fireCar = new FireCar();
            carType.carType();
            embulance.carType();
            policeCar.carType();
            fireCar.carType();
        }
    }
}
</code></pre>
<p>출력결과</p>
<pre><code>모든차
구급차
경찰차
소방차</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[docker 데스크탑에서 MySQL DB이미지 구동하기]]></title>
            <link>https://velog.io/@wg_cat/docker-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EA%B5%AC%EB%8F%99%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@wg_cat/docker-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EA%B5%AC%EB%8F%99%ED%95%98%EA%B8%B0</guid>
            <pubDate>Fri, 03 Jan 2025 07:00:38 GMT</pubDate>
            <description><![CDATA[<p>docker에서 이미지를 구동하여 컨테이너를 만들거다.
그 후 DBeaver와 연결까지 수행할거다.
DB는 MySQL</p>
<p><img src="https://velog.velcdn.com/images/wg_cat/post/ae26c95d-d2a3-4046-a027-fcfd077890a2/image.png" alt=""></p>
<p>먼저 제목표시줄에 있는 Search에서 MySQL 이미지를 Pull받는다.</p>
<p>Actions의 재생버튼을 클릭하게되면 컨테이너 정보를 입력하는 Run a new container창이 뜬다.</p>
<hr>
<h3 id="1-run-a-new-container-정보-입력">1. Run a new container 정보 입력</h3>
<p><img src="https://velog.velcdn.com/images/wg_cat/post/292996a6-89b4-4e2b-9425-01bc526c2121/image.png" alt=""></p>
<h4 id="1-container-name">1) Container name</h4>
<ul>
<li>컨테이너 이름. docker에서 컨테이너들을 이름으로 구별하기 위해 짓는다.<h4 id="2-ports">2) Ports</h4>
</li>
<li>Host port : 기본 3306, 33060<h4 id="3-volumes">3) Volumes</h4>
컨테이너를 삭제하게 되면 작업했던 데이터가 모두 삭제되어 버린다. 컨테이너는 삭제되어도 데이터는 유지하고 싶은 경우에 설정한다. 여기선 안쓸것이다.<ul>
<li>Host Path : 점 세개 눌러서 외부 볼륨 경로를 입력</li>
<li>Container Path : 컨테이너 경로 아래에 대상 경로를 입력<h4 id="4-environment-variables">4) Environment variables</h4>
환경변수 설정. DB명과 패스워드를 입력할것이다. Variable에 환경변수명, Value에 값을 적는다. 여기에서는 DB명을 hohobook으로 하겠다.</li>
<li>Variable</li>
<li>MYSQL_DATABASE</li>
<li>MYSQL_ROOT_PASSWORD</li>
</ul>
</li>
</ul>
<hr>
<h3 id="2-컨테이너-실행">2. 컨테이너 실행</h3>
<p><img src="https://velog.velcdn.com/images/wg_cat/post/e2b41015-b57f-4f43-93dc-d66f2aee7891/image.png" alt=""></p>
<p>왼쪽의 컨테이너 탭을 누르고 컨테이너가 생성되었는지 확인한 후 실행시킨다.</p>
<hr>
<h3 id="2-dbeaver-연결">2. DBeaver 연결</h3>
<p><img src="https://velog.velcdn.com/images/wg_cat/post/0a358a82-96fe-407d-8642-239b3d628791/image.png" alt=""></p>
<p>새 데이터베이스 연결을 누르면</p>
<p><img src="https://velog.velcdn.com/images/wg_cat/post/fcc97911-186d-4e78-9823-f86fc48d41e5/image.png" alt=""></p>
<p>DB종류가 뜨고 MySQL을 클릭</p>
<p><img src="https://velog.velcdn.com/images/wg_cat/post/a109e3fb-4849-4689-96be-acf6bf16c9d5/image.png" alt=""></p>
<h4 id="1-server---database">1) Server - Database</h4>
<p>컨테이너 설정때 지었던 DB명을 입력</p>
<h4 id="2-authentication---password">2) Authentication - Password</h4>
<p>컨테이너 설정때 지었던 패스워드 입력</p>
<h4 id="3-driver-properties">3) Driver properties</h4>
<p><img src="https://velog.velcdn.com/images/wg_cat/post/b417ecfc-c8f9-4c47-a64c-417b48b31906/image.png" alt=""></p>
<p>요 값을 True로 변경
후 Finish</p>
<p><img src="https://velog.velcdn.com/images/wg_cat/post/31dcfdab-97b1-4f4c-b2c6-949567c790fa/image.png" alt="">
연결됐다</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[스프링 프로젝트의 디렉토리 구조]]></title>
            <link>https://velog.io/@wg_cat/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%9D%98-%EB%94%94%EB%A0%89%ED%86%A0%EB%A6%AC-%EA%B5%AC%EC%A1%B0</link>
            <guid>https://velog.io/@wg_cat/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%9D%98-%EB%94%94%EB%A0%89%ED%86%A0%EB%A6%AC-%EA%B5%AC%EC%A1%B0</guid>
            <pubDate>Sat, 28 Dec 2024 05:47:42 GMT</pubDate>
            <description><![CDATA[<p>개발학원에서의 2차 팀 프로젝트를 spring으로 개발을 했었다.
spring 복습도 할 겸, 오늘은 spring으로 구성된 프로젝트의 디렉토리 구조를 하나하나 살펴보겠다. 빌드 툴은 메이븐을 사용했다.</p>
<hr>
<p><img src="https://velog.velcdn.com/images/wg_cat/post/df238ce6-e5c3-4c34-8424-e913e11556f6/image.png" alt=""></p>
<blockquote>
</blockquote>
<ul>
<li>Develop OS : Windows10</li>
<li>WEB/WAS Server : Tomcat v9.0</li>
<li>Language : Java 11</li>
<li>Framwork : Spring 3.1.1 Release</li>
<li>Build Tool : Maven 4.0.0</li>
</ul>
<hr>
<p><img src="https://velog.velcdn.com/images/wg_cat/post/0c05cd17-3096-4659-a142-d580234ea3fb/image.png" alt=""></p>
<h3 id="1-srcmainjava">1. src/main/java</h3>
<p>Java 파일이 모여있는 곳.</p>
<h4 id="userservice">user/service</h4>
<ul>
<li><p><code>impl/UserDAO.java</code>
: DAO(Data Access Object)는 실제 데이터베이스와의 상호작용을 담당하고, 이 서비스 클래스는 데이터를 처리하는 로직을 포함한다.
데이터 접근 개체를 생성하여 연결하여 처리되는 부분을 분리시켜서 데이터소스에 직접적으로 연결되지 않고 거쳐가는 역할을 하는 객체를 생성하여 캡슐화를 했다.
UserServiceImpl 클래스에서 호출된다.</p>
</li>
<li><p><code>UserDTO.java</code>
: DTO(Data Transfer Object)는 계층 간 데이터 전송을 위해 모델을 정의하는 객체이다.</p>
</li>
<li><p><code>impl/UserServiceImpl.java</code>, <code>service/UserService.java</code>
: Service를 만들 때 UserService로 서비스를 인터페이스로 설계하고, UserServiceImpl로 구현체인 클래스를 생성해서 사용하는 방식으로 설계했다.
UserService 인터페이스를 구현한 UserServiceImpl 클래스라고 볼 수 있다.</p>
</li>
</ul>
<h4 id="userweb">user/web</h4>
<ul>
<li><code>UserController.java</code>
사용자 관련 웹 페이지에서 발생하는 요청들을 처리하고, 비즈니스 로직을 UserService를 통해 실행하며, 뷰 페이지로 적절한 데이터를 전달한다.</li>
</ul>
<hr>
<p><img src="https://velog.velcdn.com/images/wg_cat/post/93c18144-2e5a-4e5b-92f6-90c4d4cf4586/image.png" alt=""></p>
<h3 id="2-srcmainresources">2. src/main/resources</h3>
<p>자바 클래스에서 사용하는 리소스를 보관하는 곳이다. DB 연결을 위한 자원, 의존성 주입(DI)을 위한 xml 파일 등 자바 코드 외 모든 자원을 이곳에 넣어준다.</p>
<ul>
<li><p><code>log4j.xml</code>
: 로깅 설정을 정의하는 구성 파일이다.</p>
</li>
<li><p><code>mybatis-config.xml</code>
: MyBatis 설정 파일이다.</p>
</li>
</ul>
<h4 id="mappers">mappers</h4>
<ul>
<li><code>User_Mapper.xml</code>
: MyBatis 프레임워크에서 사용되는 매퍼 파일로, SQL 쿼리와 Java 객체 간의 매핑을 정의한다.
요청값과 반환값을 정의하고, 쿼리를 담당한다.</li>
</ul>
<hr>
<p><img src="https://velog.velcdn.com/images/wg_cat/post/d826712f-371f-4ab1-862c-a17d6d55021e/image.png" alt=""></p>
<h3 id="3-srctest">3. src/test</h3>
<p>: java, resources와 같은 역할이지만 테스트를 위한 폴더이다. 현재 프로젝트에서는 사용하지 않았다.</p>
<hr>
<p><img src="https://velog.velcdn.com/images/wg_cat/post/5f26279a-246a-4ff1-aaae-5065d1461bc1/image.png" alt=""></p>
<h3 id="4-src">4. src</h3>
<p>: Web에 관련된 자원이 담겨있는 루트 폴더이다. main폴더의 하위 폴더에 웹과 관련된 모든 자원들이 분류되어있다.
test폴더는 테스트를 위한 폴더이다. 이 역시 사용하지 않았다.</p>
<ul>
<li><p><code>main/webapp/resources</code>
: 웹에 필요한 다양한 자원들을 보관하고, 사용자가 직접 접근할 수 있는 공간이다.
js, css, img 파일 등이 보관되어 있다.</p>
</li>
<li><p><code>main/webapp/WEB-INF/spring</code>
: 스프링 환경설정 파일이 보관되는 곳이다.</p>
</li>
<li><p><code>main/webapp/WEB-INF/views</code>
: jsp, HTML 파일이 보관되는 곳이다. 이 폴더가 루트(/)의 기준점이며, 사용자가 입력하고 컨트롤러가 받아주는 url이 이 폴더의 구조를 따라가게 된다.</p>
</li>
</ul>
<hr>
<h3 id="5-pomxml">5. pom.xml</h3>
<p>: Maven의 POM(Project Object Model)파일이며 Java 프로젝트의 빌드와 의존성 관리를 정의하는 파일이다.
사용하고싶은 라이브러리를 의존성 관리에 입력하면 자동으로 다운로드하여 개발 가능하다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[React, Node.js 웹사이트 개발기_5. 후기]]></title>
            <link>https://velog.io/@wg_cat/React-Node.js-%EC%9B%B9%EC%82%AC%EC%9D%B4%ED%8A%B8-%EA%B0%9C%EB%B0%9C%EA%B8%B05.-%ED%9B%84%EA%B8%B0</link>
            <guid>https://velog.io/@wg_cat/React-Node.js-%EC%9B%B9%EC%82%AC%EC%9D%B4%ED%8A%B8-%EA%B0%9C%EB%B0%9C%EA%B8%B05.-%ED%9B%84%EA%B8%B0</guid>
            <pubDate>Mon, 23 Dec 2024 16:10:34 GMT</pubDate>
            <description><![CDATA[<h2 id="1-웹사이트-개발-후기">1. 웹사이트 개발 후기</h2>
<p>이번 개인 프로젝트에서는 React, Node.js, MongoDB를 사용하여 기본적인 기능을 갖춘 블로그 애플리케이션을 개발했다. 처음에는 간단한 게시판 정도로 시작할 계획이었지만, 점점 사용자 인증, 회원 관리 등 기능을 추가하며 프로젝트를 확장하게 되었다.
나만의 커스텀 블로그를 만들겠어! 라고 다짐하며 만들기 시작했지만 생각보다 쉽지 않았고 결국 현존하는 블로그들을 존경하게 되었다. 하지만 복잡한 구조는 아니라 생각되므로 시간이 좀 더 많이 주어진다면 완성할 수 있을것 같다.</p>
<h2 id="2-프로젝트-시작과-기술-선택">2. 프로젝트 시작과 기술 선택</h2>
<p>블로그를 만들기로 결심하고 처음에는 어떤 기술 스택을 사용할지 고민했고, 결국 평소에 하고싶었던 기술인 React와 Node.js, MongoDB를 사용했다.
React는 컴포넌트 기반 구조와 상태 관리 기능이 직관적이고, Node.js는 express를 이용한 빠른 개발을 지원 가능하다고 공부했다. NoSQL 데이터베이스도 유연하게 데이터를 저장하고 처리할 수 있다고 해서 이들로 정했다.</p>
<h2 id="3-문제와-해결">3. 문제와 해결</h2>
<p>특히 어려웠던 점이 글수정이었다.<code>$.cookie(&quot;login_id&quot;)</code>로, 이는 사용자가 로그인한 후 서버에서 받은 로그인 ID를 쿠키에 저장하고 이를 사용하여 서버와 요청을 보낼 때 사용자를 인증하는 용도로 사용되었다.
처음에 게시글의 아이디값을 제대로 가져오지 못해 글 수정을 해야 하는데 사용자가 인증되지 않아 작동이 되지 않았다. 결국 jquery를 추가했고 씨름끝에 해결했다.</p>
<h2 id="4-배운-점과-성취">4. 배운 점과 성취</h2>
<p>전체적인 웹 애플리케이션 아키텍처에 대해 더 잘 이해하게 되었다.
클라이언트는 사용자 인터페이스를 제공하고, 서버에 요청을 보내며, 서버로부터 받은 응답을 화면에 표시한다.
서버는 데이터베이스와의 상호작용을 담당하며, 클라이언트의 요청에 따라 회원과 게시물 관련 처리를 수행한다.
클라이언트와 서버 간의 통신을 설계하고, 상태 관리와 데이터 처리의 중요성을 깨달아 프론트엔드와 백엔드 간의 상호작용과 데이터베이스 관리에 대한 이해를 쌓았다.
앞으로 더 많은 프로젝트를 통해 경험을 쌓고, 개선할 부분을 찾아 더욱 완성도 높은 웹 애플리케이션을 만들고 싶다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[React, Node.js 웹사이트 개발기_4. 데이터베이스]]></title>
            <link>https://velog.io/@wg_cat/%EC%9B%B9%EC%82%AC%EC%9D%B4%ED%8A%B8-%EA%B0%9C%EB%B0%9C%EA%B8%B04.-%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4</link>
            <guid>https://velog.io/@wg_cat/%EC%9B%B9%EC%82%AC%EC%9D%B4%ED%8A%B8-%EA%B0%9C%EB%B0%9C%EA%B8%B04.-%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4</guid>
            <pubDate>Mon, 23 Dec 2024 06:47:58 GMT</pubDate>
            <description><![CDATA[<h2 id="데이터베이스">데이터베이스</h2>
<p>개인프로젝트에서 데이터베이스 관련 내용을 정리했다.</p>
<h3 id="1-데이터베이스">1. 데이터베이스</h3>
<h4 id="1-mongodb">1) MongoDB</h4>
<p>MongoDB는 NoSQL 데이터베이스로 유연한 스키마와 수평 확장성이 특징이다.
MongoDB는 데이터를 테이블이 아닌 문서 형태로 저장하는데,
유연한 스키마라 함은 각 문서는 다른 문서와 필드 구조가 달라도 상관없다. 때문에 필요한 데이터를 자유롭게 수정 및 추가할 수 있다.
또한, 샤딩을 지원하여 데이터베이스를 여러 서버에 분산하여 저장할 수 있다. 이러한 수평 확장성으로 데이터가 여러 서버에 분산되기 때문에 과부하에 대응하기 좋다.</p>
<h4 id="2-mongoose">2) Mongoose</h4>
<p>Mongoose는 MongoDB를 위한 Object Data Modeling (ODM) 라이브러리로, MongoDB의 데이터베이스 작업을 더 쉽게 하고, 스키마 기반의 모델링을 제공한다.
Mongoose를 사용한 이유는 복잡한 쿼리 작업을 간단한 메서드로 작성할 수 있게 해준다고 공부했기에 사용했다.
하지만 현 프로젝트는 복잡한 쿼리가 없기 때문에 안써도 무방했을 것 같다.</p>
<h3 id="2-문서-설계">2. 문서 설계</h3>
<p>초반에 설계했던 테이블을 공부한 MongoDB에 맞게 문서로 재구성했다.
<code>_id</code>는 모든 문서에 대해 자동으로 고유한 식별자를 생성하는데 이것이 그것이다.
테이블에서의 <code>기본 키</code>라고 보면 되겠다.</p>
<blockquote>
</blockquote>
<ol>
<li>User테이블
_id
email
name
password
salt
createdAt
loginCnt
lockYn<br></li>
<li>Board테이블
_id
writer
title
content
imgPath
createdAt</li>
</ol>
<p>비밀번호 암호화 관련 필드인 salt, 로그인 실패 횟수를 카운팅하여 계정을 잠그는 역할을 하는 필드인 loginCnt, lockYn는 아직 미구현단계이다.</p>
<h3 id="2-데이터-관계-정의">2. 데이터 관계 정의</h3>
<pre><code class="language-js">const mongoose = require(&quot;mongoose&quot;);

const { Schema } = mongoose;
const userSchema = new Schema({
  email: {
    type: String,
    required: true,
    unique: true
  },
  name: {
    type: String,
    required: true
  },
  password: {
    type: String,
    required: true
  },
  salt: {
    type: String,
    required: true
  },
  createdAt: {
    type: Date,
    default: Date.now
  },
  loginCnt: {
    type: Number,
    default: 0
  },
  lockYn: {
    type: Boolean,
    default: false
  }
});

module.exports = mongoose.model(&quot;User&quot;, userSchema);</code></pre>
<p>데이터 관계를 정의하고</p>
<pre><code class="language-js">const express = require(&quot;express&quot;);
const router = express.Router();
const User = require(&quot;../schema/user&quot;);</code></pre>
<pre><code class="language-js">router.post(&quot;/update&quot;, async (req, res) =&gt; {
  try {
    await User.update({
      _id: req.body._id,
      name: req.body.name
    });
    res.json({ message: true });
  } catch (err) {
    console.log(err);
    res.json({ message: false });
  }
});</code></pre>
<p>와 같은 메서드를 사용하여 조회가 가능하다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[React, Node.js 웹사이트 개발기_3. 클라이언트]]></title>
            <link>https://velog.io/@wg_cat/%EC%9B%B9%EC%82%AC%EC%9D%B4%ED%8A%B8-%EA%B0%9C%EB%B0%9C%EA%B8%B03.-%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8</link>
            <guid>https://velog.io/@wg_cat/%EC%9B%B9%EC%82%AC%EC%9D%B4%ED%8A%B8-%EA%B0%9C%EB%B0%9C%EA%B8%B03.-%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8</guid>
            <pubDate>Mon, 23 Dec 2024 06:24:48 GMT</pubDate>
            <description><![CDATA[<h2 id="클라이언트">클라이언트</h2>
<p>개인 프로젝트에서 클라이언트에 사용된 패키지들을 정리했다.</p>
<h3 id="1-react">1. React</h3>
<p>: React는 UI를 구축하기 위해 Facebook에서 개발한 JavaScript 라이브러리이다. UI를 독립적인 컴포넌트 기반으로 설계하여 효율적인 방식으로 웹 애플리케이션을 구출할 수 있다.
이번 개인프로젝트에서는 컴포넌트 기반으로 설계를 구현하고 싶어서 사용했다.</p>
<pre><code class="language-js">import React, { useState, useEffect } from &quot;react&quot;;</code></pre>
<hr>
<h3 id="2-react-bootstrap">2. react-bootstrap</h3>
<p>: Bootstrap을 React 컴포넌트로 재구현한 라이브러리이다. HTML/CSS 요소를 React 컴포넌트로 제공하여 재사용 가능한 코드를 작성할 수 있고 Bootstrap의 디자인을 그대로 사용 가능하다. 원하는 디자인의 컴포넌트만 선택적으로 가져와 더 효율적이고 직관적인 방식으로 UI를 구현할 수 있다.</p>
<h4 id="1-설치-및-import">1) 설치 및 import</h4>
<pre><code>npm install react-bootstrap</code></pre><pre><code class="language-js">import { Navbar, Button, Image } from &quot;react-bootstrap&quot;;</code></pre>
<h4 id="2-사용-사례">2) 사용 사례</h4>
<pre><code class="language-js">const buttonStyle = {
    margin: &quot;0px 5px 0px 10px&quot;,
    display: buttonDisplay,
};
return(
    &lt;div&gt;
      &lt;Navbar&gt;
          &lt;NavLink to=&quot;/&quot;&gt;
            &lt;Button style={buttonStyle} variant=&quot;primary&quot;&gt;
              글목록
            &lt;/Button&gt;
          &lt;/NavLink&gt;
      &lt;/Navbar&gt;
    &lt;/div&gt;
);</code></pre>
<hr>
<h3 id="3-react-router-dom">3. react-router-dom</h3>
<p>: React 애플리케이션에서 라우팅을 구현하기 위해 사용되는 라이브러리이다. 브라우저의 URL을 기반으로 페이지 전환을 관리한다.</p>
<h4 id="1-설치-및-import-1">1) 설치 및 import</h4>
<pre><code>npm install react-router-dom</code></pre><pre><code class="language-js">import { NavLink } from &quot;react-router-dom&quot;;</code></pre>
<h4 id="2-사용-사례-1">2) 사용 사례</h4>
<pre><code class="language-js">&lt;NavLink to=&quot;/board/detail&quot; state={{ _id }}&gt;
    {createdAt.substring(0, 10)}
&lt;/NavLink&gt;</code></pre>
<hr>
<h3 id="4-react-domclient">4. react-dom/client</h3>
<p>: React 애플리케이션을 실제 DOM에 렌더링하는 데 사용되는 라이브러리이다.</p>
<h4 id="1-설치-및-import-2">1) 설치 및 import</h4>
<pre><code>npm install react-dom/client</code></pre><pre><code class="language-js">import ReactDOM from &#39;react-dom/client&#39;;</code></pre>
<h4 id="2-사용-사례-2">2) 사용 사례</h4>
<pre><code class="language-js">const root = ReactDOM.createRoot(document.getElementById(&quot;container&quot;));

root.render(
  &lt;BrowserRouter&gt;
    &lt;Header /&gt;
    &lt;Body /&gt;
    &lt;Footer /&gt;
  &lt;/BrowserRouter&gt;
);</code></pre>
<hr>
<h3 id="5-jquery">5. jquery</h3>
<p>: Javascript 라이브러리이며 DOM 조작과 Ajax 요청을 간소화하는 라이브러리이다.
최신기술에는 잘 안쓰이지만 나는 $.cookie(&quot;login_id&quot;)를 사용하여 쿠키에서 login_id를 가져오는 데 사용했다.</p>
<h4 id="1-설치-및-import-3">1) 설치 및 import</h4>
<pre><code>npm install jquery</code></pre><pre><code class="language-js">import $ from &quot;jquery&quot;;</code></pre>
<h4 id="2-사용-사례-3">2) 사용 사례</h4>
<pre><code class="language-js">_id: $.cookie(&quot;login_id&quot;)
</code></pre>
<hr>
<h3 id="6-axios">6. axios</h3>
<p>: Promise 기반의 HTTP 클라이언트 라이브러리로, 브라우저와 Node.js에서 HTTP 요청을 처리할 수 있다. 주로 백엔드 API 서버와의 통신을 위해 사용된다.
나는 axios.post()를 사용하여 <code>http://localhost:8080/~~~/~~~</code> 엔드포인트에 데이터를 전송했다. 또한 withCredentials를 통해 서버와의 쿠키, 세션정보를 자동으로 처리했다.</p>
<h4 id="1-설치-및-import-4">1) 설치 및 import</h4>
<pre><code>npm install axios</code></pre><pre><code class="language-js">import axios from &quot;axios&quot;;</code></pre>
<h4 id="2-사용-사례-4">2) 사용 사례</h4>
<pre><code class="language-js">axios
  .post(&quot;http://localhost:8080/board/write&quot;, send_param)
  .then((returnData) =&gt; {
    console.log(&quot;Server Response:&quot;, returnData.data);
      if (returnData.data.message) {
          toast.success(returnData.data.message);
          window.location.href = &quot;/&quot;; // 글쓰기 후 목록으로 이동
      } else {
          toast.error(&quot;글쓰기 실패&quot;);
      }
  })
  .catch((err) =&gt; {
      console.log(&quot;Error:&quot;, err);
      toast.error(&quot;서버와의 연결에 실패했습니다.&quot;);
  }
);</code></pre>
<h3 id="7-react-toastify">7. react-toastify</h3>
<p>: React 애플리케이션에서 알림을 표시하기 위한 라이브러리이다.
브라우저 기본 알림이 불편하여 사용했다</p>
<h4 id="1-설치-및-import-5">1) 설치 및 import</h4>
<pre><code>npm install react-toastify</code></pre><pre><code class="language-js">import { toast, ToastContainer } from &quot;react-toastify&quot;;
import &quot;react-toastify/dist/ReactToastify.css&quot;;</code></pre>
<h4 id="2-사용-사례-5">2) 사용 사례</h4>
<pre><code class="language-js">toast.success(returnData.data.message);
toast.error(&quot;글쓰기 실패&quot;);</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[React, Node.js 웹사이트 개발기_2. 서버]]></title>
            <link>https://velog.io/@wg_cat/%EC%9B%B9%EC%82%AC%EC%9D%B4%ED%8A%B8-%EA%B0%9C%EB%B0%9C2</link>
            <guid>https://velog.io/@wg_cat/%EC%9B%B9%EC%82%AC%EC%9D%B4%ED%8A%B8-%EA%B0%9C%EB%B0%9C2</guid>
            <pubDate>Sat, 21 Dec 2024 03:28:48 GMT</pubDate>
            <description><![CDATA[<h2 id="1-서버">1. 서버</h2>
<p>개인프로젝트에서 서버에 사용된 패키지들을 정리했다.</p>
<h3 id="1-express">1) express</h3>
<p>: Node.js환경에서 웹 애플리케이션 및 API를 구축하기 위해 사용되는 프레임워크이다.
HTTP 메서드와 URL 경로를 기반으로 요청을 처리하는 라우팅 기능을 제공한다.</p>
<pre><code class="language-javascript">const express = require(&quot;express&quot;);
const app = express();

app.use(express.json());
app.use(express.urlencoded({ extended: true }));</code></pre>
<h3 id="2-cors">2) cors</h3>
<p>: 브라우저가 다른 기원(Origin)의 리소스에 접근할 때 보안 상의 제한을 해결하기 위한 미들웨어이다. 예를들어, <code>httpL//localhost:3000</code>에서<code>httpL//localhost:8080</code>의 데이터를 가져오려고 할 때, 두 도메인이 다르므로 브라우저는 보안상의 이유로 요청을 차단한다. cors는 이를 제어하고 허용 여부를 결정할 수 있는 프로토콜이다.</p>
<pre><code class="language-javascript">const cors = require(&quot;cors&quot;);

app.use(cors(corsOptions));</code></pre>
<h3 id="3-express-session">3) express-session</h3>
<p>: Node.js의 Express 웹 프레임워크에서 세션 관리를 위한 미들웨어이다.
세션은 클라이언트와 서버 간의 상태를 유지하기 위해 사용되며, 사용자 인증과 같은 작업에서 자주 활용된다. 세션 ID 생성 및 관리, 서버 측 세션 저장소 제공, 상태 유지에 사용된다.</p>
<pre><code class="language-javascript">const session = require(&quot;express-session&quot;);

app.use(
    session({
        resave: false,
        saveUninitialized: true,
        secret: &quot;WG&quot;,
        cookie: {
            httpOnly: true,
            secure: false
        }
    })
);</code></pre>
<h4 id="세션이란">세션이란?</h4>
<p>세션은 서버에서 클라이언트와의 상태를 유지하기 위해 사용하는 메커니즘이다.</p>
<ol>
<li>클라이언트가 서버에 처음 요청을 보내면 서버는 고유한 세션 ID를 생성함</li>
<li>생성된 세션 ID는 클라이언트에게 쿠키 형태로 전달됨</li>
<li>이후 클라이언트는 해당 세션 ID를 사용해 서버와 통신하고, 서버는 이를 기반으로 사용자의 상태를 유지함</li>
</ol>
<h4 id="상태state란">상태(State)란?</h4>
<p>상태는 애플리케이션의 현재 상황을 나타내는 데이터이다.
프론트엔드는 상태 관리가 중요한데, 예를 들어 도서 관리에서 책 대여를 요청하면 페이지를 불러오는 순간에는 API를 통해 호출하고 있는 중이기 때문에 어떤 상태인지 모른다. 그 책의 상태가 대여 가능한 상태인지 대여 불가능한 상태인지 기억하는 것이다.
클라이언트와 서버 간의 여러 요청이 오가는 동안 사용자별 데이터나 상황 정보를 기억하는것을 상태 유지라고 한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[React, Node.js 웹사이트 개발기_1. 구현화면]]></title>
            <link>https://velog.io/@wg_cat/%EC%9B%B9%ED%8E%98%EC%9D%B4%EC%A7%80-%EA%B0%9C%EB%B0%9C1</link>
            <guid>https://velog.io/@wg_cat/%EC%9B%B9%ED%8E%98%EC%9D%B4%EC%A7%80-%EA%B0%9C%EB%B0%9C1</guid>
            <pubDate>Sat, 21 Dec 2024 03:26:52 GMT</pubDate>
            <description><![CDATA[<h2 id="1-프로젝트명--모든-요일의-기록">1. 프로젝트명 : 모든 요일의 기록</h2>
<h2 id="2-구현화면">2. 구현화면</h2>
<hr>
<h3 id="1-회원가입--로그인-화면">1) 회원가입 / 로그인 화면</h3>
<p><img src="https://velog.velcdn.com/images/wg_cat/post/b73db052-f9eb-4d6e-9ea4-db09821c7c6f/image.png" alt=""></p>
<hr>
<h3 id="2-글목록-화면">2) 글목록 화면</h3>
<p><img src="https://velog.velcdn.com/images/wg_cat/post/8c4c5aad-7830-4d94-9d68-bdd0d5cd0064/image.png" alt=""></p>
<hr>
<h3 id="3-글쓰기-화면">3) 글쓰기 화면</h3>
<p><img src="https://velog.velcdn.com/images/wg_cat/post/3939a1c7-e052-4d73-aa5e-70ac0d6d53be/image.png" alt=""></p>
<hr>
<h3 id="4-내정보-화면">4) 내정보 화면</h3>
<p><img src="https://velog.velcdn.com/images/wg_cat/post/6128254e-b80c-4e8f-bd71-1a157d69f115/image.png" alt=""></p>
<hr>
<h3 id="5-글상세-화면">5) 글상세 화면</h3>
<p><img src="https://velog.velcdn.com/images/wg_cat/post/174dfed6-ed3a-488d-98c9-d03b8bd0b408/image.png" alt=""></p>
<hr>
<h3 id="5-글수정-화면">5) 글수정 화면</h3>
<p><img src="https://velog.velcdn.com/images/wg_cat/post/1fcf4e42-5086-40f7-bccf-6d5442b4e38f/image.png" alt=""></p>
<hr>
]]></description>
        </item>
        <item>
            <title><![CDATA[치킨모임 송년회 후기 (2024.11.30)]]></title>
            <link>https://velog.io/@wg_cat/%EC%B9%98%ED%82%A8%EB%AA%A8%EC%9E%84-%EC%86%A1%EB%85%84%ED%9A%8C-%ED%9B%84%EA%B8%B0-2024.11.30</link>
            <guid>https://velog.io/@wg_cat/%EC%B9%98%ED%82%A8%EB%AA%A8%EC%9E%84-%EC%86%A1%EB%85%84%ED%9A%8C-%ED%9B%84%EA%B8%B0-2024.11.30</guid>
            <pubDate>Fri, 13 Dec 2024 16:09:28 GMT</pubDate>
            <description><![CDATA[<p>어느덧 연말이 다가오고 치킨모임의 날짜도 다가왔다. 이 무렵 지원서가 몇개 붙어서 면접 준비를 한답시고 신경을 못쓰고 있었는데 지인에게서 선착순 오픈톡방에 빨리 들어가라고 연락이 와서 얼떨결에 세이프했다.
9월때와는 분위기가 사뭇 달랐는데, 작년부터 참여하는 개발자의 비중이 점점 줄어들고 있었다. 그만큼 개발자를 찾는 사람들도 많았고, 시장이 안좋다는 것이 확 와닿았다.</p>
<p><img src="https://velog.velcdn.com/images/wg_cat/post/4f616116-396f-4845-b3d1-4ff2f40df8c0/image.png" alt=""></p>
<p>120명 정원을 소화하기 위해 천막까지 설치한 모습이다.</p>
<p><img src="https://velog.velcdn.com/images/wg_cat/post/44568038-2c93-4a0c-a218-9854792f5c0c/image.png" alt=""></p>
<p>나도 비교적 늦게 도착했기 때문에 천막에서 이야기를 나누었다. 백엔드 8년차이신 분을 만나서 AI에 관한 이야기를 많이 나누었다. 취업 준비중이라는 내 소개를 듣더니 힘들겠다며 위로를 하시더라.</p>
<p>치킨모임을 소개시켜준 개발자 지인이 퇴사를 했는데, 회사의 재정적인 어려움으로 인해 팀이 해체되었다고 한다. 이 모임의 주최자 진호님도 같은 팀이였는데 같이 퇴사를 하시고 구직중이라고 하신다.</p>
<p>취업시장이 좋지 않은것은 사실이지만 이 또한 지나가리라. 꾸준히 공부하면 결실이 찾아오겠지.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[React, Node.js 웹사이트 개발기_0. 프로젝트 설계]]></title>
            <link>https://velog.io/@wg_cat/%EC%9B%B9%EC%82%AC%EC%9D%B4%ED%8A%B8-%EA%B0%9C%EB%B0%9C</link>
            <guid>https://velog.io/@wg_cat/%EC%9B%B9%EC%82%AC%EC%9D%B4%ED%8A%B8-%EA%B0%9C%EB%B0%9C</guid>
            <pubDate>Sat, 07 Dec 2024 15:38:53 GMT</pubDate>
            <description><![CDATA[<h2 id="1-개발-동기">1. 개발 동기</h2>
<blockquote>
<ul>
<li>하루마다 공부한 내용을 업로드하는 사이트</li>
</ul>
</blockquote>
<p>벨로그는 마크업이 자동으로 적용된다는 장점이 있지만 왼쪽의 글 목록이나 글 전체를 볼 때 가시성이 불편했다. 티스토리도 써봤지만 남들이 만들어놓은 템플릿들은 전부 만족할 수 없었기에 결국 나만의 커스텀 블로그를 만들어야겠다! 라는 생각과 함꼐 설계를 시작했다.</p>
<h2 id="2-주요-기능">2. 주요 기능</h2>
<blockquote>
<ul>
<li>회원가입</li>
</ul>
</blockquote>
<ul>
<li>로그인/로그아웃</li>
<li>게시물 작성, 수정, 삭제</li>
</ul>
<p>기본적인 회원가입, 로그인/로그아웃, 게시물관리 기능을 구현</p>
<h2 id="3-개발-환경">3. 개발 환경</h2>
<blockquote>
<ul>
<li>프론트엔드 : React</li>
</ul>
</blockquote>
<ul>
<li>백엔드 : Node.js</li>
<li>데이터베이스 : MongoDB</li>
</ul>
<p>개발환경은 공부하고 싶었던 언어들을 사용하기로 했다. 프론트엔드는 React, 백엔드는 Node.js, 데이터베이스는 MongoDB를 사용 할 것이다.
서버는 프론트엔드와 백엔드 두개의 서버를 나눠서 사용 할 것이다. 굳이 두개를 나눠야 하느냐 할 수 있겠지만 따로 개발하기에도 편하고 독립성과 확장성을 고려하여 두개로 나누어 개발했다.</p>
<h2 id="4-테이블-구성">4. 테이블 구성</h2>
<blockquote>
<ol>
<li>Users
userId(PK)
email
name
password
createdAt</br>,</li>
<li>Boards
BoardId(PK)
userId(FK)
title
content
createdAt</li>
</ol>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[CRUD]]></title>
            <link>https://velog.io/@wg_cat/CRUD</link>
            <guid>https://velog.io/@wg_cat/CRUD</guid>
            <pubDate>Wed, 04 Dec 2024 15:05:50 GMT</pubDate>
            <description><![CDATA[<p>유저를 관리하는 간단한 CRUD를 구현했다.</p>
<hr>
<h2 id="1-요구사항">1. 요구사항</h2>
<blockquote>
</blockquote>
<p>User 테이블의 요소는 ID, Name, Email
DB는 MySQL을 사용 </p>
<hr>
<h2 id="2-코드">2. 코드</h2>
<pre><code class="language-go">package main

import (
    &quot;github.com/gin-gonic/gin&quot;
    &quot;gorm.io/driver/mysql&quot;
    &quot;gorm.io/gorm&quot;
)

// Model
type User struct {
    ID    int    `gorm:&quot;primaryKey&quot;` // pk
    Name  string `json:&quot;name&quot;`       
    Email string `json:&quot;email&quot;`      
}

// db변수
var db *gorm.DB

// MySQL연결
func initDB() {
    dsn := &quot;username:password@tcp(127.0.0.1:3306)/testdb?charset=utf8mb4&amp;parseTime=True&amp;loc=Local&quot;
    db, _ = gorm.Open(mysql.Open(dsn), &amp;gorm.Config{})

    // AutoMigrate
    db.AutoMigrate(&amp;User{})
}

func main() {
    // db초기화
    initDB()

    // Gin 라우터 생성
    r := gin.Default()

    // Create
    r.POST(&quot;/users&quot;, func(c *gin.Context) {
        var user User
        // 요청 본문에서 JSON 데이터 파싱
        c.BindJSON(&amp;user)
        // db에 저장
        db.Create(&amp;user)
        // 반환
        c.JSON(200, user)
    })

    // Read(전체)
    r.GET(&quot;/users&quot;, func(c *gin.Context) {
        var users []User
        // db에서 모든 사용자 조회
        db.Find(&amp;users)
        // 반환
        c.JSON(200, users)
    })

    // Read(단일)
    r.GET(&quot;/users/:id&quot;, func(c *gin.Context) {
        id := c.Param(&quot;id&quot;)
        var user User
        // db에서 ID로 사용자 조회
        db.First(&amp;user, id)
        // 반환
        c.JSON(200, user)
    })

    // Update
    r.PUT(&quot;/users/:id&quot;, func(c *gin.Context) {
        id := c.Param(&quot;id&quot;)
        var user User
        // 기존 사용자 조회
        db.First(&amp;user, id)
        // 요청 본문에서 수정할 데이터 파싱
        c.BindJSON(&amp;user)
        // db에 저장
        db.Save(&amp;user)
        // 반환
        c.JSON(200, user)
    })

    // Delete
    r.DELETE(&quot;/users/:id&quot;, func(c *gin.Context) {
        id := c.Param(&quot;id&quot;)
        // db에서 ID로 사용자 삭제
        db.Delete(&amp;User{}, id)
        // 반환
        c.Status(204)
    })

    // 서버 실행
    r.Run(&quot;:8080&quot;)
}</code></pre>
<hr>
<h2 id="3-정리">3. 정리</h2>
<p>언어 : go
웹프레임워크 : Gin
ORM : gorm
DB : MySQL</p>
<hr>
]]></description>
        </item>
        <item>
            <title><![CDATA[외부 API 연결하기]]></title>
            <link>https://velog.io/@wg_cat/%EC%99%B8%EB%B6%80-API-%EC%97%B0%EA%B2%B0%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@wg_cat/%EC%99%B8%EB%B6%80-API-%EC%97%B0%EA%B2%B0%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 03 Dec 2024 08:42:28 GMT</pubDate>
            <description><![CDATA[<p>간단한 환율 검색을 하는 Fixer API에 연결해보았다.</p>
<hr>
<h2 id="1-요구조건">1. 요구조건</h2>
<blockquote>
</blockquote>
<p>Path
[GET] /exchange/:code
code는 USD로 한다. </br>
Response
{
   &quot;rate&quot;: 1100.00
}</p>
<hr>
<h2 id="2-코드">2. 코드</h2>
<pre><code class="language-go">package main

import (
    &quot;encoding/json&quot;
    &quot;fmt&quot;
    &quot;net/http&quot;

    &quot;github.com/gin-gonic/gin&quot;
)

// 상수 정의
const (
    baseURL = &quot;https://data.fixer.io/api/latest&quot;
    apiKey  = &quot;1234567890&quot;
)

// Response 구조체
type FixerResponse struct {
    Rates map[string]float64 `json:&quot;rates&quot;`
}

// 환율 가져오기
func getExchangeRate(currencyCode string) float64 {
    // 0. URL 생성
    // 1. Fixer API에 요청
    // 2. JSON응답을 디코딩하여 구조체에 담기
    // 3. 반환

    // Fixer API호출 URL 생성
    url := fmt.Sprintf(&quot;%s?access_key=%s&quot;, baseURL, apiKey)

    // Fixer API에 HTTP GET 요청 후 resp에 담기
    resp, _ := http.Get(url)
    // GET 후 닫기
    defer resp.Body.Close()

    // JSON 응답을 디코딩하여 구조체에 담기
    var fixerResponse FixerResponse
    json.NewDecoder(resp.Body).Decode(&amp;fixerResponse)

    return fixerResponse.Rates[currencyCode]
}

func main() {
    // Gin 라우터 생성
    r := gin.Default()

    // http://localhost:5000/exchange/USD
    r.GET(&quot;/exchange/:code&quot;, func(c *gin.Context) {
        // URL에 적은 통화 코드 추출
        currencyCode := c.Param(&quot;code&quot;)
        // 환율 가져오기
        rate := getExchangeRate(currencyCode)
        // JSON형식으로 응답 반환
        c.JSON(http.StatusOK, gin.H{
            &quot;rate&quot;: rate,
        })
    })

    // 서버 실행
    r.Run(&quot;:5000&quot;)
}
</code></pre>
<hr>
<h2 id="3-정리">3. 정리</h2>
<p>언어 : golang
웹프레임워크 : Gin
defer를 사용해 메모리 누수를 방지했다.</p>
<hr>
<h2 id="4-결과">4. 결과</h2>
<p><img src="https://velog.velcdn.com/images/wg_cat/post/9b3b7fc9-4ef9-41e8-aa65-4459d7ba4073/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[MVC, MVP, MVVM]]></title>
            <link>https://velog.io/@wg_cat/MVC-MVP-MVVM</link>
            <guid>https://velog.io/@wg_cat/MVC-MVP-MVVM</guid>
            <pubDate>Tue, 26 Nov 2024 04:11:42 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>참고자료</p>
</blockquote>
<ul>
<li><a href="https://magicminds.io/blogs/architecture-patterns-in-android-app-development-mvc-mvp-mvvm/">https://magicminds.io/blogs/architecture-patterns-in-android-app-development-mvc-mvp-mvvm/</a></li>
<li><a href="https://www.youtube.com/watch?v=bjVAVm3t5cQ">https://www.youtube.com/watch?v=bjVAVm3t5cQ</a></li>
</ul>
<p>MVC가 제일 먼저 나왔고 MVP, MVVM 순서로 등장했다.
따라서 순서대로 살펴보겠다.</p>
<p>초창기에는 소스코드를 한군데에 몰아서 코드를 작성했었다. 그렇게 하다 보니 프로젝트가 커지면서 소스코드의 규모가 커지고 가독성이 떨어져 유지보수가 어려워지는 현상이 있었다. 그래서 만들어진게 MVC패턴이다.</p>
<hr>
<h2 id="1-mvc패턴">1. MVC패턴</h2>
<p><img src="https://velog.velcdn.com/images/wg_cat/post/ffb3a235-31d6-4c97-9813-a1cb2ffbe2dc/image.png" alt=""></p>
<p>Model-View-Controller의 약자로 애플리케이션을 세 가지 주요 구성 요소로 분리하는 디자인 패턴.</p>
<h3 id="1-뷰view">1) 뷰(View)</h3>
<ul>
<li>사용자 인터페이스를 담당. 화면상에 보여지는 부분이다.</li>
<li>사용자가 인풋을 발생시키면 Controller에 사용자 상호작용을 전달한다.</li>
</ul>
<h3 id="2-모델model">2) 모델(Model)</h3>
<ul>
<li>데이터와 비즈니스 로직을 나타낸다.</li>
</ul>
<h3 id="3-컨트롤러controller">3) 컨트롤러(Controller)</h3>
<ul>
<li>View와 Model을 연결하여 상호작용하는 중간 관리자 역할을 한다.</li>
<li>사용자의 인풋을 관리하고, Model을 업데이트하고, View를 새로고친다.</li>
</ul>
<p>화면에 보이는 요소는 View가 담당, 데이터는 Model이 담당, 둘 사이에서 Controller가 컨트롤 해주는 디자인 패턴이다.</p>
<p>1) 사용자는 View를 보고 인풋
2) 들어온 인풋을 Controller가 받음
3) Controller가 인풋에 대한 처리를 진행함</p>
<ul>
<li>Controller는 모델에게 데이터를 요청</li>
<li>Model은 View에게 데이터를 반환</li>
</ul>
<p>4) 컨트롤러는 뷰에게 데이터를 이용해 아웃풋을 내보내라고 명령함</p>
<p>Controller가 너무 많은 역할을 담당해 코드가 복잡해지는 이슈가 있다.
이를 위해 나온 아이디어가 MVP패턴이다.</p>
<hr>
<h2 id="2-mvp패턴">2. MVP패턴</h2>
<p><img src="https://velog.velcdn.com/images/wg_cat/post/d57dc605-665d-452c-a8a4-bbb52f2d6e29/image.png" alt=""></p>
<p>Model-View-Presenter 약자</p>
<h3 id="1-뷰view-1">1) 뷰(View)</h3>
<ul>
<li>사용자 인터페이스를 담당. 화면상에 보여지는 부분이다.</li>
<li>사용자 인풋을 받아 Presenter에게 전달하고 Presenter로부터 받은 데이터를 화면에 표시</li>
</ul>
<h3 id="2-모델model-1">2) 모델(Model)</h3>
<ul>
<li>데이터를 관리하고 관련 비즈니스 로직을 처리한다.</li>
</ul>
<h3 id="3-프리젠터presenter">3) 프리젠터(Presenter)</h3>
<ul>
<li>View와 Model을 연결하여 상호작용하는 중간관리자 역할을 한다.
사용자의 이벤트를 받아서 처리하고 그 결과를 모델에 반영한다.</li>
</ul>
<p>화면에 보이는 요소는 View가 담당하고 버튼 레이블 포함하여 전부 가져가게 되어 사용자로부터의 인풋도 View가 받는다. 데이터는 Model이 담당.
Presenter는 화면에 어떤 내용이 보여질지만 담당한다.</p>
<p>1) 사용자는 View를 보고 인풋
2) View는 들어온 인풋을 Presenter에게 전달
3) Presenter는 인풋을 처리</p>
<ul>
<li>Presenter는 Model에게 데이터를 요청</li>
<li>Model은 Presenter에게 데이터를 반환
4) Presenter는 데이터를 통해 View에게 아웃풋을 내보내라고 명령함</li>
</ul>
<p>MVC와의 차이점은 Presenter가 MVC의 Controller에서 화면만 떨어져 나간 중간관리자라는 점이다. Presenter는 View는가 어떤 요소를 보여줘야 할 지 결정만 해주고 인풋 아웃풋에 대한 모든 처리를 지니고 있지만 화면과는 상관이 없다. 따라서 View는와 Presenter가는 1:1관계로 의존성이 강하게 연결되어있다.</p>
<p>그런데 View의 개수가 많아지면 View를 하나 만들때마다 Presenter를 같이 만들어야했다. 비슷한 구성의 View여도 Presenter를 매번 만들어야했다. View에서 들어오는 인풋을 무조건 Presenter가 받아서 처리해야하기 때문에 View가 많으면 Presenter도 많아져서 귀찮아진다.
그래서 생겨난 패턴이 Presenter가 공통으로 처리하자는 아이디어로 생겨난 MVVM패턴이다.</p>
<hr>
<h2 id="3-mvvm패턴">3. MVVM패턴</h2>
<p><img src="https://velog.velcdn.com/images/wg_cat/post/cf5db269-1126-434c-ae75-c228b4079c0a/image.png" alt=""></p>
<h3 id="1-뷰view-2">1) 뷰(View)</h3>
<ul>
<li>사용자 인터페이스를 담당. 화면상에 보여지는 부분이다.</li>
<li>ViewModel을 주시하며 필요한 데이터를 가져와 화면에 아웃풋한다.</li>
</ul>
<h3 id="2-모델model-2">2) 모델(Model)</h3>
<ul>
<li>데이터를 관리하고 관련 비즈니스 로직을 처리한다.</li>
</ul>
<h3 id="3-뷰모델viewmodel">3) 뷰모델(ViewModel)</h3>
<ul>
<li>화면에 그려지는 데이터 요소만 가지고 있는다.</li>
<li>View에게로부터 인풋을 전달받고 Model과 상호작용하여 데이터를 받는다.</li>
</ul>
<p>1) 사용자는 View를 보고 인풋
2) View는 들어온 인풋을 ViewModel에게 전달
3) ViewModel은 인풋을 처리</p>
<ul>
<li>Model과 교류하며 데이터를 받음
4) View는 ViewModel을 주시하고 있다가 필요한 데이터가 들어오면 데이터를 가져가 사용자에게 아웃풋을 내보냄</li>
</ul>
<p>여러 화면 View가 있더라도 비슷한 데이터를 가지고 있다면 ViewModel을 공유할 수 있다.
UI와 데이터 로직이 분리되어있어 관리가 쉽지만 간단한 애플리케이션에 MVVM을 적용하면 오히려 코드가 복잡해질 수 있다.</p>
<p>정리하자면 MVC, MVP, MVVM 중 어느 하나가 최고다가 아닌 본인의 방식, 프로젝트의 특성에 맞게 설계하면 되겠다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Winform으로 계산기 개발]]></title>
            <link>https://velog.io/@wg_cat/Winform%EC%9C%BC%EB%A1%9C-%EA%B3%84%EC%82%B0%EA%B8%B0-%EB%A7%8C%EB%93%A4%EA%B8%B0</link>
            <guid>https://velog.io/@wg_cat/Winform%EC%9C%BC%EB%A1%9C-%EA%B3%84%EC%82%B0%EA%B8%B0-%EB%A7%8C%EB%93%A4%EA%B8%B0</guid>
            <pubDate>Fri, 22 Nov 2024 10:01:25 GMT</pubDate>
            <description><![CDATA[<h2 id="1-데이터베이스의-연결">1. 데이터베이스의 연결</h2>
<p>간편한 SQL Server를 사용했다.</p>
<hr>
<p><img src="https://velog.velcdn.com/images/wg_cat/post/b5d663a0-b989-4b3e-87ca-10a353eba5fe/image.png" alt="">
서버를 실행하고</p>
<hr>
<p><img src="https://velog.velcdn.com/images/wg_cat/post/4d46b9a4-6f81-46b7-941b-32a9ecc17934/image.png" alt=""></p>
<p>서버매니저로 테이블을 만들어주고 </p>
<hr>
<p><img src="https://velog.velcdn.com/images/wg_cat/post/f9cf9e92-f0d0-49e8-b1dc-e91dbf8362d9/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/wg_cat/post/f140276f-16c1-412a-9b20-0693da034de4/image.png" alt="">
연결문자열을 통해 데이터베이스를 연결해준다.</p>
<hr>
<p><img src="https://velog.velcdn.com/images/wg_cat/post/896f4e55-a0b7-4b9b-85d8-67438b3a3d7d/image.png" alt=""></p>
<p>그 후 쿼리를 작성하여 데이터를 생성 및 삭제를 진행한다.</p>
<hr>
<h2 id="2-구현화면">2. 구현화면</h2>
<ol>
<li>숫자 텍스트박스에 숫자를 입력</li>
<li>부호를 눌러준다.</li>
<li>다시 숫자 텍스트박스에 숫자를 입력하고 부호를 눌러준다</li>
<li>마지막 숫자를 입력하고 계산을 눌러준다.</li>
</ol>
<hr>
<p><img src="https://velog.velcdn.com/images/wg_cat/post/9883d467-c962-4100-aced-872bc67951cb/image.png" alt="">
계산기 시작화면</p>
<hr>
<p><img src="https://velog.velcdn.com/images/wg_cat/post/8f66074a-cd36-4b31-887c-a4c95246a8fc/image.png" alt="">
숫자입력 후 부호를 누르면 숫자 텍스트박스 아래 label에 연산이 저장된다.</p>
<hr>
<p><img src="https://velog.velcdn.com/images/wg_cat/post/ef1d7386-2e65-486e-b0fe-c99b6671b21d/image.png" alt="">
계산을 누르면 계산기록이 labellist에 저장되고 결과값 label에 계산결과가 출력된다.</p>
<hr>
<p><img src="https://velog.velcdn.com/images/wg_cat/post/8b161fdd-e425-4602-b62f-e049a2215ccd/image.png" alt=""></p>
<p>labellist의 계산기록을 클릭 후 기록삭제를 누르면</p>
<hr>
<p><img src="https://velog.velcdn.com/images/wg_cat/post/3940c1e2-657d-4271-8a52-a7b88a9c4e45/image.png" alt=""></p>
<p>계산기록이 삭제된다</p>
<hr>
]]></description>
        </item>
        <item>
            <title><![CDATA[빛의 거장 카라바조 전시회 후기]]></title>
            <link>https://velog.io/@wg_cat/%EB%B9%9B%EC%9D%98-%EA%B1%B0%EC%9E%A5-%EC%B9%B4%EB%9D%BC%EB%B0%94%EC%A1%B0-%EC%A0%84%EC%8B%9C%ED%9A%8C-%ED%9B%84%EA%B8%B0</link>
            <guid>https://velog.io/@wg_cat/%EB%B9%9B%EC%9D%98-%EA%B1%B0%EC%9E%A5-%EC%B9%B4%EB%9D%BC%EB%B0%94%EC%A1%B0-%EC%A0%84%EC%8B%9C%ED%9A%8C-%ED%9B%84%EA%B8%B0</guid>
            <pubDate>Fri, 22 Nov 2024 09:26:56 GMT</pubDate>
            <description><![CDATA[<p><a href="https://www.sac.or.kr/site/main/show/show_view?SN=66041">https://www.sac.or.kr/site/main/show/show_view?SN=66041</a></p>
<p>11월20일 예술의전당으로 카라바조 전시회에 다녀왔다.</p>
<blockquote>
<p>아내 : 여보 전시회가자
나 : 어? 무슨전시회?
아내 : 카라바조라고 유명한 화가 전시회인데 다 예약해놨어 가자
나 : ?? 카라반 뭐?</p>
</blockquote>
<p>공학생활만 하던 나에게 처음듣는 생소한 화가이름의 전시회장. 간만에 문화생활이라 생각하고 현관문을 나섰다.</p>
<p><img src="https://velog.velcdn.com/images/wg_cat/post/c8993457-4be1-4907-8d43-21bca2ef4ece/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/wg_cat/post/6015a924-d197-42ce-89bd-67ed9acd46b4/image.png" alt=""></p>
<p>미술책에서 많이 본거같기도 하고</p>
<p><img src="https://velog.velcdn.com/images/wg_cat/post/4c8cf0c6-30e6-4c18-9f68-01f7f940fab7/image.png" alt=""></p>
<p>대표적 그림인 &#39;도마뱀에 물린 소년&#39;이다.
유리병에는 흰색 꽃을 틔운 재스민과 보랏빛 장미 한 송이가 담겨 있다. 재스민은 현명함과 신중함을, 장미는 반대로 고통을 상징한다. 신중한 사랑과 고통이 뒤따르는 사랑의 상반된 메시지를 담고있다고 한다.</p>
<p><img src="https://velog.velcdn.com/images/wg_cat/post/a7887a11-179f-4ad7-bd2a-e113113b9e33/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/wg_cat/post/512b4c15-0602-4f96-a667-fd908cf93ff5/image.png" alt=""></p>
<p>정물화도 멋지다. 이 화가는 그림을 그릴 때 스케치 없이 모델을 그려나간다고 한다.</p>
<p><img src="https://velog.velcdn.com/images/wg_cat/post/75fb169c-d446-4318-9b15-721f6b21da34/image.png" alt=""></p>
<p>제일 인상깊게 본 그림이다. 머리카락과 옷감, 손가락의 표현이 너무 사실적이라서 놀랐다.</p>
<p><img src="https://velog.velcdn.com/images/wg_cat/post/1d3ccd32-7f7c-4379-905f-2dfc9d9938bb/image.png" alt=""></p>
<p>마지막 엽서판매처에서 해당 그림의 사본들을 마주할 수 있었다.</p>
<p>이 화가는 16세기에 태어나 다음세기까지 영향력을 미칠 만큼의 핵심적인 천재적 재능을 지닌 화가라고 한다.
그런데 행적을 살펴보면 어릴때부터 말썽을 피우고 각종 범죄에 살인까지 저질러 사형선고를 받았고 다시 도주하였지만 잡혀서 투옥와 탈옥을 병행하다 병으로 숨졌다.
인간쓰레기의 행적을 가지고 있는 자를 천재화가라고 전시회까지 하는걸 보니 뭐든 잘하면 인정받는다는걸 다시한번 깨달았다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Winform과 WPF]]></title>
            <link>https://velog.io/@wg_cat/Winform%EA%B3%BC-WPF</link>
            <guid>https://velog.io/@wg_cat/Winform%EA%B3%BC-WPF</guid>
            <pubDate>Fri, 22 Nov 2024 09:01:55 GMT</pubDate>
            <description><![CDATA[<p>요즘 공부하고있는 Winform과 WPF을 살펴보자.</p>
<h2 id="1-winform">1. Winform</h2>
<p>옛날 C언어로 개발할 시절에 Windows 32 API라는게 있었다. Windows라는 운영체에서 윈도우를 구성하는 여러 라이브러리들이 존재하고 이들이 잘 조합되어서 우리가 쓰는 Windows가 된다.</p>
<p>한편 C로 Windows를 더 잘 개발하기 위해 Winform이 등장한다. MS는 이 때 C#을 개발중이였는데 이 Winform이 너무 잘 만들었다고 여겨져 C#과 합쳐버렸다. 이것이 우리가 알고있는 Winform이다.</p>
<h2 id="2-wpf">2. WPF</h2>
<p>ASP.NET안에는 Webform이 포함되어 있었다. Webform은 Winform처럼 드래그하면 웹이만들어지는 혁신적인 기술이었다. </p>
<p>근데 Webform을 사용하다보니 MS의 개발 트랜드가 코드가 타이트한 개발로 변하였고 이는 Winform이나 Webform을 개발할때 코드가 타이트하게 되어있는 나머지 디자이너가 디자인하기 너무 힘들어졌다.
그래서 UI부분과 비하인드코드 부분의 복잡성을 줄이고자 XAML이라는 마크업언어를 개발하였다. (XAML은 단순히 XML 기반이므로 개발자들과 디자이너들은 컴파일을 하지 않아도 두 마크업 언어 사이에서 콘텐츠를 자유로이 공유하고 편집할 수 있다.)</p>
<p>이 XAML언어로 화면구성을 하고 효율적인 체계로 만든것이 WPF이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[.NET생태계]]></title>
            <link>https://velog.io/@wg_cat/.NET%EC%83%9D%ED%83%9C%EA%B3%84</link>
            <guid>https://velog.io/@wg_cat/.NET%EC%83%9D%ED%83%9C%EA%B3%84</guid>
            <pubDate>Fri, 22 Nov 2024 08:43:34 GMT</pubDate>
            <description><![CDATA[<p>MS는 고민했다. JVM(Java Virtual Machine)같이 자바로 코드를 짜면 모든 OS에서 동작 하듯이 크로스플랫폼을 하기 위한것이 필요했다.
크로스플랫폼이란 컴퓨터 프로그램, 운영 체제, 컴퓨터 언어, 프로그래밍 언어, 컴퓨터 소프트웨어 등이 여러 종류의 컴퓨터 플랫폼에서 동작할 수 있다는 것.</p>
<p>그래서 탄생한것이 바로 크로스플랫폼을 위한 .NET프레임워크이다.
C#, C++, F#, Q#, 델파이닷넷 등 .NET프레임워크에서 동작이 가능하다.</p>
<p>그런데 이러한 .NET의 단점이 있었으니 MS에서 만들어서 window에서 잘 동작하는 window특화 프레임워크였다. 애플 등에서는 작동하지 않았다.</p>
<p>아이러니하지않은가? .NET프레임워크는 크로스플랫폼을 위한 프레임워크인데 다른os에서는 동작하지 않았다. MS에서는 전략을 바꿔 크로스플랫폼에 초점을 맞췄고 4.8.1까지 제작한 .NET프레임워크라는 이름을 버리고 .NET으로 개명을 했다. 이는 현재 VS의 프레임워크 버전 선택창에서도 확인이 가능하다.
<img src="https://velog.velcdn.com/images/wg_cat/post/d5a840f7-e321-40d4-b390-004c02440500/image.png" alt=""></p>
<p>4.6버전부터 기존의 .NET프레임워크와 .NET코어를 병행하여 만들었다. .NET코어는 다른 OS에서 호환이 되는것에 초점을 맞춘 나머지 기존 .NET프레임워크의 기능이 많이 줄었다. 그런데 .NET프레임워크기능을 전부 탑재하고 .NET코어의 기술까지 계승한 .NET 5가 개발되었다. 이 이후는 우리가 알고있는 그 .NET이다</p>
<p>.NET은 기술싸움이다. 무슨이야기냐면 .NET생태계는 상당히 독특한데 Java로 개발한다고 했을때 스프링이 먼저 떠오를거다. 백엔드도 스프링 프론트도 스프링 뭘 해도 스프링이다. Go도 마찬가지다. fiber나 Gin같은 웹프레임워크를 사용하지만 main.go에서 임포트해서 사용하여 Go안에서 끝이난다.
Go나 Java나 Python 대부분 오픈소스이기 때문에 여러사람들이 기여하다보니 강제성을 구축하기가 힘들다는 뜻이다.</p>
<p>왜 이런 이야기를 하냐면, .NET은(C#포함) 오픈소스와는 다르게 MS에서 만든 플랫폼이다. C#으로 백엔드 하려면 뭐해야해요? 하면 가능한 기술들이 엄청많다. .NET으로 ui하려면 뭐해야해요? 하면 윈폼이요 wpf요 등등 수많은 기술들로 구현이 가능하다.</p>
<p>따라서, .NET생태계에 속해있는 기술을 많이 알고있으면 유리하다는 의미가 된다.</p>
]]></description>
        </item>
    </channel>
</rss>