2025 9-12월 회고

이셀·2025년 12월 3일

회고록&TIL

목록 보기
14/14

근황

추석연휴가 껴있던터라 9~10월이 매우 널널했었다.
그래서 이번 회고는 9-12월달을 합쳐 작성하게 되었다.
(사실 벨로그와 깃허브를 연동해서 잔디를 심어 얼마나 관리하는지 보고 싶었지만... 아직까지도 진행을 하지 못했어서 미루고 미루다가 통합 회고록을 작성하게 되었다ㅜㅜ)

요즘은 여느 SI 프로젝트들이 그렇듯 마감과 주말출근을 통해 업무를 최대한 매듭짓고 오고 가는 연휴일정을 계획하며 인수인계과정을 보내고 있는 나날이다.
돌이켜 생각해보면 평소에는 일기처럼 기록했었지만 이번엔 빛과 그림자처럼 장점과 단점이 확연하게 보이는 하반기였다.

MSSQL을 작성하다 일자나 시간 관련으로 SQL랑 좀 싸워서(?) 작성하게 되었다.

시계의 신!!!

트러블슈팅 : SQL 이슈

문제 1. 과거로 가거나 미래로 가거나(1990 - 9999)

캘린더를 사용하여 일자를 저장하는 기능을 만드는데, 해당 부분에 NULL 값이 오면 년도에 '1990' 또는 '9999'가 박히는 불상사가 생겼다
둘 다 다른 포커스가 달라서 각자 다르게 데이터가 저장되는 것이지만 사실 발생되는 원인은 같다.
타입이 DATETIME인 데이터에는 NULL값은 올 수 없는데(유효하지 않은데) 이 자리에 NULL값이 옴으로 인하여 초기화가 벌어진다.
따라서 Default인 '1990'이 박히거나 DB2TimeStamp 최대 값인 '9999'가 박히게 되는 것이다.

근데 이걸 어떻게 해결하는지에 대해 아무리 고민해도 풀리지가 않았었다.
하지만 구글링해보고 해결할 수 있었는데

// 초기화 @NEWDATE
if @Newdate IN ('1990','9999')
BEGIN
	DATE1 = NULL
END
ELSE BEGIN
// DATETIME을 NVARCHAR로
// 타입과 형태(YYYY-MM-DD) 변경 
	SET DATE1 = CONVERT(NVARVHVAR(10), DATE1, 120)
END

엄청 간단했다
그냥 저런 데이터가 들어오면 어차피 그리드에 들어가야하는 데이터 타입은 VARCHAR이기 때문에 변경할 수 있다.

문제 2. UTC KOREA를 유지하며 분리하기

해외지사가 있는 곳에서 생기는 이슈인데 각 프로그램을 어느 나라에서 열고 적용하냐에 따라 문제가 생긴다.
각 프로젝트마다 기준점이 다르겠지만...
아무튼 내 경우엔
1. UTC KOREA가 기준
2. 날짜와 시간을 분리해서 적용
3. 타입은 DATETIME에서 VARCHAR로 적용(캘린더 > 그리드로 데이터 넘겨주기)
이었다.

이것도 구글링을 하면서 최대한 머리를 굴렸는데, 4줄까지 가던것을 다듬고 다듬어 최종적으로 가장 깔끔한 로직을 작성하게 되었다.

SELECT CONVERT(NVARCHAR(10),DATEADD(HOUR,9,@DATE),121) as DATE,
	   CONVERT(NVARCHAR(10),DATEADD(HOUR,9,@TIME),108) as TIME

이 부분들이 대략 2번정도 깎고 다듬어져서 만들어진 코드들이다보니 그나마 직관적으로 작성되지 않나 생각된다.
역시 사람은 시행착오를 겪어야...ㅎㅎ
한번에 깔끔하고 다른 사람들이 볼 때도 편한 코드들은 바로 나오기 어렵기 때문에 계속 깎고 다듬어야한다고 생각한다.

트러블슈팅 : JQuery 이슈

2가지 문제는 같은 페이지에서 발생한 이슈들이었다.
산 하나 넘으니 산 하나가 또 나타난 그런 슬픈... 이력을 가지고 있던 것인데 다른 페이지들과 레이아웃이 다르다보니 다른 방법을 구상해야했다.
대략 2~3주정도 잡아먹었던 이슈였는데 다음엔 헤매지 않길 바라며 적는다.

클라이언트가 처음에 원하는 동작 방식은 특정 그리드를 클릭하면 클릭한 컬럼의 Data를 가져와서 새 창의 input에 해당 Data가 들어가 있는 방식이었다.
그리고 사용하고 있는 UI는 C#을 기반으로 한 솔루션을 사용하여 작성되는데 css 커스텀을 해야하는 경우 제이쿼리를 사용해서 작성해야 하는 형태로 돌아가고 있었다.
그래서 그 방식에 맞춰 작성했으나... 완성을 했는데 클라이언트의 요구가 바뀌어 input에 Data가 들어가는 것이 아닌 그리드에 직접적으로 들어가는 방식으로 변경되었다.
그래도 아까우니 이전 버전과 함께 적어둔다.

