Server) 코딩테스트 만들기 (feat. CodeMirror)

백준우·2023년 1월 5일
3

Server

목록 보기
3/4
post-thumbnail

1. 기본 설계

  1. 코딩테스트 사이트

  2. React구성
    2.1 CodeMirror
    2.2 CodeMirror Source Code
    2.3 데이터 상태관리
    2.4 결과 화면

  3. Server 구성
    3.1 Node Express 구성
    3.2 문자열을 함수로 변환
    3.3 에러가 날경우
    3.4 Source Code


들어가면서

  • 최근 직무가 LMS에 관련되다보니 코딩테스트를 직접 만들어서 서비스하는것에 대해 관심이 생겼다.
  • 간단히 프론트에서 코드를 받아서 서버에서 가상으로 실행시켜주고 이를 정답과 비교하는 로직을 생각했다.
  • 물론 가상환경의 메모리설정과 시간제한등 구체적인 부분은 후에 로직이 확정 되었을때 해도 될것으로 판단했다.

1. 코딩테스트 사이트

먼저 한국에서 많이 쓰이는 사이트부터 알아봤다.

프로그래머스
1. 먼저 코드실행하는 부분과 제출, 그리고 질문하기 테스트케이스추가하기 기능이 있다.
2. 프로그래머스에 로그인하고 문제를 풀다가 나가면 입력했던 코드가 저장되는것을 확인 할 수 있다.
3. 실행결과는 아래 표시영역에 출력되며 결과와 정답 유무를 확인 할 수 있다.
4. JAVA, JS , Python , C 등 다양한 언어를 사용자가 지정하여 설정할 수 있다.

가장 유저입장에서 사용하기 편하고 필요한 기능을 가장 잘 지원해주는 프로그래머스를 따라서 만들어 볼 예정이다.

사용 기술은

종류이름
FrontReact.js
BackNode.js

를 사용할 예정이다 .

필요기능으로는
1. 코드를 IDE환경과 같은 모습으로 입출력 할 수 있어야 한다.
2. 테스팅을 통해 오답 유무를 가려낼 수 있어야한다.
3. 결과를 사용자에게 보여줄 수 있어야한다.

이렇게 3가지를 간단하게 목적으로 두고 만들어볼 예정이다.

2. React 구성

2.1 CodeMirror

  • 먼저 핵심기능이라 할 수 있는 IDE환경을 웹에 구축해주는것이다.
  • 프론트에서 CodeMirror라는 라이브러리를 통해 마치 VS Code와 같은 환경을 웹에 구축해 줄 수 있다.
  • CodeMirror는 다양한 테마도 지원해주고 들여쓰기나 자동입력등 많은 기능을 지원해준다.
  • 개발자 도구를 활용해서 프로그래머스를 확인해보니 CodeMirror태그를 사용한것을 확인했다.
  • https://codemirror.net/

2.2 CodeMirror Source Code

  <div className='codingIDE'>
          <CodeMirror
            className='CodeMirror'
            lineNumber={true} // 줄옆에 숫자 
            value={code} // 입력된 값을 code라는 변수에 담았다
            extensions={[javascript({ jsx: true })]} // 입력값의 종류 
            onChange={onChange} //값이 변할때마다 호출되는 함수 
            theme={okaidia} // 테마 
            gutter={true} // 자동생성
          />
 <div className="BtnArea">

이렇게 해주면 CodeMirror를 활용해서 웹 IDE를 구성할 수 있다.

2.3 데이터 상태관리

