Trading 시스템을 내가 아닌 제 3자의 사용자적 입장에서 사용하도록 시뮬레이션 해 보았을 때

자식 Form을 새로 띄워서 값을 입력 받거나 확인할 수 있게 하는 작업이 많이 필요하단 것을 알게 되었다. 

(기능적으로 그렇지만 보기에, 사용하기에 신규Form을 보여주는 것이 더 깔끔한...)

 

  • 부모 Form : Form1 (Delegate Test) 

'로그인' 버튼과 결과를 출력해줄 TextBox를 갖는 부모 Form

  • 자식 Form : Form2 (Login)

'아이디'와 '비밀번호'를 입력할 수 있는 TextBox와 로그인 버튼을 갖는 자식 Form

 

테스트 구현 방식은

부모 Form(Form1)에서 아이디 값을 넘겨주어 자식 Form(Form2)에서는 아이디가 자동으로 입력되고

자식 Form에서 비밀번호 입력 후 '로그인' 버튼을 누르면 

자식 Form이 사라짐과 동시에 부모 Form의 TextBox에 입력받은 비밀번호를 출력하도록 한다. 

 

그러면 두 Form 간에 데이터를 주고 받는 테스트가 완료!

 

1. 부모 Form -> 자식 Form

 

여러 다른 방법이 있는지는 모르겠지만, 내가 구현한 방법은 생각보다 간단하다.

 

[ 부모 Form ]

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace delegate_test
{
    public partial class Form1 : Form
    {
        static string static_id = "brandon";          // 자식 Form에 넘겨줄 ID 값
        Form2 Child = new Form2(static_id);           // 자식 Form 생성자

        public Form1()
        {
            InitializeComponent();

        }

        private void 로그인ToolStripMenuItem_Click(object sender, EventArgs e)  // 로그인 버튼을 눌렀을 때
        {
            Child.Owner = this;
            Child.ShowDialog();                     
        }
    }
}

[ 자식 Form ]

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace delegate_test
{
    public partial class Form2 : Form
    {
        string global_id = string.Empty;

        public Form2(string id)           // 자식 Form의 생성자 - 부모 Form으로부터 값을 전달 받음
        {
            InitializeComponent();
            global_id = id;
        }

        private void Form2_Load(object sender, EventArgs e) // Form2가 보여질때 설정
        {
            textBox1.Text = global_id;    // Form2에 부모 Form으로부터 받은 id 값을 미리 설정
        }

        private void button1_Click(object sender, EventArgs e)
        {

        }
    }
}

[ 결과 ]

자식 Form(Login)이 표시됨과 동시에 부모 Form에서 받은 'brandon'이란 ID 값이 자동으로 입력됨.

 

2. 자식 Form -> 부모 Form

 

이 경우에는 delegate라는것을 사용하는데, C++에서의 함수포인터와 비슷한 개념이다.

'대리자'라는 뜻의 이 delegate는 메소드를 대신해서 호출해 주는 역할을 한다고 생각하면 된다. 

 

[ 부모 Form ]

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace delegate_test
{
    public delegate void LoginGetEventHandler(string id, string password); // 자식 Form EventHandler

    public partial class Form1 : Form
    {
        static string static_id = "brandon";
        Form2 Child = new Form2(static_id);

        public Form1()
        {
            InitializeComponent();
            Form2.LoginGetEvent += new LoginGetEventHandler(this.Login_Process); // EventHandler 등록
        }

        private void 로그인ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Child.Owner = this;
            Child.ShowDialog();                     
        }

        private void Login_Process(string id, string password) // Event 발생 시, 처리할 함수 선언
        {
            string test_result = string.Empty;
            test_result = String.Format("ID : {0}, PW : {1}", id, password);
            textBox1.Text = test_result;  // 자식 Form에서 수신한 값 표시
        }
    }
}

[ 자식 Form ]

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace delegate_test
{
    public partial class Form2 : Form
    {
        public static LoginGetEventHandler LoginGetEvent;  // 부모 Form에서 등록한 EventHandler 선언

        string global_id = string.Empty;

        public Form2(string id) 
        {
            InitializeComponent();
            global_id = id;
        }

        private void Form2_Load(object sender, EventArgs e) 
        {
            textBox1.Text = global_id;
        }

        private void button1_Click(object sender, EventArgs e) // 로그인 버튼을 눌렀을 때
        {
            this.Close();
            LoginGetEvent(textBox1.Text, textBox2.Text);  // 입력된 ID와 PASSWORD 값을 EventHandler에 전달
        }
    }
}