문제 1. 그리드 클릭 시 input으로 데이터 넣기

// 방법 1: tbody의 td 클릭 시 해당 컬럼의 data-field 가져오기

$('tbody td').click(function() {
    var columnIndex = $(this).index(); // 클릭한 td의 위치 (0, 1, 2...)
    var dataField = $('thead td').eq(columnIndex).attr('data-field');
    
    console.log('클릭한 컬럼의 data-field:', dataField);
    sessionStorage.setItem('selectedField', dataField);
});
// 방법 2: thead의 td를 직접 클릭하는 경우
$('thead td').click(function() {
    var dataField = $(this).attr('data-field');
    console.log('data-field:', dataField);
    sessionStorage.setItem('selectedField', dataField);
});

두가지 방식은 어느 곳을 "클릭"하느냐가 중요한 것이었는데 각자의 방식을 참고해서 최종적으로 작성했다.

이 역시도 순수한 js를 사용할지, jquery 메서드를 사용할지에 따라 방법이 나뉜다.

$('tbody td').click(function() {
    // 방법 1: 순수 JavaScript 속성 사용
    var columnIndex = this.cellIndex;
    
    // 방법 2: jQuery 메서드 사용
    // var columnIndex = $(this).index();
    
    var dataField = $('thead td').eq(columnIndex).attr('data-field');
    console.log('컬럼 인덱스:', columnIndex);
    console.log('data-field:', dataField);
    
    sessionStorage.setItem('selectedField', dataField);
});

문제 2. Window.Open()+그리드에 데이터 넣기 이슈

해당 이슈는 원래의 창에서 새로운 창을 띄우는 방식으로 위의 방법과 함께 해결되었으나, 변경요청으로 인해 그리드에 데이터가 바로 들어가는 형태로 최종 수정하게 되었다.

// 부모 페이지

	$('document').ready(function(){
		CON_GRID = $(".그리드 기능");
       	// 데이터로드가 완료되면 행선택 해제
       	CON_GRID.dgAttachHandler("dataLoaded", gfnGridDeselectAll);
	});
    
    	var sColumnSelect = "";

	$('table').on('click', 'tbody td', function(){
		sColumnSelect = $(this).attr('data-field');
	});
	 
	function fnPopupAbnormal()
	{
		var 파라미터 = "";

		$('.그리드기능').find(".selected").each(function () {		
			파라미터 = $(this).find('td[data-field="파라미터명"] span.display').text();
		});
		
		var 파라미터 = $('td.Control.데이터 input').val();
		
	    if(sProductionLineNo != ""){
			sessionStorage.setItem(데이터);
            
			// Window.open()
			window.open(URL"?Alias=스크린명&전달 파라미터명=","fullscreen=yes,menubar=yes,resizable=yes,status=yes,titlebar=yes,toolbar=yes");
		}
	}
// 팝업 페이지
	var CON_GRID_CONTEXT = $Context;

	function DoSearch(){
		CON_GRID_CONTEXT = $Context;
		
		var 파라미터명 = sessionStorage.getItem("파라미터");
	
		CON_GRID_CONTEXT.outputs.파라미터 = 파라미터명;
	};

	// 들어오는 데이터/팝업 데이터 체크 + 자동 조회
	function checkSearch(){
	    var currentParams = sessionStorage.getItem("파라미터") + "_" ...

	// 조건 = 다를 경우 조회
	    if(currentParams !== SearchParams) {
	        sessionStorage.setItem("SearchParams", currentParams);
	        DoSearch();
	    }
	}	



	// 페이지 로딩
	$(document).ready(function(){
	    // 메인페이지에서 가져온 데이터 확인&팝업 페이지 포커스가 되었는지 확인
	    if(window.opener && window.opener.sessionStorage) {
	        try {
	            var keys = ["파라미터","ColumnSelect"];
	            
	            keys.forEach(function(key){
	                var value = window.opener.sessionStorage.getItem(key);
	                if(value){
	                    console.log(key + " 복사:", value);
	                    sessionStorage.setItem(key, value);
	                }
	            });
	        } catch(e){}
	    } 
	    
	    // 자동 조회 function
	    checkSearch();
	    

	    // 팝업>메인(데이터 가져옴)>팝업 페이지 포커스
	    $(window).on('focus', function(){
	        if(window.opener && window.opener.sessionStorage) {
	            var keys = ["파라미터", "ColumnSelect"];
	            
	            keys.forEach(function(key) {
	                var value = window.opener.sessionStorage.getItem(key);
	                if(value) {
	                    sessionStorage.setItem(key, value);
	                }
	            });
	        }
	 		checkSearch();
		});
		
	 });

로 작성해서 마무리 지었다