function App() {

  const jsFuction = `function solution(t,p) { 
    
}`

  const [code, setCode] = useState(jsFuction); // CodeMirror에 입력되는 값들 ( 기본으로 jsFunction을 가진다 )
  const [result, setResult] = useState([]); // 채점 후 결과를 저장하는 곳



  const onChange = (e) => {
    setCode(e) // CodeMirror의 값이 변할 때마다 호출되어서 값이 저장된다.
  }

  const runCode = async () => {
	// 제출버튼을 누르면 axios를 통해 서버로 코드데이터가 넘어간다.
    await axios.post("http://localhost:8080", { "data": code })
      .then((result) => {
        console.log(result.data)
        setResult(result.data.result)
      })
      .catch((err) => {
        console.log(err)
      })
  }

// CodeMirror에서 MarkDown도 지원해줘서 문제에 대한 설명을 MarkDown으로 표시할 수 있었다.
  const markdown = `
## JavaScript 문제풀이 
...
`

  const markdownExampel = `
 #### 출력 예시  
...

2.4 결과 화면

  • 문제는 프로그래머스에서 가져와서 예시로 만들었다.
  • 문제는 정상적으로 채점이 된다.
  • CSS는 ... 그나마 이쁘게 만들려고 노력했다.. CSS는 배우든가 어디서 뽐낼 실력은 아닌것 같다;;

3. Server 구성

3.1 Node Express 구성

  • 서버는 간단하게 "/"를 API로 받는 값을 채점하는 방식으로 처리했다.
  • Express로 간단히 구성하였다.

3.2 문자열을 함수로 변환

  • 서버로 프론트의 데이터가 넘어올땐 Json으로 넘어오는데 이떄 사용자가 푼 함수또한 Json으로 넘어온다.
  • 문자열로 된 함수를 구동할 수 있는 함수로 전환 해야한다는것이다.
  • 이때 사용되는것이 new Function이라는 기능을 이용해 함수안에 문자열 함수를 넣어서 하나의 함수로 작동할 수 있겠끔하는것이다.

3.3 에러가 날경우

  • 에러가 발생할 경우 에러에대한 메세지를 사용자한테 보여줘야한다.
  • catch문으로 에러를 잡고 문제의 결과부분에 넣어주려했으나 문자열이 너무 길어서 데이터가 깨지게 된다.
  • error를 담은 변수에 toString()을 붙이면 에러객체에서 에러의 이유를 간단하게 표현해줄 수 있다.

  • 난 위 사진의 전체 에러문자열이 아닌 "listen EADDRINUSE" 부분만 필요한 경우이다.

3.4 Source Code

app.post('/', async (req, res) => {
  
	// 문자열인 함수를 받아와서 하나의 함수로 만들기 
    const execFunc = (new Function("return " + funcNm))(); 
  	// result에 함수의 결과값을 받는다. 
	const result = execFunc(argument1 , argument2)
	
    // err의 결과중 string부분만 받아올 수 있도록 한다.
    catch(err){
            resultArray.push({'desc': err.toString() , 'state' : 0})
    }
    
    ...// result를 TestCase와 비교해서 확인하기
    return res
            .status(200)
            .json({"result": resultArray})

});

마치며 ...

  • 원래 코딩 테스트는 SandBox라는 하나의 독립된 환경을 부여해서 돌려야하는것이라고 최백준님의 강의자료를 통해 확인했다.
  • 그리고 지금 위와같은 환경으로 구성하면 만약 사용자가 함수에 무한 함수나 서버를 다운시킬만한 코드를 넣으면 너무 쉽게 당해버린다.
  • 메모리를 제약해서 SandBox로 구성해서 문제환경을 만들어야할 필요성이 있었다.
  • 하루만에 만든거 치곤 괜찮게 결과가 나온거 같고 역시 부딪혀봐야지 문제와 취약점이 보이는 단계라 아직 더 노력해야겠다.
  • 설계단계에서 보안 및 취약점을 알 수 있는 그날까지!!

향후 방향

  • 그리고 결정적으로 프로그래머스는 코드를 돌리면 별도의 네트워크 통신을 하지 않는것을 확인했다.!!!!(개발자 도구) 그래서 어떻게 구성했는지 다시한번 아키텍쳐링과 공부를 하고 재도전을 해볼 계획이다.
  • 일단 Socket.io를 통해 실시간 통신으로 코드를 채팅처럼 받아서 가능한게 아닌가 싶어서 Socket을 통해 채팅서버를 구성해서 네트워크통신을 확인해볼 예정이다.
  • 다시한번 CSS는 공부를 하든 포기를 해야겠다.. 색감정하는것도 능력인거 같다;;;

참고

profile
이게 되네?

0개의 댓글