git checkout "빠져나갈 브랜치 이름"
(로컬에서 브랜치를 만들어두지 않았던 상태라면
git checkout -b "브랜치 이름"
이 명령어로 브랜치의 생성과 이동을 한번에 해도 괜찮다.


git add .
(혹은 git add "추가할 파일 이름")


git commit -m "커밋 남길 메시지"


git push origin "1번 줄에서 입력했던 브랜치 이름"


git checkout "원래 있던 곳"
(보통은 main 이나 master로 빠져나갈겁니다)


git merge "1번 줄에서 입력했던 브랜치 이름"


git push

위와 같은 순서로 브랜치를 생성하고

생성한 브랜치에 commit 및 push를 한 후 메인과 merge를 할 수 있습니다.

이때의 merge 방식은 fast-forward 입니다.

 

현재 커밋이 6번이라고 가정했을 때

master나 main 브랜치에 이슈가 생겨서

5번으로 커밋을 되돌리고 임시용 브랜치 A를 만들어서 위의 6번을 그 브랜치에 푸쉬해둔 후 

되살린 5번 커밋의 내용을 바탕으로 문제를 해결한 후 B 브랜치를 만들어서 보낸 커밋을 6-2라고 합시다.

6번과 6-2는 fast-forward 방식으로 merge하기 힘들 수 있습니다. 같은 파일을 작업했다고 치면

conflict가 날 것이기 때문입니다.

이런 경우에 협업에서 가장 많이 사용하게 되는 방식이

3way_merge 입니다.

 

임시대피용 브랜치 A와 문제 해결을 위한 또 하나의 브랜치 B가 있습니다.

여기서 위에서 사용한 방식으로 main과 A를 merge 하게 되면 처음에는 fast-forward 방식으로 merge 되었다고 출력이 됩니다.

그런 후에 6번 커밋이 있는 main과 6-2번 커밋이 있는 B를 merge 하게 되면 fast-forward 방식이 아닌,

Merge made by the 'recursive' strategy

라는 식으로 merge가 진행됩니다.

이 의미는 6번 커밋과 6-2번 커밋을 서로 비교하는 것이 아닌, 그 둘의 부모 커밋인

5번 커밋을 바탕으로 3_way_merge를 하였다는 뜻입니다.

이 3_way_merge도 치트키는 아닌게, 같은 이름의 파일에 같은 부분이 수정되었다면 여전히 conflict가 뜰 수 있습니다.

그럼에도 불구하고 한번의 커밋을 바탕으로 여러명이서 하나의 파일 이름에 내용들을 추가할 경우, 위와 같이 3_way_merge를 할 수 있어야합니다. 

이 방법이 어렵다면 제가 아는 수준에서는 여러 사람이 하나의 파일을 수정하는 일을 최대한 피해야합니다만...

백엔드던 프론트엔드던 협업에서는 위와 같은 방법을 숙지할 수 있으면 좋을 것이라 생각합니다.

문제 설명
두 문자열 s와 skip, 그리고 자연수 index가 주어질 때, 다음 규칙에 따라 문자열을 만들려 합니다. 암호의 규칙은 다음과 같습니다.

문자열 s의 각 알파벳을 index만큼 뒤의 알파벳으로 바꿔줍니다.
index만큼의 뒤의 알파벳이 z를 넘어갈 경우 다시 a로 돌아갑니다.
skip에 있는 알파벳은 제외하고 건너뜁니다.
예를 들어 s = "aukks", skip = "wbqd", index = 5일 때, a에서 5만큼 뒤에 있는 알파벳은 f지만 [b, c, d, e, f]에서 'b'와 'd'는 skip에 포함되므로 세지 않습니다. 따라서 'b', 'd'를 제외하고 'a'에서 5만큼 뒤에 있는 알파벳은 [c, e, f, g, h] 순서에 의해 'h'가 됩니다. 나머지 "ukks" 또한 위 규칙대로 바꾸면 "appy"가 되며 결과는 "happy"가 됩니다.

두 문자열 s와 skip, 그리고 자연수 index가 매개변수로 주어질 때 위 규칙대로 s를 변환한 결과를 return하도록 solution 함수를 완성해주세요.

 

제한사항
5 ≤ s의 길이 ≤ 50
1 ≤ skip의 길이 ≤ 10
s와 skip은 알파벳 소문자로만 이루어져 있습니다.
skip에 포함되는 알파벳은 s에 포함되지 않습니다.
1 ≤ index ≤ 20

 

풀이

// skip 문자열을 먼저 분해하고 해석한다.
// 전체 알파벳에서 스킵할 문자열을 빼고 처리한다.

// 문자열을 분해해서 한글자 한글자 바꿔서 배열화 시킨 후에
// 그 배열을 돌려서 이미 작업이 끝난 알파벳 문자열을 이용해 인덱스만큼 움직인다.
// 1. 한글자를 뺀 후에 전체 배열에서 그 알파벳이 몇번째 index인지 찾는다.

let a_to_z;

let skip_arr = []

function make_a2z_zrr(){
    a_to_z = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
             'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'];
}