[ 결과 ]

비밀번호를 'asdf1234!@#$'로 입력 후 로그인 버튼 클릭
자식 Form에서 입력한 값을 부모 Form에서 받아서 출력

 

나도 C#을 처음 해보는 것이기에 더 좋고, 간단하며, 오류 없는 방법이 있을지는 모르겠다. 

Trading 시스템의 '사용자 로그인' 부분을 구현하면서 필요한 기능이었기에 어떻게 활용하였는지는

아래 링크에서 확인해 보자. 

Posted by [ 브랜든 ]
,

[C#] MAC Address 가져오기

C# 2020. 6. 15. 23:51

Trading 시스템을 만들면서 사용자 인증방식을 지정된 단말로만 가능하도록

'MAC 인증' 방식을 택했다.

 

물론 내가 C#을 처음써서인 것도 있겠지만, MAC 주소를 읽어올때 마다 값이 다른 것을 확인했다.

이유인 즉, PC에 설치된 VPN...가상 환경 때문이었다.

 

구글링 결과 C#에서 기본적인 단말 MAC 주소를 가져오는 로직은 NetworkInterface들중에 0번째 것을 가져오도록 하는 소스가 대부분이었다. 

 

[ 방법 1 ]

string mac = string.Empty;
mac = NetworkInterface.GetAllNetworkInterfaces()[0].GetPhysicalAddress().ToString();

가상 환경이 설치되어 있는 PC의 경우, 해당 가상환경 사용중인 여부에 따라 값이 다르게 읽어지는 것을 확인했다.

 

그래서 찾은 방법은 현재 상태가 사용중인 네트워크 어댑터의 MAC 주소를 가져오는 것.

 

[ 방법 2 ]

var macAddr =
    (
        from nic in NetworkInterface.GetAllNetworkInterfaces()
        where nic.OperationalStatus == OperationalStatus.Up
        select nic.GetPhysicalAddress().ToString()
    ).FirstOrDefault();

OperationalStatus가 "Up"으로 설정되어 있는 놈을 가져오는 것이다. 

위의 경우에도 현재 시스템의 상태에 따라 정확하게 MAC 주소를 가져오는 것을 확인했다.

실제 물리적 네트워크 어댑터만 사용 중

[ 방법 1 ]을 사용했을 때는 '이더넷 3'인 가상 네트워크 어댑터의 MAC주소를 가져왔지만, [ 방법 2 ]를 사용했을 경우에는 현재 사용중인 '이더넷 2' 네트워크 어댑터의 MAC주소를 가져왔다.

 

하지만, 가상환경도 함께 연결되어 있는 경우, 보다 정확하게 하기 위해 현재 데이터 송/수신량까지 확인하여 가장 많이 사용되고 있는 네트워크 어댑터의 MAC 주소를 가져오는 방식을 사용하는 방법도 있다. 

가상환경 네트워크 어댑터 동시 사용 중

[ 방법 3 ]

Dictionary<string, long> macAddresses = new Dictionary<string, long>();
foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces())
{
    if (nic.OperationalStatus == OperationalStatus.Up)
        macAddresses[nic.GetPhysicalAddress().ToString()] = nic.GetIPStatistics().BytesSent + nic.GetIPStatistics().BytesReceived;
}

long maxValue = 0;
string mac = "";
foreach(KeyValuePair<string, long> pair in macAddresses)
{
   if(pair.Value > maxValue)
    {
        mac = pair.Key;
        maxValue = pair.Value;
    }
}

먼저 딕셔너리에 네트워크 어댑터들의 MAC 주소와 데이터 송/수신량을 쌍(Pair)로 저장 후,

비교하여 송/수신량이 가장 많은 MAC 주소를 가져오는 로직이다. 

 

아래 웹 페이지에 MAC 주소를 가져오는 다양한 방법이 기술되어 있으니, 본인의 개발 방향과 맞는 방법을 사용하면 좋을 것 같다.

 

[ 출처 ]

https://www.it-swarm.dev/ko/c%23/c-%EC%97%90%EC%84%9C-%EC%BB%B4%ED%93%A8%ED%84%B0%EC%9D%98-mac-%EC%A3%BC%EC%86%8C%EB%A5%BC-%EC%96%BB%EB%8A%94-%EC%95%88%EC%A0%95%EC%A0%81%EC%9D%B8-%EB%B0%A9%EB%B2%95/957550098/

Posted by [ 브랜든 ]
,

Class...객체지향에서 빼놓을 수 없는.

