개발된 프로그램을 타인에게 배포시 프로그램 서명이 되어 있지 않아 일부 백신에서 악성 프로그램으로 인식이 되는 문제가 발생하기도 한다.
다음의 절차로 위의 문제를 해결하고자 한다.
서명관련 프로그램 다운로드
디지털 인증서 (PVK, CER) 생성
디지털 인증서 등록 (SPC)
개인정보교환 파일 (PFX) 생성
배치파일로 자동 서명
1.서명관련 프로그램 다운로드
서명관련한 프로그램 파일은 윈도우 SDK 다운로드페이지에서 내려 받아 설치하거나 윈도우 10 이상의 OS일 경우, C:\Program Files (x86)\Windows Kits\10\bin\10.0.XXXXX 폴더에서 서명에 관련된 프로그램을 찾을 수 있고, 아래 첨부 파일을 내려받아 압축해제 하여 사용해도 무방하다.
형식 : makecert -n “CN=[표시하고자 하는 개인 또는 단체명]” -r -sv [디지털인증서파일명].pvk [디지털인증서파일명].cer
makecert -n "CN=테스트" -r -sv ca.pvk ca.cer
위의 명령어 이후,
창이 나오면서 비밀번호를 입력하도록 되어 있는데, 여기에 입력한 비밀번호는 앞으로의 절차에 반복적으로 나오니, 기억해 둘 것
3. 디지털 인증서 등록 (SPC)
위의 절차를 성공적으로 수행하였다면, 폴더 내에 *.cer 파일과 *.pvk 파일이 생성이 되어 있을 것이다. 다음으로 *.cer 파일로 *.spc 파일을 생성하는데 형식은 다음과 같다.
형식 : cert2spc.exe [디지털인증서파일명].cer [디지털인증서파일명].spc
cert2spc ca.cer ca.spc
cert2spc 실행 프로그램을 통하여, *.spc 파일이 생성된다.
다음은 인증서를 등록하는 과정인데, 다음과 같은 형식으로 입력한다.
형식 : certmgr.exe -add [디지털인증서파일명].cer -s -r localMachine root
certmgr.exe -add ca.cer -s -r localMachine root
등록 여부를 확인하려면 Edge나 익스플로러에서 인터넷옵션->내용->인증서->신뢰할 수 있는 루트 인증기관에 보면, 방금 등록한 [표시하고자 하는 개인 또는 단체명] 이 표시되며, 만약 표시되지 않는다면 가져오기 버튼을 통하여 수동으로 경로를 지정하여 파일 선택해서 가져오면 된다.
4. 개인정보교환 파일 (PFX) 생성
개인정보교환파일을 생성하기 위해 pvk2pfx 프로그램을 사용하는데, 형식은 다음과 같다.
으로 명령어로 서명하거나 signtool signwizard를 통해 디지털 서명 마법사에 나온 절차대로 서명하면 된다.
아래 배치 파일은 서명하고자 하는 실행파일의 경로만 입력받으면 서명하도록 하는 배치 파일이다. 각자 환경에 맞게 커스텀해서 쓸것.
@echo off
setlocal
REM PFX 파일 경로와 비밀번호 설정
set PFX_FILE=ca.pfx
set PFX_PASSWORD=****
set TIMESTAMP_SERVER=http://timestamp.digicert.com
REM 사용자로부터 서명할 파일 이름 입력받기
set /p FILE_NAME="서명할 파일 이름을 입력하세요: "
REM 서명 명령어 실행
signtool sign /f %PFX_FILE% /p %PFX_PASSWORD% /tr %TIMESTAMP_SERVER% /td sha256 /fd sha256 /v %FILE_NAME%
REM 서명 확인
echo.
echo 서명이 완료되었습니다. 서명을 확인합니다.
signtool verify /pa /v %FILE_NAME%
echo.
echo 서명 과정이 완료되었습니다.
pause
endlocal
** 주의 : 경로명에 한글이 들어가 있을 경우, signtool에서 인식을 못하는 상황이 발생 할 수 있음
SELECT column_name
FROM information_schema.columns
WHERE table_name = '테이블명';
SELECT column_name
FROM user_tab_cols
WHERE table_name = '테이블명';
select concat('public object ', column_name, ' { get; set;}')
from information_schema.COLUMNS
where table_name = '테이블명' and table_schema = 'DB명'
/* 결과값 :: 복사 후 자료 형만 적절하게 교체 */
public object SEQUNCE {get;set;}
public object LEVEL {get;set;}
public object MENU_REG {get;set;}
public object MENU_RENT {get;set;}
public object MENU_SEARCH {get;set;}
public object MENU_ANALYZE {get;set;}
public object MENU_DEL {get;set;}
public object MENU_MATCH {get;set;}
public object USER_NM {get;set;}
public object USER_ID {get;set;}
public object USER_PW {get;set;}
public object START_DATE {get;set;}
public object END_DATE {get;set;}
프로그램 개발을 하다 보면 변수들에 대한 규칙을 따라 개발 하다 보면, 변수명이 개떡같아도 최소한 어디에 쓰이는지는 유추 해 볼 수 있다. 데이터베이스도 마찬가지, 몇 가지 룰을 정해서 테이블이든 컬럼이든 명칭을 지정해서 만들다 보면 최악의 경우 데이터베이스 명세가 없어도 명칭과 데이터를 보고 대충 유추해 볼 수도 있다. 왠만하면 미운거 아님 명세서라도 남겨..줘..
SQLite supports different types of SQL Joins, like INNER JOIN, LEFT OUTER JOIN, and CROSS JOIN. Each type of JOIN is used for a different situation as we will see in this tutorial.
When you are working on a database with multiple tables, you often need to get data from these multiple tables.
With the JOIN clause, you can link two or more tables or subqueries by joining them. Also, you can define by which column you need to link the tables and by which conditions.
Any JOIN clause must have the following syntax:
Each join clause contains:
A table or a subquery which is the left table; the table or the subquery before the join clause (on the left of it).
JOIN operator – specify the join type (either INNER JOIN, LEFT OUTER JOIN, or CROSS JOIN).
JOIN-constraint – after you specified the tables or subqueries to join, you need to specify a join constraint, which will be a condition on which the matching rows that match that condition will be selected depending on the join type.
Note that, for all the following examples, you have to run the sqlite3.exe and open a connection to the sample database as flowing:
Step 1) In this step,
Open My Computer and navigate to the following directory “C:\sqlite” and
Then open “sqlite3.exe“:
Step 2) Open the database “TutorialsSampleDB.db” by the following command:
Now you are ready to run any type of query on the database.
SQLite INNER JOIN
The INNER JOIN returns only the rows that match the join condition and eliminate all other rows that don’t match the join condition.
Example
In the following example, we will join the two tables “Students” and “Departments” with DepartmentId to get the department name for each student, as follows:
SELECT
Students.StudentName,
Departments.DepartmentName
FROM Students
INNER JOIN Departments ON Students.DepartmentId = Departments.DepartmentId;
Explanation of code:
The INNER JOIN works as following:
In the Select clause, you can select whatever columns you want to select from the two referenced tables.
The INNER JOIN clause is written after the first table referenced with “From” clause.
Then the join condition is specified with ON.
Aliases can be specified for referenced tables.
The INNER word is optional, you can just write JOIN.
Output:
The INNER JOIN produces the records from both – the students and the department’s tables that match the condition which is “Students.DepartmentId = Departments.DepartmentId “. The unmatched rows will be ignored and not included in the result.
That’s why only 8 students from 10 students were returned from this query with IT, math, and physics departments. Whereas the students “Jena” and “George” were not included, because they have a null department Id, which doesn’t match the departmentId column from the departments table. As following:
SQLite JOIN … USING
The INNER JOIN can be written using the “USING” clause to avoid redundancy, so instead of writing “ON Students.DepartmentId = Departments.DepartmentId”, you can just write “USING(DepartmentID)”.
You can use “JOIN .. USING” whenever the columns you will compare in the join condition are the same name. In such cases, there is no need to repeat them using the on condition and just state the column names and SQLite will detect that.
The Difference between the INNER JOIN and JOIN .. USING:
With “JOIN … USING” you don’t write a join condition, you just write the join column which is in common between the two joined table, instead of writing table1 “INNER JOIN table2 ON table1.cola = table2.cola” we write it like “table1 JOIN table2 USING(cola)”.
Example
In the following example, we will join the two tables “Students” and “Departments” with DepartmentId to get the department name for each student, as follows:
SELECT
Students.StudentName,
Departments.DepartmentName
FROM Students
INNER JOIN Departments USING(DepartmentId);
Explanation
Unlike the previous example, we didn’t write “ON Students.DepartmentId = Departments.DepartmentId“. We just wrote “USING(DepartmentId)“.
SQLite infers the join condition automatically and compares the DepartmentId from both the tables – Students and Departments.
You can use this syntax whenever the two columns you are comparing are with the same name.
Output
This will give you the same exact result as the previous example:
SQLite NATURAL JOIN
A NATURAL JOIN is similar to a JOIN…USING, the difference is that it automatically tests for equality between the values of every column that exists in both tables.
The difference between INNER JOIN and a NATURAL JOIN:
In INNER JOIN, you have to specify a join condition which the inner join uses to join the two tables. Whereas in the natural join, you don’t write a join condition. You just write the two tables’ names without any condition. Then the natural join will automatically test for equality between the values for every column exists in both tables. Natural join infers the join condition automatically.
In the NATURAL JOIN, all the columns from both tables with the same name will be matched against each other. For example, if we have two tables with two column names in common (the two columns exists with the same name in the two tables), then the natural join will join the two tables by comparing the values of both columns and not just from one column.
Example
SELECT
Students.StudentName,
Departments.DepartmentName
FROM Students
Natural JOIN Departments;
Explanation
We don’t need to write a join condition with column names (like we did in INNER JOIN). We didn’t even need to write the column name once (like we did in JOIN USING).
The natural join will scan both the columns from the two tables. It will detect that the condition should be composed of comparing DepartmentId from both the two tables Students and Departments.
Output
The Natural JOIN will give you the same exact output as the output we got from the INNER JOIN and the JOIN USING examples. Because in our example all three queries are equivalent. But in some cases, the output will be different from inner join then in a natural join. For example, if there are more tables with the same names, then the natural join will match all the columns against each other. However, the inner join will match only the columns in the join condition (more details on the next section; the difference between the inner join and natural join).
SQLite LEFT OUTER JOIN
The SQL standard defines three types of OUTER JOINs: LEFT, RIGHT, and FULL but SQLite supports only the LEFT OUTER JOIN.
In LEFT OUTER JOIN, all the values of the columns you select from the left table will be included in the result of the query, so regardless of the value matches the join condition or not, it will be included in the result.
So if the left table has ‘n’ rows, the results of the query will have ‘n’ rows. However, for the values of the columns coming from the right table, if any value that doesn’t match the join condition it will contain a “null” value.
So, you will get a number of rows equivalent to the number of rows in the left join. So that you will get the matching rows from both tables (like the INNER JOIN results), plus the un-matching rows from the left table.
Example
In the following example, we will try the “LEFT JOIN” to join the two tables “Students” and “Departments”:
SELECT
Students.StudentName,
Departments.DepartmentName
FROM Students -- this is the left table
LEFT JOIN Departments ON Students.DepartmentId = Departments.DepartmentId;
Explanation
LEFT JOIN syntax is the same as INNER JOIN; you write the LEFT JOIN between the two tables, and then the join condition comes after the ON clause.
The first table after the from clause is the left table. Whereas the second table specified after the left join is the right table.
The OUTER clause is optional; LEFT OUTER JOIN is the same as LEFT JOIN.
Output
As you can see all the rows from the students table are included which are 10 students in total. Even if the forth and the last student, Jena, and George departmentIds doesn’t exist in the Departments table, they are included as well.
And in these cases, the departmentName value for both Jena and George will be “null” because the departments table doesn’t have a departmentName that match their departmentId value.
Let’s give the previous query using the left join a deeper explanation using Van diagrams:
The LEFT JOIN will give all the students names from the students table even if the student has a department id that doesn’t exist in the departments table. So, the query won’t give you only the matching rows as the INNER JOIN, but will give you the extra part which have the unmatching rows from the left table which is the students table.
Note that any student name that has no matching department will have a “null” value for department name, because there is no matching value for it, and those values are the values in the un-matching rows.
SQLite CROSS JOIN
A CROSS JOIN gives the Cartesian product for the selected columns of the two joined tables, by matching all the values from the first table with all the values from the second table.
So, for every value in the first table, you will get ‘n’ matches from the second table where n is the number of second table rows.
Unlike INNER JOIN and LEFT OUTER JOIN, with CROSS JOIN, you don’t need to specify a join condition, because SQLite doesn’t need it for the CROSS JOIN.
The SQLite will result in logical results set by combining all the values from the first table with all the values from the second table.
For example, if you selected a column from the first table (colA) and another column from the second table (colB). The colA contains two value (1,2) and the colB also contains two values (3,4).
Then the result of the CROSS JOIN will be four rows:
Two rows by combining the first value from colA which is 1 with the two values of the colB (3,4) which will be (1,3), (1,4).
Likewise, two rows by combining the second value from colA which is 2 with the two values of the colB (3,4) which are (2,3), (2,4).
Example
In the following query we will try CROSS JOIN between the Students and Departments tables:
SELECT
Students.StudentName,
Departments.DepartmentName
FROM Students
CROSS JOIN Departments;
Explanation
In the select clause, we just selected two columns “studentname” from the students table and the “departmentName” from the departments table.
For the cross join, we didn’t specify any join condition just the two tables combined with CROSS JOIN in the middle of them.
Output:
As you can see, the result is 40 rows; 10 values from the students table matched against the 4 departments from the departments table. As following:
Four values for the four departments from the departments table matched with the first student Michel.
Four values for the Four departments from the departments table matched with the second student John.
Four values for the Four departments from the departments table matched with the third student Jack… and so on.
Summary
Using SQLite JOINs, you can link one or more table or subquery together to select columns from both of the tables or subqueries.
작년 ‘내 아기의 첫 번째 웨어러블’ 올비의 킥스타터 캠페인이 성공한 후, 배송 전 짧은 기간 내에 앱을 완성하기 위해 네이티브 크로스 앱 개발 플랫폼 Xamarin.Forms를 시작했고 무사히 서비스를 하고 있다. Xamarin.Forms의 개발과정은 이전 글 [앱 개발, 이젠 다시 크로스 개발이다] 을 통해 자세히 다루었다. 요즘은 React Native를 시작해서 앱 개발을 하고 있다.
React Native나 Xamarin.Forms로 네이티브 앱 개발을 해보게 되면 기존의 앱 개발 방식이 허무해지며 다시는 그 방식으로 돌아갈 수 없다. 또한 너무나 매료되어 다른 사람들에게 이것을 알리지 않을 수 없다. 나도 그들 중 한 명으로서 글을 적었고 감사하게도 많은 분들이 읽어주셔서 적지 않은 보람을 느낄 수 있었다. 그런데 이상하다 우리 전도사들의 힘이 약했던 것일까 React Native와 Xamarin.Forms는 한국에서 유독 성장하지 않는다. 대세가 되기는커녕 소수의 회사나 프리랜서들 외에는 관심에서 멀어져 있다고 생각된다.
한국에서는 안 팔린다
Xamarin 네이버 카페 : 회원수 2600이지만 실제 활동 회원 10명 남짓
Xamarin Korea 페북 그룹 : 멤버 1000, 한 달에 글 한두개
React Native 네이버 카페 : 회원수 33
React Native Korea 페북 그룹 : 멤버 500, 일주일에 글 한개 꼴
React Native Seoul Meetup 그룹 : 멤버 100, 매주 작은 모임 진행 중
전혀 활성화되지 않았고 앞으로도 될 것 같아 보이질 않는다. OnOffmix나 meetup에도 모임을 상당히 찾기 어렵다.(마소 MVP분들이 가끔 수고해 주시고 있지만) 일단 React Native와 Xamarin.Forms가 뭔지 아주 간략하게 장단점을 이야기해 보자.
2018-07-30 추가:
*Xamarin.Forms 는 한때 주목받았지만 시간이 지난 현재시점에 비교하면 React Native 에 추월당해 그 격차가 상당히 많이 벌어졌음을 이야기 드립니다.
갓 React Native 갓 Xamarin.Forms
*React Native와 Xamarin.Forms는 하나의 코드로 iOS/Android 혹은 그 외 플랫폼까지 ‘네이티브 앱’ 결과물을 만들어주는 개발도구이다. 둘 다 오픈소스!
서로 싸울 것 없다.. 둘다 짱이니까
React Native
장점 : Javascript, 미친듯한 개발 속도(Live reload), npm 월드의 무궁무진한 모듈들, 트렌디하고 젊은 개발자들이 대거 유입 중인 js진영(진행 중), 백엔드가 js라면 같은 계열이 유지된다, Redux 등 훌륭한 패턴, 향후 본인의 서비스가 웹으로 확장되어 간다면 좋은 선택(React)
단점 : JAVASCRIPT, React에 익숙하지 않다면 러닝커브 있다, Best Practice를 발견하기까지 시간이 걸림(바꿔 말해 Best Practice가 계속 바뀐다), 각 네이티브를 건드리려면 각각의 언어와 툴을 이용해야 한다.
Xamarin.Forms
장점 : C#, 빠르고 안정적이며 정석적인 개발, .Net 월드의 성숙한 라이브러리들, MS 진영의 수준 높은 개발자들 진영 및 서포트, 훌륭한 MvvM 패턴, 각 네이티브를 건드릴 때도 C#으로 작업, XCode나 Android Studio를 한 번도 켤 필요 없이 배포까지 완벽, 향후 본인의 서비스가 데스크톱 클라이언트 앱으로 확장되어 간다면 좋은 선택(Xamarin.Forms for UWP/Mac *Mac은 Preview)
단점 : 해당 진영이 모바일에 대한 이해도가 낮아 모바일 라이브러리들의 생성/개선이 뒤쳐짐
React Native, Xamarin.Forms 공통
장점 : 잘 작성된 매뉴얼, 현재는 매우 빠르고 안정적인 성능을 보여줌, 각 네이티브 플랫폼을 손쉽게 건드릴 수 있음, OS SDK 버전 업데이트에 발 빠르게 대처, 많은 개발자풀 진영/커뮤니티, 개발사와의 소통, 주체가 공룡들이다(Facebook, MS), 오픈소스, VS등 좋은 개발툴
단점 : 노하우가 생기기 전까지는 괴로운 폭탄들이 좀 있다. 한국 회사 네이티브 SDK 래퍼 라이브러리 없음
구글트렌드. 이들의 강세는 현재 진행중.
Why not?
React Native와 Xamarin.Forms는 해외에서 끝없이 성장하고 있고, 앞서 말했듯이 한번 해보고 나면 도저히 기존의 개발방식으로 돌아갈 수 없다. 그런데 왜 한국에서 여전히 널리 퍼지지 않고 있을까. 나도 모르겠다.
대체 그 이유가 무엇인지 몇 가지 가설을 세워서 의문을 제기해보고 싶다.
가설 1. 한국 개발자들의 신기술에 대해 도입 속도가 떨어지는 걸까?
간혹 제기되는 한국 엔지니어들의 영어실력에 대한 언급과 함께 최신 기술에 반응이 늦는 것에 대한 지적이 있기도 한 것 같다. 그런데 아무리 봐도 그렇지는 않은 것 같다. 웬만한 개발자들은 실제로 영어를 잘하진 못하더라도 기술문서를 읽고 적용하는 것은 어렵지 않게 해내고 있다. 또 Swift를 프로젝트에 적용하는 속도나, 과거 Angular / React가 다양한 프로젝트에 도입되는 속도 등을 봐도 신기술을 적용하는 속도가 늦다고 생각되지 않는다. 신기술을 이용하면서도 IE8 등을 지원해야만 하는 개발사들의 노력은 오히려 박수를 쳐줘야 하는 눈물겨운 상황까지.
가설 2. 교과서를 따라야 해… 그렇게 배워왔지…
웹 프론트는 오랜 시간 동안 혼돈의 카오스이며 끝없는 춘추전국시대이다. 도대체 이 구역의 보스가 누구인지 알 수가 없다. 좀 자리가 잡혀간다 싶으면 또 “내가 더 미친놈이야”라며 새로운 게 나온다. 그러면서 각자 생존력을 발휘해가며 ‘무엇이 좋은가’를 찾아가며 성장시켜 온 것이 아닐까 싶다. 이 흐름에 한국의 웹 프론트 개발자들은 직접 만들어내진 못해도 무엇이 좋은지 고민하고 찾아내는 노력을 게을리하지 않았다고 생각한다.
그런데 한국에서 모바일 네이티브 앱 개발은 정석의 틀에서 틀어질 기미가 보이질 않는다. iOS는 XCode/Swift, Android는 Android Studio/Java를 통한 개발 방법이 완전히 시멘트처럼 굳어졌다. 이미 교과서가 있는데 왜 굳이 다른 걸 해야 한다고 생각하는 사람들이 보다 많은 것일까? 보다 나은 것에 대한 갈망보다 안정적인 업무수행이 더 우선시되는 것은 아닌지 생각해볼 필요도 있을 것 같다.
가설 3. 사장이 뿔 내면 누가 책임질 건데?
실리콘밸리에서 스타트업을 하는데 공동창업자 CTO가 없으면 투자는 꿈도 꿀 수 없다는 이야기를 들은 적이 있다. 태생이 뼛속부터 엔지니어링 적인 미국인들에게는 엔지니어 공동창업자가 없이 테크 스타트업을 벌이는 것이 말이 안 되는 것이다.
최근 세계 부자 1위에 등극한 아마존의 제프 베조스가 어떻게 아마존을 경영했는지 봐도, 테크놀로지에 이해가 깊은 대표는 어떤 일이 가능한지 보여주었다. 게다가 최근에는 이런 일까지. [미디어 테크놀로지 기업으로 재탄생한 워싱턴 포스트]
“우리는 결정해야만 했습니다. 우리가 가려는 근본적인 방향이 어느 쪽인지. 그리고 뭐가 이치에 맞고 뭐가 이치에 안 맞는지.” – D8 컨퍼런스
한국에서는 이 반대의 일이 꽤 많이 일어난다. 빵집은 하고 싶은데 제빵기술은 없는 파리바게트 점주들처럼 엔지니어 공동창업자 없이 창업을 하거나, 큰 테크 회사의 높은 요직에 앉아있는 경우이다. 자고 일어나면 새로운 기술이 나오는 세계에서 기술적인 판단과 평가를 해낼 수가 없으니 무엇이 올바른 방향인지 알 길이 없고. 외주에 의존하는 경우가 잦다. 여기에 ‘맡은 일만’ 하기 원하는 엔지니어들이 시너지를 내어 놀라운 작품들이 많이 탄생한다.
대표가 엔지니어가 아니고, 기술에 대한 권한과 책임을 엔지니어에게 완전히 위임할 것도 아니라면, 동급의 위치에서 싸워가며 방향을 결정할 공동창업자 엔지니어가 필수적이다. 나는 꼭 ‘개발자 찬양론’을 전개하려는 것은 절대 아니지만, 중요한 기술적 방향을 결정할 때 엔지니어가 스스로 목소리를 내지 않거나 혹은 중하지 않은 것으로 여겨지는 현실이 안타깝다. 개발 역사적으로 한국은 응용프로그램이 주가 되었고 소프트웨어 원천기술 쪽으론 부족한 상황도 한 몫한다. 우리들 스스로 그만한 중한 위치를 만들지 못한 것도 있다.
기괴하다. 달리 표현할 길이 없는 따릉이 iOS앱
어쨌든 이런 상황의 대표적인 예가 천만 서울시민이 애용하는 따릉이 iOS 앱이 아닐까 싶다. 이 웹앱은 정말이지 시작부터 경악스러운데 뒤로 갈 페이지가 없는데 존재하는 뒤로가기 버튼부터 ‘오른쪽’ 위 햄버거 메뉴를 누르면 ‘왼쪽’에서 경악스러운 쉐도우와 함께 등장하는 Drawer Menu 라던지. 나는 자전거는 사랑하지만 이 앱을 만지기가 싫어서 따릉이를 못쓰겠다. 몇 명 쓰는 앱도 아니고 수백만의 사람들이 써야 하는 앱이 도대체 왜 이모양인 걸까. 이 앱을 보면 그 전설적인.. 1억짜리 개발 건이었는데 외주에 외주를 거쳐 결과물은 500만 원 받고 어떤 개인개발자가 만들었던 사례가 떠오른다. 서울시청에는 이것에 대해 평가할 수 있는, 혹은 개선할 수 있는 사람이 한 명도 없는 것인가? 아니면 그냥 자기 입에 지퍼를 닫아버린 건가. 몇 년째 같은 모양인 이 앱 대체 언제까지 봐야 하나?
하이브리드 앱이 문제라는 말이 아니다. 웹앱은 한마디로 알맹이 웹을 잘 만든다면 사용이 원활한 훌륭한 결과물이 나올 수 있다. 실제로 그런 회사들이 한국에도 꽤 많이 있다. React Native와 Xamarin.Forms의 경쟁상대는 하이브리드가 아니고 각 네이티브다. 하이브리드는 지금까지 그랬고 앞으로도 모바일 앱의 한 축을 계속 담당할 것이다. (뒤에 다시 언급하겠다)
어쨌든 React Native나 Xamarin.Forms로 개발을 하게 되면 노하우가 쌓이기 전까지는 앞으로 해야 할 이 부분이 크로스 플랫폼으로 가능할지 불가능할지 가늠을 하지 못해 시간을 박아 넣어야 하는 순간이 분명 있다. 내가 엔지니어면서 동시에 내가 중요 결정권자면 그럼에도 불구하고 그것을 감수해보자 라는 선택을 할 수도 있지만, 그렇지 않은 경우 회사에서 나는 곤란한 처지에 빠지게 될 것이 분명하다. 좀처럼 쉽게 선택할 수 없다. 뭔가에 막혀 끙끙대며 시간을 보내고 있게 된다면 개발을 잘 알지 못하는 사장에게 ‘내가 무능한 개발자가 아니다’라는 변호를 훌륭하게 해낼 자신이 없다. 해낸다 해도 사장의 머릿속에 의문은 사라지지 않겠지. 물론 훌륭한 개발자라면 회사와 관계없이 다른 개인 시간에 공부하고 테스트해보지 않을까 싶기도 하다.
가설 4. 마켓 리더 개발사들의 미적거림
이게 가능한지 불가능한지 가늠이 안 되는 이유는 그만큼 선례가 많지 않기 때문이다. 한마디로 먼저 총대 맸던 사람이 많지 않으니 아무도 움직이지 않는 현상이 오래도록 지속되고 있다. 가장 기본적으로는 한국형 앱 개발에 필수적인 네이버/카카오/지도 SDK 나 PG사 결제모듈 SDK 의 React Native 용 공식 래퍼모듈이 없다는 것이 큰 문제다. (Xamarin 쪽은 훨씬 상황이 심각하다)
npm에서 검색해보면 몇몇 개인이 배포한 래퍼모듈이 있기는 한데 (감사합니다) 다운로드 수가 매우 적고 해당 프로젝트를 진행하면서 필요해서 배포한 임시적인 모듈들이라 향후 관리가 되지 않을 가능성이 크다. Facebook SDK 등과 같은 유명한 SDK들의 경우 React Native는 지네가 만든 것이니 당연히 자기들이 배포해놓았고, Xamarin의 경우 활성화를 위해서 Xamarin 팀이 직접 FB SDK 등 주요SDK는 바인딩해서 배포/업데이트 관리하고 있다. 그럼 네이버, 카카오 SDK 이거 누가 React Native용으로 래핑 해서 배포해야 하는 것일까? 네이버, 카카오에서 해야 한다고 생각한다. 이 정도로 지속적으로 (해외에서) 대세급으로 성장하고 있는 플랫폼이면, 조금 손해 보는 것 같아도 기여하는 측면으로 해주는 선택을 했으면 좋겠다. 쓰는 사람들이 많아지면 해줄 계획일까? 사람들은 반대로 네이버, 카카오가 해주면 쓸려고 할지 모르겠다. 닭이 먼저냐 달걀이 먼저냐..
그리고 아주 쌘 놈이 오고 있다. 위에서 열심히 한말을 전부 쓰레기통에 집어넣어야 할 수도 있다는 위기감에 아찔하다. Progressive Web App(이하 PWA)는 한마디로 말해 (잘 만들어진) 하이브리드 앱의 끝판왕이다. 지금까지의 하이브리드 앱은 웹이지만 앱의 껍데기가(앱스토어 등록 등) 갖고 싶어서, 웹뷰 하나에 url 박고 Push Notification 좀 추가해서 스토어에 등록한 앱이다. 방금 말했듯이 이들이 필요했던 건 단지 바탕화면에 깔리는 앱 아이콘과 푸시뿐이다. 이것을 Android OS적으로 지원하고 추가로 오프라인 가동까지 가능하게 된 것이 PWA다. [Progressive Web App is a perfect solution for your Lite version] 이 글에 사례들과 함께 아주 잘 나와있다.
올라간다~~ 내가 짱 한번 먹어볼려고!
웹앱은 알맹이가 잘 만들어졌기만 하면 요즘은 정말 네이티브 앱과 비교해도 아무 문제가 없다. Angular나 React로 만든 웹앱도 약간의 작업을 추가하면 어렵지 않게 PWA로 바꿀 수 있다. 웹앱의 유일한 문제라 한다면 중구난방한 UX. 그들의 앱 생태계에 ‘디자인 가이드라인’을 철저히 세우고 이를 철저하게 수호해왔던 애플의 경우 내 생각에 이 UX 때문에 가장 고민을 하고 있지 않을까 생각된다. 최근 iOS의 PWA 지원 계획을 가늠하게 할 수 있는 정보가 하나 나오긴 했지만, 아직은 확실치가 않다. 그리고 PWA앱과 네이티브 앱이 공존했을 때의 혼동을 줄 수 있는 문제. 앱스토어를 통해 내오던 수익을 나눠먹을 것이라는 위기의식. 대세가 될 것은 분명하나 교통정리가 어떤 식으로 흘러갈지 모르겠다. iOS는 PWA용 포켓 바탕화면을 따로 만들어주려나? 뭐 예측이야 자유니 한번 해본다.
PWA가 대세가 된다고 하여도 앱의 모든 부분을 대체 가능한 것은 아니기 때문에 (스마트폰 디바이스의 센서를 사용해야 한다던지), React Native와 Xamarin.Forms가 없어질 것이라고 생각되지는 않지만, 이들 크로스 플랫폼이 가장 효력을 발휘하는 파트가 PWA의 그것과 겹치는 부분도 있어. 쉽게 가늠하기는 어렵겠다.
글을 마치며.
아직도 한국에서는 Active X를 몇년도에 없애니 하는 이야기를 마주해야 하는 현실이 참 원통하다. 아직도 모바일 결제가 여러 규제에 묶여 활성화되지 않는 현실이 고통스럽다.
그리고 그동안 여러 방법으로 새로운 기술들을 알리는 세션 스피커 분들, 커뮤니티를 만들어온 여러 분들, 네이티브 SDK 래퍼모듈을 배포하는 분들, 이를 지원하고 후원하는 공개SW개발자Lab 등의 기관 분들께 감사드린다.
일부 소프트웨어 개발 인력 시장에서, 제가 근무했던 D사 같은 회사에 다니는 인력의 가치를 높게 평가하고 있는 듯합니다. 그래서인지, 종종 인재를 소개해 달라는 부탁을 받고는 했고, 그럴 때 들었던 생각을 차마 직접 얘기하지는 못하고 맘속에 담아뒀다가 이제야 풀어 보았습니다.
개발자 인력 시장에서 선호하는 직장에서 오래 일했기에, 종종 “좋은 개발자를 추천해달라”는 얘기를 듣기도 했습니다. 그럴 때마다 사실대로 말했지요.
“제가 내성적이라 인맥이 좁아서 아는 개발자도 별로 없구요, 그 아는 개발자들도 지금 각자 직장에 잘 다니고 있어서요…”
이렇게 있는 그대로를 말씀드려도, 상대의 눈빛에는 못내 아쉬움이 묻어납니다. 어떤 분은 저한테 혹시 함께 일할 생각이 없는지를 떠보기 위해 이런 간접적인 질문을 하기도 하는 것 같습니다. 마치 남자 어린이들이, 자기 여자친구가 됐으면 좋겠는 여자애에게 “야 주변에 괜찮은 쏠로 없냐?”라고 묻는 것과 비슷한 심리인가 봅니다. 아니면, 남자친구가 있는지 확인하려고 “너 소개팅 나가 볼래?”라고 묻는 심리와 비슷한 걸 지도 모르겠구요. 물론, 그냥 순수히(?) 주변 사람의 소개를 요청하는 경우가 더 많겠습니다.
좋은 시니어 개발자는 누구인가?
소개를 원하는 “좋은 개발자”는 대체 어떤 사람일까요? 앞서 무리하게 비유한 연애시장의 메타포를 조금 더 이어가자면, “괜찮은 남자/여자”처럼 불분명한 표현일 것입니다. 주위에 좋은 남자를 소개해달라며 이렇게 얘기하는 여자 친구, 한두 명쯤은 있었죠?
“키는 180cm+까지는 아니더라도, 내가 힐 신고 다니기에 부담이 없을 정도는 돼야겠지? 학교는 인서울이면 되고, 집안에 돈도 좀 있으면 좋겠고, 얼굴은 아주 잘 생길 필요는 없지만, 그래도 같이 다니기 창피하지는 않았으면 해. 내가 정우성, 소지섭 뭐 이런 급을 바라는 건 아니고, 아! 요새 유아인 좀 괜찮더라 … 구구절절절”
차라리 이렇게 솔직하게 얘기하면, 오히려 다행일지도 모릅니다. “아, 그렇구나, 그냥 넌 혼자 지내는 게 이 지구의 공익에 나을 것 같다. 우주에 가서 네 꿈을 찾아보렴!”라고 얘기해주면 되니까요. 하지만 저렇게 얘기하는 친구가 속물처럼 보일지라도 차라리 양반입니다. 그냥 뭉텅그려 얘기하는 친구에게, 아까운 내 동성 친구들을 소개해줘 봤자, 이번에는 뭐 키가 작네, 다음에는 성격이 별로네, 그다음에는 다 좋은데 얼굴이 너무 미안하게 생겼네, 이런 핑계들을 대고는 하지 않던가요?
아, 혹시 위에 적은 내용이 성차별적인 비유일까 봐, 공평하게 남자 버전도 적어볼까요?
“뭐, 좀 예쁘면 되지 뭐, 얼굴을 아주 깎아내린 미모는 아니더라도 길 가던 사람들이 한 번쯤 뒤돌아볼 정도면 되고, 쾌활하면서 얌전하고, 청순하면서 섹시하고, 몸매는 약간 마른듯하면서 글래머면 좋겠고… 아, 참, 나이는 나보다 4~5살 어리면 좋겠는데, 그보다 더 어려도 상관은 없어.”
물론, 남자들은 이렇게까지 얘기도 못 합니다. 저 내용의 일부도 체 말하기 전에 한 바가지 욕을 먹으며 두들겨 맞고 상황 종료될 테니까요. 그리고 대개는 자신이 어떤 여자를 원하는지도 저렇게까지 자세히(?) 알지도 못해요. 그저 이렇게 물어보는 정도지요.
예쁘냐?
암튼, 다시 원래의 좋은 시니어 개발자 얘기로 돌아와서, 아마 그분들이 찾고 있는 좋은 시니어 개발자란 사람은 이런 사람이 아닐까 하는 생각을 합니다.
번듯한 IT기업에서 나름 인정받을 만큼 실력을 보유한, 검증된 개발자.
대기업의 프로세스를 체화하고 있어서, 스타트업에서도 바로 적용해 줄 수 있는 자.
10년 정도의 숙련된 경험으로, 갑자기 문제가 생겨도 침착하게 대응할 수 있는 사람. 나아가 문제가 생기지 않게끔 빠르고 안정적으로 개발하는 사람.
오랜 경력에 걸맞게 대인관계나 커뮤니케이션에 뛰어난 사람.
경력이 있으니 깊이 있는 기술이 있을 테고, 또 스타트업에서 일해야 하는 만큼 다양한 기술 스펙트럼을 보유하고 있는 사람. 소위 풀스택 개발자인데, 각 분야도 부족하지 않은 깊이가 있는 사람.
우리의 멋진 비전과 일치해서, 급여가 적더라도 미래의 폭발적 가능성을 보고 동기부여가 충만할 사람.
리스트 면면을 보면, 뭐 응당 그런 사람을 원하겠다는 생각이 들기도 합니다. 그러나 제가 보기엔 앞서 비유한 연애 시장에서의 기대치와 마찬가지이거나, 심지어 더 무리하게 느껴지더군요.
저런 개발자가 그 스타트업으로 이직을 원할지는 둘째 치더라도, 과연 이 세상에 존재하는지도 의문입니다. 저 정도 근처에라도 있는 개발자는, 연애시장으로 치자면 엄친아/엄친딸입니다. 20대 초절정 미녀인데, 성격까지 좋으면서 학벌도 끝내주는 뭐 그런 사람 아닐까 싶습니다.
자, 그럼 상식적으로 이런 생각이 이어집니다. “그래 좋아, 그런 20대 연예인급 미녀를, 어렵사리 30대 후반의 별 볼 일 없는 너한테 소개해줬다고 치자.”
“근데 말야, 그런 여자가 널 왜 만나야 하지?”
누구나 쉽게 할 수 있는 이런 질문과 답하기도 전에 알 수 있는 결론적 사실을, 왜 “개발자 구인”이라는 도메인으로 옮기면 새까맣게 잊게 되는 걸까요?
시니어 개발자가 기대를 충족할 부분
스타트업이 아니라 나름 안착한 IT기업에 다니는 시니어 개발자들이, 사실 어느 정도 좋은 속성들은 보유하고 있는 경우가 많기는 합니다.
예를 들어, “오랜 경력으로 문제 상황에 침착하게 대처한다.” 이런 자질은 어느 정도 기대를 걸어볼 만합니다. 장애 대응 능력 같은 것은 어디에서 책이나 구전으로 배울 수 없고, 실제 경험으로만 배울 수 있는 부분이 크기에, 그런 면에서 경력자를 우대하는 것은 인정할 만합니다. 아무리 유능한 신입도, 프로덕션에서 발생하는 문제들을 즉각 해결해야 하는 긴장된 상황 같은 영역에서는, 메꿀 수 없는 넘사벽의 틈새가 있으니까요.
그리고 원만한 대인관계나 커뮤니케이션도, 뛰어난 정도까지는 아니더라도, 적어도 같이 일하기 어려울 만큼 문제 되는 사람은 거르기 쉽습니다. 이건 큰 기업에는 그런 문제 구성원이 없다는 얘기가 아니라, 선별하기 쉽다는 뜻입니다. 한두 사람 건너건너 물어보면 분명 아는 사람을 찾을 수 있고, 레퍼런스 체크를 해보면 되니까요.
“거기 다니는 OOO 있잖아? 그 사람 어때? 일 잘해? 성격이 유난히 모나거나 문제 되진 않지?”
직원 수가 많아서 직접은 잘 모른다 하더라도, 특별히 뛰어나거나 특별히 문제 되는 사람들은 소문이 나기 마련입니다. 그래서 특별히 드러날 만큼 대인관계에 문제 되는 사람은 쉽게 걸러 낼 수 있으므로, “오랜 경력에 걸맞게 대인관계나 커뮤니케이션에 뛰어난 사람.” 이 항목도 어느 정도 충족시킬 수 있을 것입니다.
한 가지 더, “깊이가 있는 개발 실력”도 그럭저럭 기대해 볼 수 있습니다. 뭐 10년 경력이라고 해서, 다 같은 10년 경력이 아니고, 1년짜리 경력을 10번 쌓은 사람들도 많으니까 경력 다 믿지 말라고도 말하지만, 그래도, 앞에서 언급한 “인정받는 개발자”로 필터링을 마쳤다면, 어느 정도 깊이가 있을 것입니다.
시니어 개발자가 기대에 못 미치는 이유
이제 환상을 깨봅시다. 그러나 문제는, 깊이 있는 개발능력이라는 게 “개발의 넓은 스펙트럼”과는 모순된다는 것입니다. 섹시하면서 청순한 거예요. 아무래도 경력이라는 것이, 자기 잘하는 도메인으로 파고드는 쪽으로 수렴하기 쉽고, 또, 대기업의 구조상 업무의 분업이 잘 되어 있어서, 그 분업 된 업무의 자기 파트를 전문적으로 잘하는 것이지, 전반적인 일을 뛰어나게 하는 것과는 별개이기 쉽습니다. 오히려 역으로, 그런 분업화가 잘 안 된 환경에서는 제 역량의 절반도 발휘하지 못하고 힘들어할 수도 있지요.
업무 프로세스나 시스템 역시, 그 시스템을 잘 따르는 경험과 그 시스템을 만들거나 장려하는 입장의 차이는 큽니다. 마치 (저 같은) 콩글리시 코리안들이 영어를 얼추 듣거나 해석한다고 하더라도, 막상 외국인을 만나면 꿀벙어리가 되는 것과 비슷하다고 비유해 볼 수 있겠습니다. 그리고 당최, 왜 쪼끄만 몇 명 없는 스타트업에서 대기업 프로세스를 따르고자 하는지 알 수가 없습니다. 프로세스로 파생되는 단점도 있고, 또 규모에 따라 유효한 프로세스가 다를 텐데 말이죠.
마지막으로, 어쩌면, 그 시니어 개발자에게는 가장 중요한 문제일 텐데, 보상과 급여의 문제입니다. 그 대기업에서 개발 능력을 인정받으며 다니고 있는 그 20대 초절정 미녀 같은 개발자에게, 그 회사가 바보가 아닌 이상, 그 능력자에게 연봉 적게 주고 있겠습니까? 안 그래도, 평균 연봉도 높은 회사를 다니는 사람인데, 그 와중에도 탑클래스의 급여나 인센티브를 받고 있을 사람이라는 거지요.
우선, 무리해서 그 연봉 수준을 맞춰주거나, 운 좋게도 심지어 더 줄 수 있다고 하더라도, 이미 오랜 기간 대기업에 근무한 사람의 속성상, 더 안정적인 회사를 선호하기 쉽습니다. 이미 도전이나 모험을 택할 사람이라면, 진즉에 이미 모험하고 있지 않겠어요?
만약, 금수저 들고 시작하는 투자자 빵빵한 스타트업이라서, 그런 연봉 처우나 지분이나 스톡을 두둑하게 주면서 데리고 왔다고 칩시다. 이건, 20대 초절정 미녀를 어떻게든 만났는데, 몇 번의 만남 동안 허세 가득 풍기고 우아하고 고상한 능력자인 척하며 무리해서 간신히 사귀기로 한 것과 비슷하다고 볼 수 있겠습니다.
얼마나 갈 수 있나요? 그렇게 큰 금액을 월급으로 줘야 하는데, 그렇게 줄줄 불타오르며 흘러나가는 자본금을 어떻게 감당할 것이며, 지분이나 스톡으로 데려왔더라도, 행여 그 사실을 다른 적은 지분이나 스톡의 멤버가 알기라도 하면, 불 보듯 뻔한 그 불화를 어떻게 감당할 건가요?
게다가, 분명 그 인정받던 시니어 개발자도, 그 몸값만큼 가치를 당장 만들어 내지는 못할 확률이 높습니다. 큰 회사에서 개발 업무의 일부만 분업화된 환경에서 잘하는 것과, 프론트엔드 백엔드 가릴 것 없이, 심지어 기획이든 디자인이든 다 참여하고 서버 운영도 돌봐야 하는 상황은 분명 도전이고 재적응할 기간이 필요할 것입니다. 젊고 예쁘면 다 될 줄 알았는데, 새침만 떨고 뭘 할 줄 아는 게 없는 거죠.
한마디로 말해, “환상을 깨셔야 한다” 이 말씀입니다.
그럼 어떻게 해야 하나요?
당신이 큰 회사에 다니는 개발자인데, 주변에서 개발자 소개를 요청받는다면, 어지간하면 그냥 물러서는 편이 좋습니다. 열심히 알아봐서 소개해줬다고 하더라도 결렬될 확률이 훨씬 높으며, 설사 연결이 됐다고 해도, 이득 될 일은 별로 없습니다. 시간과 정력 낭비할 생각 말고, 그저 스팸 메일을 지우듯, 광고 전화를 끊어버리듯, 가볍고 무례하지 않게 상황을 재빨리 끝내시면 됩니다.
반대로, 당신이 스타트업 (코)파운더이고, 구인해야 하는 입장이라면, 감히 이런 조언을 드릴 수 있습니다. 그냥 포기하세요. 시니어 개발자 구인의 방법을 고민한다는 것 자체가 이미 그런 사람을 구할 능력이 없다는 뜻일 수 있습니다. 이미, 개발 능력자를 구할 수 있는 누군가라면, 이미 그런 사람이 주변에 모여있는 게 맞습니다. 괜히 구하기도 어려운 사람, 그리고 구해도 위험 부담이 큰 사람 찾느라 애쓰지 마시고, 이미 있는 개발자를 최대한 지원하고, 함께 성장할 환경을 만들어주며 나아가는 것이 현명합니다. 함께 일하는 지금의 주니어 개발자가 그토록 바라던 시니어 개발자가 되는 것이지요.
불굴의 스타트업 정신으로
앞에 드린 차갑고 건방진 조언이 현실적입니다만, 희박하나마, 그런 환상의 시니어 개발자를 서로에게 좋은 조건으로 채용하고, 서로 동기부여 충만해서 아름다운 창업을 이뤄낼 가능성도 없지는 않을 것입니다. 게다가, 저는 아직 스타트업을 경험해본 적이 없으니, 제 말이나 조언이 틀리다는 판단으로 도전 해보시면 될 것입니다. 그리고, 적어도, 대기업에 다니는 시니어 개발자를 구하기 힘들 것이라는 일반적 얘기이지, “개발 능력자”를 구하기 어려울 것이라는 얘기는 아니니까요.
몇몇 안되는 이유와 흔한 환상을 깨드린 것이 이 글의 전부이고, 이제 해결할 방법은 여러분의 몫일 것입니다. 불굴의 스타트업 정신으로, 그럼에도 불구하고 되게하는 힘으로 하시는 일 잘 이뤄내시길 바라겠습니다. 혹시 좋은 방법으로 이뤄내셨으면 제게도 좀 알려주세요. 저도 조만간 그런 입장으로 들어설지도 모르겠네요. 😉
그리고 결국 다 알게 되듯이
위에 웃자고 비유한, 남녀의 외모나 경제적 조건 등의 스펙(?)들은 사실 정작 연애를 하거나 평생의 배우자를 만나는 데에 (조금은 관련이 있겠지만) 가장 중요한 사항은 아닐 것입니다.
마찬가지로, 스타트업으로 이루고자 하는 일을 함께 하는 데에 있어서도, 그 시니어 개발자의 스펙이나 조건들보다 더 중요한 게 있지 않을까요?
– 끝 –
덧) 조만간 여력이 된다면, 이 글과는 정 반대되는 요지로, 대기업에 다니는 개발자인 당신이 왜 회사를 떠나야하는지를 주장하는 글도 써보려고 합니다.
이상의 글은, 반나절 신나게 휘갈겨 써서 Publish 했다가, 소심한 걱정이 들어서 Unlisted로 내렸었습니다. 혹시나 저에게 개발자 소개를 부탁했던 분들이 이 글을 읽고 맘 상해하시진 않을까 하는 걱정이 들었던 것이지요. 그런데 그 잠깐 퍼블리시된 사이에도 입소문(?)이 퍼져나갔는지 이미 조회 수가 많아졌네요. 이렇게 된 이상, 미리 오해를 풀 설명을 덧붙이며 다시 공개로 전환합니다. 그런 노파심에 덧붙이면, 그동안 저에게 개발자 소개를 진지하게든 지나가면서든 부탁했던 분이 최소 50명은 되는 것 같습니다. 그리고, 지난 글 “투자를 받지 않으려는 이유”에서도 언급한 적이 있는데, 그중에는 남부러운 Exit를 이뤄낸 멋진 로켓 스타트업 창업자도 두 명이나 있고, 해외 유명 VC에게서 투자받으며 뻗어나가고 있는 스타트업 창업자도 있습니다. 그러니, 이하에 언급한 극단적인 묘사는 본인에게 해당하지 않을 확률이 높습니다. 심지어, 엊그제 만난 대학생 스타트업 팀이 저를 그 시니어 개발자로 여기고, 시니어 개발자 구하는 방법을 알려달라고 했을 정도로 아주 흔한 일입니다. 대견한 학생팀의 열정이 부러웠을 따름이지요.