function split_sts( skip ){
    for(let i = 0; i<skip.length; i++){
        skip_arr.push(skip[i]);
    }
}

function compare_to_a2z(){
    for(let i = 0; i<a_to_z.length; i++){
        for(let j = 0; j<skip_arr.length; j++){
            if(skip_arr[j] === a_to_z[i]){
                delete a_to_z[i];
            }
        }
    }
}


function solution(s, skip, index) {
    var answer = '';
    make_a2z_zrr();
    split_sts( skip );  // skip 문자열 분해 완료
    compare_to_a2z();
    let new_alphabet = a_to_z.filter((element) => element !== undefined); 
    // a to z 에서 skip에 들어간 문자열을 뺌
    
    // 이제 s 문자열을 반복문에 넣고 돌린다.
    for(let i = 0; i<s.length; i++){
        let temp_index = new_alphabet.indexOf( s[i] )+index;
        while(temp_index>=new_alphabet.length){
            temp_index-=new_alphabet.length;
        }
        answer+=new_alphabet[temp_index];
    }

    
    return answer;
}

 

역할을 나눠서 문제를 풀면 훨씬 쉽고 빠르게 접근할 수 있는 듯 합니다.

벌써 이 봇을 만든지도 반년이 넘었다.

그동안 크고 작은 업데이트들이 있었는데, 오늘은 날씨봇을 업데이트 하는 과정 중에 생긴 이슈에 대해 적어보려고 한다.

 

내가 했던 프로젝트 중에서는 민재봇 프로젝트가 진행했던 프로젝트들 중에서는 다른 사람도 이용할 수 있으며,

사용자들의 피드백을 들으면서 더 개선점을 찾아나갈 수 있다는 점에서 제일 재밋는 프로젝트다.

 

 

현재는 구글로부터 날씨를 얻어와서 알려줄 수 있는 기능이 추가된 상태인데...

반복되는 코드들을 처리하면서 문제를 만났다.

이전까지는 코드들이 잘 동작하다가 const에 객체를 할당할 경우 객체의 값이 변하거나 내용이 추가되어도 잘 출력되던 것을 기억해서 반복되는 문장을 빼둔 후에 const로 정의해두고 관리를 해보려고 했다. 그랬더니 처음에 설정한 안내 문자만 반복할 뿐 새롭게 업데이트 되지 않았다.

나는 분명히 ${ } 문법을 사용해서 값이 유동적으로 되도록 표시하지 않았나...? 라는 생각을 했었다.

하지만 이는 큰 착각이었다... 결국 백틱을 쓰던 ${ }을 쓰던 컴파일할 때는 그저 문자열일 뿐이다.

const에서 재할당이 되어서 새로운 문자열이 될 수가 있을 턱이 없기에 생긴 당연한 일이었다.

"이렇게 하면 되지 않을까~~??"라고 생각했었는데 내가 es2015 문법에 대해 아직 숙지를 하지 못해서 생긴 해프닝이었다.

반복되는 부분을 줄이고 싶어서 url.select( 변수 ).text(); 부분을 함수화 시켜보는 것도 연구했었지만 크게 유의미하진 않았던것 같아서 다시 원래대로 되돌리게 되었다.

 

주석친 부분은 기존의 코드이다

 

function response(room, msg, sender, isGroupChat, replier) {
 
    if (msg.startsWith(".날씨 "))  {
        let weather = msg.slice(4);
        if (isNaN(weather))  {
            try {
                const url = org.jsoup.Jsoup.connect("https://www.google.com/search?q=" + weather + " 날씨").get();
                let guide_msg = `지금 현재 ${weather}의 날씨는 ${url.select("#wob_dc").text()}입니다.`+ "\n";
                guide_msg+=`온도는 ${url.select("#wob_tm").text()}°C 입니다.`+ "\n\n";
                guide_msg+=`강수확률: ${url.select("#wob_pp").text()}
풍속: ${url.select("#wob_ws").text()}
습도: ${url.select("#wob_hm").text()}`;
                if(url.select("#wob_dc").text()=="")  {
                    replier.reply("지금 현재 " + weather + "의 날씨를 불러올 수 없습니다.");
                    return;
                }
                replier.reply(guide_msg);
            }catch(e)  {
                replier.reply("불러올 수 없는 지역이거나 지원되지 않는 지역입니다.");
                return;
            }
        } else {
            replier.reply("지역을 잘못 나타냈어요(EX..날씨 \"조회할 지역\")");
            return;
        }
    }
}