Class에는 항상 상속, 오버로딩, 오버라이딩 그리고 캡슐화가 항상 붙어 다닌다.

 

절차적 언어인 C언어를 주 언어로 사용하던 나는

솔직히 객체지향 방식이 쉽게 와닿지 않았다. (사실은 지금도 그렇다....)

그래서 Python을 써도 C언어를 주로 쓰던 시절처럼 Library 함수 형태로 만드는 것이 익숙하고

Class 형식의 Library를 만드는 것이 덜 익숙하다. 

 

그래도 Class에 대해 정리를 해두면 필요할 경우 곧잘 사용할 수 있겠지. 

 

C언어를 사용하던 나에게는 구조체(Struct)라는 개념은 아주 많이 익숙하다. 

때때로 C# 책을 만든 저자들은 클래스와 구조체를 크게 구분하지 않으려 하지만 나와 같은 개발자에게는

분명하게 개념상의 차이점이 있다. 

 

  • 클래스 및 구조체에는 데이터와 동작을 나타내는 멤버가 있다. (사실 8년여간 C 프로그래밍을 해오면서 단 한번도 구조체 않에 멤버 함수를 선언해서 사용해 본 적이 없다!!)
  • 클래스가 상속 받았다면, 클래스에서 선언된 모든 멤버와 함께 상속받은 클래스에서 선언된 모든 멤버들(생성자 및 소멸자 제외)도 클래스의 멤버에 포함된다.
멤버 설명
필드 필드는 클래스 또는 구조체에서 직접 선언되는 모든 형식의 변수이다. 필드는 기본 제공 형식 또는 다른 클래스의 인스턴스일 수 있다.
상수 상수는 값이 컴파일 시간에 설정되며, 변경할 수 없는 필드나 속성이다.
속성 해당 클래스의 필드처럼 액세스되는 클래스의 메소드로 객체 모르게 필드가 변경되지 않도록 할 수 있다.
메소드 클레스가 수행하는 작업을 정의한다. 입력으로 매개변수를 사용할 수 있고, 매개변수를 통해 출력 데이터를 반환할 수 있다. 매개변수를 통하지 않고 직접 값을 반환할 수도 있다.
이벤트 이벤트는 버튼 클릭, 성공적인 메소드 완료 등의 사건이 발생했을 때 알림을 다른 객체에 제공한다.
이벤트는 대리자(delegate)를 사용하여 정의 및 트리거 된다.
연산자 오버로드 된 연산자는 클래스 멤버로 간주되며, 클래스에서 'public static' 메소드로 정의한다.
인덱서 인덱서를 사용하면 배열과 유사한 방식으로 객체를 인덱싱할 수 있다. 
생성자 생성자는 객체를 처음 만들 때 호출되는 메소드이다. 보통 객체의 데이터를 초기화하는데 사용한다.
소멸자 C#에서 드물에 사용되며, 메모리에서 객체를 제고할 때 런타임 실행 엔진이 호출하는 메소드이다.

 

C# 공부를 위해 구매한 책에서 발췌한 내용이다. 

다른 것들은 한번쯤은 들어보거나 사용해봤던 것들인데, '이벤트'와 '인덱서'는 조금 새롭다. 

 

C 언어로 프로그래밍 할 때 '구조체 배열'을 자주 사용했었는데, '인덱서'를 사용하면 비슷한 기능을 구현할 수 있을 것 같다. 

'이벤트' 요소는 .NET 계열에서 특화적으로 사용되는 것으로 생각되는데(그냥 내 생각....), 내가 구현하고자 하는 Trading System에서 아주 많이 사용될 기능으로 보인다. 

 

  1. 필드 (Field)
  • 인스턴스(객체) 필드 : 객체 이름과 함께 사용. public string name과 같이 [접근제한자][자료형][필드명]으로 생성하고 [인스턴스].[필드명]으로 사용.
  • 정적(클래스) 필드 : 클래스 이름과 함께 사용. static 키워드 필수. [클래스이름].[필드명]
  1. 상수
  • 컴파일 시간에 알려진 변경할 수 없는 값. 프로그램 수행되는 공안 갑승ㄹ 변경하지 않는 경우 사용.
  • const 한정자 사용.
  • bool, byte, char, int double, string만 const 사용 가능.
  • Access : [클래스이름].[상수명]

 

 