이 과정도 순탄치 않았는데...

https://musubi-iroiro.tistory.com/406
GET방식을 이용한 Url 데이터 전달 방법

https://inpa.tistory.com/entry/JS-%F0%9F%93%9A-localStorage-sessionStorage
SesstionStorage 참고용 글

다른 예시들을 참고하여 몇몇 데이터들은 GET방식을 사용해서 URL에 데이터를 전달 + 몇몇 데이터들은 dessionStorage를 복사해서 전달해주는 방식으로 코드를 작성했었다.
다만 이 경우에 부모 페이지에서 다른 데이터를 클릭했을 때(데이터가 변경되었을 때) 팝업 페이지에서 그것을 반영하지 못하는 문제가 발생했었다.

이것은 road > submit > search 형태로 로직을 짜서 해당 이슈가 터졌던 것인데, 이걸 가려줄 장치가 필요했다.

https://inpa.tistory.com/entry/JS-%F0%9F%93%9A-%ED%8F%AC%EC%BB%A4%EC%8A%A4-%EC%A0%9C%EC%96%B4-focus-blur
Focus 이벤트 참고용 글

그래서 road > submit > focus > search 형태로 로직을 추가했다.

여기서 focus 이벤트를 준 이유는 위의 문제를 확인할 때 부모 페이지>팝업 페이지>부모 페이지 로 넘어가는 것을 착안해서 이 과정을 통해 팝업 페이지에 포커스가 될 때 부모 페이지의 sessionStorage를 재복사해서 search할 수 있도록 로직을 주면 해결할 수 있는 문제였기 때문이다.

엄청 많이 헤맨데다가 이슈 사항이 복합적으로 얽혀있어서 많은 부분을 첨삭했던... 로직이었다...ㅠㅠ

커리어&도메인 이슈

자세히 밝힐 수는 없지만ㅎㅎ 나는 제조업에서 일하고 있는 프론트엔드다. 물류개발자라고 하면 다들 아!! 하는 것같다
아무튼 이 회사의 입사 사유도 물류와 라인이 어떻게 도는지 알면 어딜가든 써먹을 수 있다보니 응한거지만...!
가장 중요한건 입사제안 형태로 들어온 케이스였기 때문이다.
나에게 있어 이 얼어붙은 취업시장에 들어오는 한줄기의 빛이었다.

처음엔 남들이 하는 웹 언어인 REACT나 JS를 주로 하며 NEXT.JS와 TS를 연마하는... 그런 주니어 개발자였는데 현재는 담당회사가 바뀌어서 c#과 mssql을 주로 사용하고 있다.
처음엔 winform과 directX을 사용하는 정말 c#으로 차력쑈를 했었는데 지금은 스마트팩토리를 추구하는... 사유로 인해 c#을 기반으로 한 솔루션을 함께 사용중에 있어 내 커리어에 좋지 않다는 고민이 2025년 하반기를 힘들게 만들었다.

게다가 최근 해당 물품에 대한 사전조사(라고 쓰고 공부라고 읽는)를 하라는 지시가 떨어져서 더더욱 흥미가 사그라들고 있다.
도메인을 알아야 업무를 할 때 지지부진하지 않고 현업과도 대화가 빠르게 되니 중요하다는 것은 어느 직군에 몸담았던간에 느껴왔던 것이고 늘 해내왔었지만 이번 조사를 통해서 나한테 있어 제조업은... 안맞는다는걸 깨달아버렸다.
내가 이정도 알았으면 됐다고 생각하는 것보다 깊게 알아야하는게 이질감을 불러오게 하는 원인 중 하나인듯하다.

이제 2년차 개발자가 됐는데 이 커리어로 프론트엔드를 지속할 수 있을지는... 모르겠다!ㅎㅎ
처음엔 데이터 흐름에 대해서 공부할 수 있어 너무 좋았고 산업기사 공부하면서 발전하는 개발자가 되고 있구나! 뿌듯했었는데...
주변 개발자들이 제조업에 있는 경우가 드물어 더더욱 외로운 싸움을 하고 있는 것같다.
조만간 조언을 구할 수 있는 사람을 찾아보아야겠다;ㅡ;

그래도 2025년도 내내 작성했던 것처럼 주변에 있는 웹을 다루는 프론트엔드들과 다르게 c#과 sql을 주로 다루다보니 데이터와 코드 읽는게 좋아진 것같다.
부트캠프때는 ts를 적용하기 어려워했었는데(솔직히 any만 쓸거면 js를 쓰는게 맞다!) 지금은 정적인 타입 언어를 통해 타입이 많이 익숙해졌고 장담컨데 그때보단 지금 ts를 공부&실무에 대입하라면 좀더 잘할 자신이 있다.
여러모로 주변인들과 다른 환경에 난관을 겪고 있지만 긍정적인 마음으로 남은 2025년을 보내야겠다:)!

profile
얼렁뚱땅 돌아가는

0개의 댓글