수정하게 된 코드는 다음과 같다 

지금 코드의 장점이라면 이전에 비해서 양이 많이 줄었다는 점이 있다.

단점이 있다면 지금 당장 생각나는건 수정에 취약하다는 점이다.

정확히 어떤 수정에 취약하냐면, 만약에 더 이상 내가 구글로부터 날씨를 얻을 수 없게 되었다면?

그때는 다시 구조를 만들고 좀 더 시간이 많이 필요할 것이다.

하지만 원래의 코드라면 좀 더 길지만 구조적이기 때문에 그 부분에 맞는 부분만 갈아끼는 식으로 대응이 가능하다.

 

프로젝트를 역행해서 그냥 코드를 짧게만 만들어보니 

구조화가 왜 중요한지 좀 더 느낄 수 있는 계기가 되었다.

 

여러 테이블의 값을 조회할 때 뷰 외에도 사용할 수 있는 방법이 뭐가 있을까 하다가

여러 시행착오를 겪어보았다.

여기에서 foreach 를 이중으로 써보니 jsp에서 출력이 제곱으로 되는 문제가 있었고,

아직 jstl 문법에서 var와 item 정도 밖에 몰랐던 수준에서는 방법이 보이지 않아

이런저런 뻘짓 끝에 varStatus 라는 문법을 알게 되었다.

(실은 문서도 제대로 찾아보지 않고 학원에서 배운대로만 활용해보려 했던 잘못이기도 하다. 심화해서 작업을 해볼 생각이었으면 조금 장벽에 부딪혔을 때 바로 문서를 찾아보자고 다시 다짐해본다...)

foreach 문에 varStatus를 이용한다면 다음과 같이 이용할 수 있다.

<c:foreach items="${배열이름}" var="별칭" varStatus="상태용 변수">
 
	// 반복해서 표시할 내용 혹은 반복할 구문
 
</c:foreach>

// 배열이름에는 jsp 등에서 setAttribute 등으로 전달한 배열도 활용할 수 있다.
// 별칭은 반복 구문 안에서 사용할 변수의 이름을 별칭으로 지정해주는 형태이다.
/** 
	상태용 변수라는 말은 다양한 방식으로 활용할 수 있다.
    varStatus 뒤에 올 수 있는 값으로는 foreach에 사용가능한 대부분의 값이 올 수 있다.
    예를 들어 current index count begin end step 등을 말한다.
    
    표현 방식은 
    ${상태용 변수.index}
    이런 식으로 활용이 가능하다. 조금만 더 응용해보자면
    한번의 반복문 안에서 같은 인덱스를 공유하는 다른 배열을 처리할 수도 있다.

	ArrayList의 형식을 빌려서 세팅된 배열이 2개 이상 있다고 가정하고
    아래의 코드를 만들어볼 생각이다.
*/


// 예시 구문, 모든 배열은 ArrayList의 형식
// 게시물에 대한 정보를 담은 boardList
// 멤버들의 값이 담긴 membersList,
// 게시물에 대한 덧글들의 관계정보가 담긴 memberReplyList가 세션에 전달되었다고 치자.

<table>
<c:foreach items="${boardList}" var="boardVO" varStatus="status">
	// 게시물의 번호와
    // 그 번호 게시물에 작성자 해당하는 유저의 닉네임
    // 사람들이 그 번호 게시물에 대해 달은 전체 덧글의 수를
    // 같은 인덱스를 공유하며 한번의 반복으로 표현할 수 있습니다.
	<tr>
    	<td>${boardVO.boardNumber}</td>
        <td>
        	${membersList[status.index].nickname}
        	${memberReplyList[status.index].count}
        </td>
    </tr>
</c:foreach>
</table>

 

 문제의,시작

메인 프로젝트의 구성을 만들 때 긁어온 파일이 utf-8과 ms949로도 인코딩이 되지 않자 구글링으로 알아낸 정보가