Posted by [ 브랜든 ]
,
  • 프로그램 명 : L-ATS (Lim's Automatic Trading System)
  • 버전 : 2.0
  • 환경 : Visual C#
  • 주요기능 : HTS/MTS 매수 종목 정보 실시간 수신, 설정값 기반 주식 매도, Flexable 스탑로스
  • API : 이베스트 증권 XingAPI
  • 제작기간 : 2020.05 ~ 

 

1차 화면 구성 초안이 완성 됐다. 

 

v1.0이 있어서 구성은 어렵지 않았지만, v2.0은 실제 다른 여러 사람이 사용할 수 있을 거란(그럴리 없겠지만...;;;)

생각을 전제로 시작부터 많은 기능을 구상했다. 

 

프로그램 사용 절차부터 가입 사용자 로그인 부분과 HTS 접속을 구분하고,

사용자 구분에 따라 스탑로스 사용 범위를 나눌 생각이다. 

그렇게 기본 스탑로스는 모두에게 공개하며, 스탑로스 Flex는 공개되지 않을 예정이다. 

무엇보다 공개 Beta 서비스는 모의 투자만 가능하도록 할 것이다. 

 

스탑로스 자체는 증권사 HTS/MTS에서도 제공되는 기능이지만,

v1.0에서 구현했던 세분화된 스탑로스 조건을 적용할 수 있는 방식을 다시 사용하여 차별화를 둘 예정이다. 

 

설계랑 구현을 동시에 할라니 정신이 없구나...

'Trading' 카테고리의 다른 글

[Trading] L-ATS 사용자 시나리오  (0) 2020.08.02
[Trading] 사용자 정보 구조  (0) 2020.07.18
[Trading] HTS 로그인 설계, 구현  (0) 2020.07.08
[Trading] 프로그램 로그인  (0) 2020.06.21
[Trading] 첫번째 프로그램  (0) 2020.05.24
Posted by [ 브랜든 ]
,

WinApp이나 Explorer에서 항상 해보고 싶던 팝업 띄우기.

 

제공하는 라이브러리가 있을테니 별것 아닐거라 생각은 했지만 실제로 해보게 되니

그 또한 즐겁구나.

 

1. 팝업을 띄울 버튼 생성

 

모달, 모달리스 'Button' 생성

 

2. 팝업으로 보여줄 새로운 Form 추가

 

Project > Add Windows Form

새로운 Form2를 생성

 

3. 팝업창 만들기

 

 

4. 팝업을 띄우는 방법

모달 모달리스
1. showDialog()
2. 새로운 Form이 프로그램의 제어권을 독점.
3. 다른 작업 불가능.
4. 중요한 메시지를 표시할 때 사용.
1. show()
2. 새로운 Form이 프로그램의 제어권을 독점하지 않음.
3. 다른 작업 가능.
4. 알림 또는 정보를 표시하는데 사용.
using System.Windows.Forms;

namespace WinFormTest
{
	public partial class Form1 : Form
    {
    	public Form1()
    	{
            InitializeComponent();
        }
        
        // 모달
        private void button1_Click(object sender, EventArgs e) 
        {
            Form2 modal = new Form2();
            modal.showDialog()
        }
        
        //모달리스
        private void button2_Click(object sender, EventArgs e)
        {
            Form2 modalless = new Form2();
            modalless.show();
        }
    }
}

 

5. 창 닫기

 

팝업 화면에 닫기 버튼이 있다면...

using System.Windows.Forms;

namespace WinFormTest
{
    public partial class Form2: Form
    {
        public Form2()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            this.Close();
        }
    }
}

 

  • 그럼...팝업의 닫기 버튼으로 Form1까지 종료시킬 수 있을까..?

     - 이벤트를 추가하면 된다는데...?

 

6. 원하는 위치에 보이고 싶을때

 

사용자 입장에서 볼 때, 상위(부모) Form의 가운데에 팝업을 띄우는 것이 가장 보기 좋을 것이다.

방법...?

C#에서 제공해 주는 라이브러리가 없다면....

상위(부모) Form의 크기와 팝업 Form의 크기를 구해서 위치를 변경해주는 수밖에...

이것 저것 해보다 보니 C#에서 제공되는 쉬운 방법이 있었다.

private void button1_Click(object sender, EventArgs e) 
{
    Form2 modal = new Form2();
    modal.StartPosition = FormStartPosition.CenterParent; // 부모 Form의 가운데
    // modal.StartPosition = FormStartPosition.CenterScreen; // 모니터의 가운데
    modal.showDialog()
}

와우...정말 손쉽게 이런 기능을...

C언어 쓰던 자괴감이 든다...

'C#' 카테고리의 다른 글