내가 작업하려던 파일은 euc-kr로 읽으면 깨지지 않는다는 점이었다. 이 문제는 혼자서 프로젝트를 구축할 때는 전혀 문제가 없었는데 협업을 시작하고 난 후에 대환장 파티가 시작되었다.

그것은 바로 깃을 이용해서 나와 협업자들이 pull push를 할때마다 반드시 깨지는 파일들이 나타났다는 점인데,

이는 내가 구축했던 프로젝트는 euc-kr로 자바 소스 파일들을 읽어들이는데, 협업자들은 utf-8로 되어 있어서

서로 작업물을 공유했을 때 문제가 안생기면 이상할 수 밖에 없던 구조인 것이었다.

 

이를 해결하기 위해서

General의 Content Types에 들어가서

상단의 Content types: 에 있는 Text 항목의 하위권에서 내가 바꿨었던 값을 찾았다.

 

여기서 디폴트 인코딩 값이 euc-kr로 되어 있었는데 UTF-8로 바꿔주니 문제가 해결되었다.

(저 부분에서 디폴트 인코딩이 다르게 설정되어 있으면, 프리퍼런스의 워크스페이스와 프로젝트에서의 UTF-8 설정을 한다고 하더라도 적용되지 않고 자바 소스 파일이 생성되거나 수정된다면 euc-kr로 변경된다는 뜻이다. 그래서 한글 깨짐 현상이 반복되었고, 저 처리 이후에는 한글 깨짐 현상은 없어졌다.)

※ 본 포스팅은 현재 국비학원을 다니는 학생의 시점에서 작성된 글입니다.

 

팀 프로젝트는 처음이라 이런 저런 걱정도 되고

하고 싶은건 많지만 억제하면서 협업 중이다.

모든 과정을 여기에 담을 수는 없지만

배운 점이나 간략한 진행 현황은 블로그에 아카이빙하기로 했다.

 

 회의 또 회의

협업에서는 회의의 중요성을 빼놓을 수 없다.

각자의 역할 분담도 중요하지만, 모두가 알아야할 내용도 있고

주제부터 시작해서 테이블명, 입력값, 출력값, 타입, 이용할 기술 스택, 협업 방식, 기본값 설정 여부, 연동 방식 등등.... 논의해야할게 많다. 첫날은 정리할 것도 많고 얘기할 것도 많아서 거의 모든 시간을 회의에 쏟고 정리했다.

다행히 빠르게 시작할 주제가 좁혀져서 다행이었다.

회의의 중요성은 아무리 강조해도 지나치지 않다...

지금은 협업이 처음이라 오랜 시간 회의가 걸렸지만, 나중에는 목표 시간을 잡고 충분한 준비를 해야겠다고 생각했다.

 

 Git 공동 작업자로 이용

지금까지 Git 허브는 혼자서 작업한 내용들을 아카이빙 하는 용도로만 사용하였는데,

깃허브 계정을 하나를 사용해서 돌려쓰는게 아니라

Setting의 Collaborator 를 이용하여 공동 작업자를 추가해서 저 계정들로도 push pull merge 등을 할 수 있게 만들었다.

그러다보니 같은 이름의 파일을 수정해서 커밋을 올렸을 때

같은 이름의 파일을 다른 계정으로 중복해서 커밋을 올리면 conflict가 발생한다는 점도 알게 되었고,

협업은 혼자할 때보다 고려해야할 사항이 더 많아진다는 점을 실감하게 되었다.

Git을 이용할 때는 워크 플로우를 어떻게 하자(commit 전에 저장소에 새롭게 pull 할 내용이 있는지 체크하기 등등) 등의 이야기를 나눌 수 있었고, 순조롭게 작업이 진행되는 중이다.

 

 open api 이용

api 이용에 대해서 겁먹고 있던게 좀 있었기 때문일까

오늘은 오후 시간에 rest api에 대한 사전 지식을 좀 공부해보고 공공 데이터 포털 이용을 위해서

이것저것 뒤져봤었는데 생각보다 시간을 엄청 많이 잡아먹었다....

 

다른 키워드로 찾아보니 그렇게 어렵지만은 않았다.

https://youtu.be/pe5-RQb-OPI

 

이 유튜브 영상과

https://youtu.be/QPEUU89AOg8

이곳의 영상을 살펴보면서 api 에 대한 지식을 좀 더 보충했다.

문서만으로는 구체적으로 그림이 잘 안그려졌는데 유튜브가 큰 도움이 되었다.

+ Recent posts