[C#] delegate, 폼 간의 DATA 공유  (2) 2020.06.20
[C#] MAC Address 가져오기  (0) 2020.06.15
[C#] Class, 클래스, 구조체  (0) 2020.06.08
[C#] 값을 표현하기 위한 방법  (0) 2020.05.28
[C#] 눈에 보이는 재미  (0) 2020.05.24
Posted by [ 브랜든 ]
,

[Developer] 전역변수

Developer 2020. 5. 28. 22:57

Simple한 얘기를 해보자. 

 

  • 전역 변수 - 파일 내 어디서든 접근 가능하며, 변하는 값(변수)

엄청나게 유용해 보인다. 소스 파일 내의 어디서는 접근이 가능하다니!! 

하지만

'변수'라는 상태가 문제다.

소스 파일내 어디서든 이 값을 변경할 수 있다는 것이다. 

 

만약 프로그램이 One Thread의 순차처리 방식이라면 당연히 문제가 없겠지만

Multi Thread일 경우 누가 어느 시점에 이 값을 바꿀지 모른다.

 

 

[ 프로그램 동작 전제 ]

  1. Non-Block Packet Receive로 지속적으로 메시지를 수신하여 동일 로직을 처리한다.
  2. 사용자는 1개의 세션을 통해 연결 후, 모든 Transaction이 끝날 때까지(즉, End 메시지를 전송할 때까지) 메모리에 데이터를 유지한다.
  3. 세션관리자는 사용자의 Transaction 진행 여부를 알 수 있다.
  4. 세션 연결 후, 첫 메시지 처리 과정에 사용자 정보를 구조체 배열 메모리(Context Index 기준)에 저장 후, 두 번째 이후 메시지 부터는 사용자 번호를 기준으로 Context Index를 가져와 사용자 정보를 조회/갱신 한다.
  5. Transaction 종료 시, 구조체 배열 메모리 및 세션 관리에서 데이터를 삭제한다.

위의 케이스는 전에 다니던 회사에서 겪은, 실제 운영 시스템에서 발생한 장애 상황을 심플하게 줄여서 정리한 것이다. (실제로는 훨씬..무지막지하게 복잡하다...)

한 시점에 여러명의 사용자가 지속적인 Transaction 처리 중인 상태가 될 수 있기 때문에, Non-Block 상태에서 여러 Transaction을 처리하는 프로그램의 세션, Context 관리란 정말 골치 아프다. 

 

A 사용자가 Transaction을 진행하고 있다. a라는 메시지를 시작으로 30번의 Context ID를 할당받고, b라는 메시지를 전달했을 때, 세션관리자가 A 사용자라는 것을 인지하고 30번의 Context ID를 알려주어 아주 빠른 메모리 접근으로 작업을 처리하도록 했다.

문제는 세션관리자가 Context ID를 'Global Index'에 넣어주고 Process #1은 이 값으로 메모리에 접근하게 되어 있었다는 것이다. (아마 처음 이 프로그램을 만든 사람은...a라는 메시지를 처리하는 함수와 b라는 메시지를 처리하는 메시지가 별도의 파일로 관리되고 있어 전역 변수를 선언해서 extern 명령어로 어디서든 접근하기 쉽게 하려고 했던것 같다.)

 

만약 A 사용자가 a 메시지를 처리하고 b 메시지를 전달후 b 메시지에 대한 함수를 타기 바로 전에 B 사용자가 전송한 새로운 a 메시지가 먼저 처리되면...? 

A 사용자의 b 메시지를 처리하기 바로 직전에 Global Index는 A 사용자의 Index 30에서 B 사용자의 Index 25로 변경될 것이다. 그럼 A 사용자의 b 메시지를 처리할 때는 당연히 Index 25에 접근하게 되어 잘못된 데이터를 처리하게 될 것이다.

 

이것이 얼마나 심각한 문제일지는 겪어본 사람은 알겠지...

거대한 운영 시스템에서 원인 분석만 꼬박 일주일을 잡아 먹은적도 있을 정도다. 

장애 이후 전역변수를 없애는 일 또한 엄청난 곤욕이다.

 

오늘부로 아래 3가지만 실천해 보자.

  1. 모든 전역'변수'는 제거한다.
  2. 변수는 반드시 함수의 Parameter(인자)로 넘겨줘서 사용한다. Call-by-Value든 Call-by-Reference든 상관없다.
  3. 전역으로 선언할 수 있는 것은 오직, 값을 변경할 수 없는 '상수'뿐이란 것을 명심하자.

 

다음에는 위 문제로 새로 만들었던 'Context 관리 라이브러리'를 포스팅 해봐야겠다.

'Developer' 카테고리의 다른 글

[Developer] Input Validation - 입력값 검증  (0) 2020.05.26
[Developer] 개발할 때가 좋았는데.....  (0) 2020.05.25
Posted by [ 브랜든 ]
,

GUI로 표현되는 개발 언어들은 다양하고 편리한 기능들을 제공해준다.

 

예를 들면, 값을 표시해주는 방법 같은 것.

 

1. 그룹 표시자

 

   숫자의 정수부를 표시할 때, 특히 금액을 표시할 때 세자리마다 콤마(,)를 넣는 것이 인식하기 편리하다.

   C#에서 제공하는 표준 형식지정자 중에 N이 그룹 분리자를 표시해준다.

  • 표준 형식 지정자 'N'은 Default로 소수점 아래 두자리까지 표시해 준다. 
double value = 1234.5678;

string.Format("{0:N}", value);      // 출력 : 1,234.57  (Default 소수점 두자리)
string.Format("{0:N0}", value);     // 출력 : 1,235     (소수점 삭제)
string.Format("{0:N3}", value);     // 출력 : 1,234.568 (소수점 세자리)

 

2. String.Format()

 

   String.Format() 메소드는 개발자가 지정한 형식에 따라 객체, 변수, 수식의 값을 문자열로 변환하여 문자열 변수에

   저장해 준다.

  •    통화 (Currency)는 'C'
  •    날짜 (Date)는 'd'
  •    시간 (Time)은 't'
  •    % (Percent)는 'P'
String str;
Decimal ExchangeRate = 1240.00m;
double percent = 1.25d;

str = String.Format("원달러 환율 : {0:C}", ExchageRate);    // W1,240
str = String.Format("원달러 상승률 : {0:P}", percent);      // 1.25%
str = String.Format("날짜 : {0:d}", DateTime.Now);          // 2020-05-28
str = String.Format("시간 : {0:t}", DateTime.Now);          // 오후 8시 12분

 

사용자 지정 형식 문자열은 종류도 많을 것이고 어떻게 활용하냐에 따라 나열하기에는 끝도 없을 것이다.

우선 필요한것 만 정리할 뿐...

'C#' 카테고리의 다른 글

[C#] delegate, 폼 간의 DATA 공유  (2) 2020.06.20
[C#] MAC Address 가져오기  (0) 2020.06.15
[C#] Class, 클래스, 구조체  (0) 2020.06.08
[C#] 팝업창, 새로운 Form 열기, 모달vs모달리스  (0) 2020.06.01
[C#] 눈에 보이는 재미  (0) 2020.05.24
Posted by [ 브랜든 ]
,

[Python] Check Validation

Python 2020. 5. 27. 23:23

변수에 대한 유효성 검증은 어떤 개발 언어에서든 동일한 방식으로 구현된다.

 

나의 경우 Library 형태의 함수화하는 걸 즐기는 편이라 여러가지 형태의 변수값 유효성 체크 함수들을

하나의 파일에 모아두고 import하여 사용한다. 

 

 

1. 일반 문자열

  • 조건 : Length

  모든 값들을 Database에 저장한다면 해당 값에 대한 MAX 값이 존재할 것이다. 

  입력한 문자열의 길이가 Database에 할당된 저장 공간보다 크다면 INSERT 작업이 실패날 것이다.

def check_String_Length(min, max, value):
    if len(value) > max or llen(value) < min :
    	return False
    else:
    	return True

2. 숫자 문자열

  • 조건 : Is Decimal?, Range

  숫자로 된 문자열이니 숫자만 입력가능하여야 하며, 숫자이므로 입력 범위가 필요하다.

  예를들면, PORT 번호 같은 경우이다. PORT는 WELL-KNOWN PORT를 제외하고 1024~65535까지 사용가능 하다.

def check_Decimal_And_Range(min, max, value):
    if value.isdecimal() == False:
        return False
     
    if int(value) > max or int(value) < min :
        return False
    else:
        return True

 3. 나열값 (ENUM)

  • 조건 : Length, Range

  ENUM값은 GUI에서는 Select 박스로 구현하면 참 간단하고 쉽다.

  CUI에서는 ENUM List를 별도로(환경설정파일) 관리하여 사용하면 추가/삭제도 편리하다.

enum_list = ['ORACLE', 'MYSQL', 'MSSQL', 'MARIADB', 'DB2']

def check_Enum(enum_list, value):
    if value not in enum_list:
        return False
    else:
        return True

 4. IP Address

 

  입력된 값이 IP 주소 형태인지 확인하는 가장 간단한 법은 Python에서 제공하는 ipaddress 모듈을 사용하는 것이다.

  복잡하게 정규식을 사용하지 않아도 IPv4/IPv6 모두 간단히 확인 가능하다.

import ipaddress

def check_Ip_Address(value, log):
    try:
        ip = ipaddress.ip_address(value) # just ask!!
        log.debug("[{}] is IP{} Address.".format(ip, ip.version))
        return True
    except ValueError:
        return False

5. E-mail Address

 

  SI 사업을 진행하다보니 사용자 정보를 관리해야하는 경우가 발생하여 E-MAIL 주소를 입력받는 경우가 있었다.

  E-MAIL 주소형태는 간단한 정규식으로 가능하다. (구글링하면 많이 나온다..)

import re

def check_Email_Address(value):
    email = re.compile(r'''(
                    ([a-zA-Z0-9._%+-]+)                  # 이메일의 @ 앞부분
                    @
                    ([a-zA-Z0-9.-]+)                     # 이메일의 @ 뒷부분
                    (\.[a-zA-Z]{2,4}))'''. re.VERBOSE)   
    result = email.match(value)
    if result is None:
        return False
    else:
        return True

 

또 뭐가 있을까...

필요할 때마다 만들어서 계속 추가해야겠다.

Posted by [ 브랜든 ]
,

Input Value. 즉, 프로그램 사용자의 입력은 정말 무궁무진하다.

 

이 사용자의 입력에 관해서는 CUI와 GUI는 확연히 큰 차이를 보인다.

 

GUI의 경우, 예를 들면 C# WinForm, HTML/CSS와 같은...

사용자의 입력 Value를 입력 받음과 동시에 제어할 수가 있다.

 

문자열일 경우 Text Box에 길이 제한을 두어 Max 길이 이상 입력이 되지 않게 한다든지...

ENUM의 값을 갖는 경우 Select Box를 만들어 한정된 값 내에서 사용자가 선택하게 한다든지...


이전 회사에서 쓰던 GUI 화면 예시

  •   PFX는 숫자만 입력이 될 것이며 최소 3자리, 최대 15자리까지만 입력이 가능하다.
  •   IDTYPE은 Select Box로 되어 사용자가 정의된 값들만 입력할 수 있다.
  •   DESC는 어떠한 문자도 입력이 가능하고 최대 20자까지만 입력할 수 있다.

하지만 CUI는 사용자가 입력하는 대로 무궁무진하게 입력 받는다.

CUI환경에서는 Input Data Validation(검증) 작업이 무엇보다 중요하며, 시스템 장애를 막을 수 있는 가장 첫번째 관문이다.


 

그럼 System의 어떤 모듈에서 이 작업을 해야 가장 효율적일까?

 

GUI의 경우를 보면 알수 있듯이...당연히 최초 입력값이 생성되는 시점이다.

이전 회사에서는 아래와 같이 하나의 시스템이 대부분 동일한 구조를 갖고 있었다.

 

TCP/IP를 통해 들어오는 특정 Protocol 형식의 패킷이 Application까지 전달되는 과정의 계층 구조

Input Data Validation 작업은 어디서 해야할까?

당연히 Stack 모듈에서 해야하는, 아니 Stack 모듈에서 구현되어야 하는 기본 기능중의 하나이다.. 

그래야 그 위에서 동작하는 모든 Application들이 사용하는 Value들에 대해 의심하지 않고 

사용할 수 있기 때문이다. 

 

Stack 모듈에서 걸러주지 않는다면....?

각각의 Application들이 실제 사용하는 값들만 직접 검증하면....?

만약 100개의 입력값이 있다고 가정해 보자. 하지만 각각의 Application들은 100개 중 일부(약 10개? 15개?)의 

서로 다른 값을 사용한다고 했을 때, 후자가 훨씬 적합해 보이지 않을까? 필요한 것들만 골라서 쓰면 전체적인 작업도 훨씬 줄어 들고.

 

약 20개의 Application이 Stack 위에서 동작한다고 했을 때, 물론 서로 다른 입력값들을 사용할 수 있지만, 일부 필수 값들(Mandatory)은 중복되서 사용할 수 있다. 마치 동일한 상위 클래스를 상속받은 클래스들 처럼....

그렇게 될 경우, Stack 모듈에서 1번만 검증하면 되는 작업을 20개의 Application이 똑같은 값을 다~ 검증하고 있는 셈이 된다. (5개라고 가정한다면...시스템 입장에서는 100개의 입력 값을 검증하는 셈이지 않을까? 다 같은 값인데...). 아무리 봐도 비효율적이다.

 

10년간의 경험적 측면에서의 핵심은 '실수를 최소화 할 수 있는 방향'을 선택하는 것이다.

실수가 없을것 같지...?만! 어디에도 있더라...그리고 언젠가는 장애가 나더라...사람이 만드는 것이니...

더 큰 문제는 그 수많은 값들 중에 어떤 값인지 정확히 알수가 없었다는 것....

(시스템 마다 다르겠지만 1초에 수십만의 패킷이 유입되는 시스템이라면 유입되는 모든 패킷의 Parameter들을 실시간으로 전부 Logging할 수 없으니...H/W 용량도 용량이지만...File Writing 작업이....)

 

이 정도면 Input Data Validation이 귀찮고 하찮은것 같지만 무엇보다 중요하다는 것을 알수 있을 것이다. 

 

그럼 Python으로 Data 검증 함수들을 하나씩 만들어 보자. 

막상 보면 엄청 심플하고 필요 없을 것만 같은 작업이다. 실제로도 간단하고.... 하지만 실전에서는 필수 작업이다.

 

2020/05/27 - [Python] - [Python] Check Validation

'Developer' 카테고리의 다른 글

[Developer] 전역변수  (0) 2020.05.28
[Developer] 개발할 때가 좋았는데.....  (0) 2020.05.25
Posted by [ 브랜든 ]
,

나는 이제 막 PM의 길에 들어선 10년차 개발자이다. 

 

컴퓨터 공학을 전공하였지만 그렇게 개발이 싫었다.

그렇게 나는 먹고살기 위해 개발자의 길에 서게 되었고 '지옥'같은 시간을 보내게 되었다.

('지옥'이라는 말을 쓴 이유는, 개발자, 프로그래머의 길을 쉽게 생각지 말라는 점에서...)

 

나의 첫 직장은 이름만 들어도 알만한 이동통신 네트워크 Provider의

80% 이상 시스템을 구축하는 1차 Vendor였다. 

이곳은 10년 이상의 안정된, 그리고 체계적인, 기술력 있는 회사다운 회사였다.

 

내 앞길만 보자니...개발의 '개'자도 모르는 놈이 

메모리, 포인터의 C언어, 그것도 네트워크...그 중에서도 하루가 멀다하게 Next Generation 기술이 튀어나오는...

3GPP 국제규격까지 준수해야 하는 이동통신 네트워크라니...

참 실체를 알기 전까지는 얼마나 무모한 선택이었는지 몰랐다.

 

나에게 주어진 첫 프로그램.

내가 처음으로 만든 프로그램.

그것은 시스템에서 사용하는 Configuration Value(환경 설정 값)들을 Control하는 모듈.

 

내가 들은 첫 마디.

"니가 만든 소스는 쓰레기야."

 

당시의 나는 별로 충격 먹지 않았다. 내가 그정도 수준이라고 스스로 생각하고 있었기 때문에..

(나중에 알게됐지만 이유는 배열의 Index를 1부터 사용했기 때문이었다.)

 

하지만 

그곳에서 내가 잘할 수 있는 것을 꿰뚫어 본 스승을 만나게 되었고, 지금처럼 성장할 수 있었다.

 

지금의 나는 나의 능력을 맘껏 펼칠 수 있는(그렇게 믿고 있는) 인공지능 벤처로 이직하여 음성인식 사업분야의 Leader로써 열심히 달리고 있다.

 

2년간 PM으로써 여러사업을 진행하면서 함께 일한 젊은 친구들로부터 느낀것은 

그동안 개발의 기본이라고 배웠던 부분들에 대한 필요성과 중요성에 대해 전혀 모른다는 것이었다.

 

나 역시 공부하는 차원에서 남기는 이 글들이 좋은 개발자가, 좋은 Leader가 되고 싶은 누군가에게 도움이 되었으면 한다. 

나는 머리가 좋은 것도, 공부를 잘했던 것도, 좋은 대학을 졸업한 것도 아니지만, 나만의 개발철학을 갖고 일을 하는 사람으로써 순전히 경험에 의한 나의 humble knowledge가 어딘가에 기록되는 즐거움을 느껴보기로 한다.

'Developer' 카테고리의 다른 글

[Developer] 전역변수  (0) 2020.05.28
[Developer] Input Validation - 입력값 검증  (0) 2020.05.26
Posted by [ 브랜든 ]
,