<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-5613791988833919078</id><updated>2025-08-16T17:13:40.525-07:00</updated><category term="Programming"/><category term="개발"/><category term="구글"/><category term="C"/><category term="CSP"/><category term="Communicating Sequential Processes"/><category term="android"/><category term="gnome"/><category term="gnome 3.0"/><category term="jQuery"/><category term="jqGrid"/><category term="웹프로그래밍"/><category term="C++"/><category term="Dart"/><category term="TDD"/><category term="Zeitgeist"/><category term="aes"/><category term="algebraic data type"/><category term="gnome-shell"/><category term="hacknslash"/><category term="hns"/><category term="java"/><category term="javascript"/><category term="padding"/><category term="php"/><category term="programming language"/><category term="sum type"/><category term="trac"/><category term="구글 앱스"/><category term="구글 앱스 스크립트"/><category term="대수적 자료형"/><category term="빌드툴"/><category term="안드로이드"/><category term="자바스크립트"/><category term="잡담"/><category term="프로그래밍"/><category term="프로그래밍 언어"/><title type='text'>r-search engine III</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://routitz.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5613791988833919078/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://routitz.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/5613791988833919078/posts/default?start-index=26&amp;max-results=25&amp;redirect=false'/><author><name>one-shave-man</name><uri>http://www.blogger.com/profile/03069698161893010566</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>57</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-5613791988833919078.post-5677123783649045000</id><published>2024-12-19T05:43:00.000-08:00</published><updated>2024-12-19T05:43:18.614-08:00</updated><title type='text'>CentOS Stream 10, 크롬 한글 ibus</title><content type='html'>&lt;p&gt;&amp;nbsp;GTK3, text-input-v3 설정에서 동작.&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://routitz.blogspot.com/feeds/5677123783649045000/comments/default' title='댓글'/><link rel='replies' type='text/html' href='http://routitz.blogspot.com/2024/12/centos-stream-10-ibus.html#comment-form' title='0개의 덧글'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5613791988833919078/posts/default/5677123783649045000'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5613791988833919078/posts/default/5677123783649045000'/><link rel='alternate' type='text/html' href='http://routitz.blogspot.com/2024/12/centos-stream-10-ibus.html' title='CentOS Stream 10, 크롬 한글 ibus'/><author><name>one-shave-man</name><uri>http://www.blogger.com/profile/03069698161893010566</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5613791988833919078.post-1372117184876952955</id><published>2023-11-08T10:03:00.002-08:00</published><updated>2023-11-14T19:58:43.919-08:00</updated><title type='text'>wayland 환경에서 크롬 브라우저 설정</title><content type='html'>&lt;p&gt;개인적으로 fractional scaling 때문에 wayland 가 필요하다. 특히나 두 모니터의 스케일이 다른 fractional scaling 에 필요하다.&lt;/p&gt;&lt;p&gt;fractional scaling 을 그냥 적용하고, 두 모니터의 스케일을 다르게 잡으면 크롬 브라우저의 글씨가 흐리게 나온다.&lt;/p&gt;&lt;p&gt;수정하기 위해서는 chrome://flags 에서 &#39;Preferred Ozone platform&#39; 항목을 wayland 를 지정할 수 있도록 바꿔야 한다. Auto, Wayland 등이 그것이다. 그러나 문제는 여전히 하나 또는 두 가지 남는다.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;ul style=&quot;text-align: left;&quot;&gt;&lt;li&gt;한글을 사용할 수 없다.&lt;/li&gt;&lt;li&gt;fractional scaling 을 사용하지 &lt;b&gt;않고 배율을 200%로 설정했다면&lt;/b&gt;, 여전히 글씨가 흐리게 나온다.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;ibus 를 사용할 수 없는 문제는 2023년에 해결되었다. google-chrome, google-chrome-stable 을 다음과 같은 환경변수 및 옵션과 함께 실행하는 것으로 해결할 수 있다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: IBM Plex Mono;&quot;&gt;GTK_IM_MODULE=ibus google-chrome-stable --gtk-version=4&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그리고 크롬 브라우저를 재실행하면 한글 입력이 가능하다. Fractional scaling 을 사용하지 않을 생각이라 여전히 화면이 흐리다면&amp;nbsp;--disable-features=WaylandFractionalScaleV1 설정을 추가한다. google-chrome-stable 을 실행한다면 다음과 같은 형태가 될 것이다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: IBM Plex Mono;&quot;&gt;GTK_IM_MODULE=ibus google-chrome-stable --gtk-version=4&amp;nbsp;--disable-features=WaylandFractionalScaleV1&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;.desktop 파일의 Exec 항목에 환경변수를 포함하기 위해서는 env 명령이 필요하다. 다음과 같은 형태가 된다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: IBM Plex Mono;&quot;&gt;Exec=env GTK_IM_MODULE=ibus /usr/bin/google-chrome-stable --gtk-version=4 --disable-features=WaylandFractionalScaleV1&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://routitz.blogspot.com/feeds/1372117184876952955/comments/default' title='댓글'/><link rel='replies' type='text/html' href='http://routitz.blogspot.com/2023/11/wayland.html#comment-form' title='0개의 덧글'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5613791988833919078/posts/default/1372117184876952955'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5613791988833919078/posts/default/1372117184876952955'/><link rel='alternate' type='text/html' href='http://routitz.blogspot.com/2023/11/wayland.html' title='wayland 환경에서 크롬 브라우저 설정'/><author><name>one-shave-man</name><uri>http://www.blogger.com/profile/03069698161893010566</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5613791988833919078.post-7222226496915518901</id><published>2023-08-29T00:46:00.000-07:00</published><updated>2023-08-29T00:46:32.217-07:00</updated><title type='text'>우분투 20.04 에서 터미널버전 이맥스 빌드 스크립트</title><content type='html'>&lt;pre&gt;&lt;code&gt;
sudo apt install -y autoconf make clang texinfo libgnutls28-dev \&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code&gt;pkgconf libjansson-dev &lt;/code&gt;libgccjit-9-dev zlib1g-dev gcc libxml2-dev libsqlite3-dev \&lt;/pre&gt;&lt;pre&gt;libtree-sitter-dev libgccjit-11-dev&lt;/pre&gt;&lt;pre&gt;&lt;code&gt;
./autogen.sh &amp;amp;&amp;amp; ./configure --with-native-compilation &amp;amp;&amp;amp; time make -j8
&lt;/code&gt;
&lt;/pre&gt;</content><link rel='replies' type='application/atom+xml' href='http://routitz.blogspot.com/feeds/7222226496915518901/comments/default' title='댓글'/><link rel='replies' type='text/html' href='http://routitz.blogspot.com/2021/06/2004.html#comment-form' title='0개의 덧글'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5613791988833919078/posts/default/7222226496915518901'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5613791988833919078/posts/default/7222226496915518901'/><link rel='alternate' type='text/html' href='http://routitz.blogspot.com/2021/06/2004.html' title='우분투 20.04 에서 터미널버전 이맥스 빌드 스크립트'/><author><name>one-shave-man</name><uri>http://www.blogger.com/profile/03069698161893010566</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5613791988833919078.post-6572712629848497269</id><published>2021-09-29T07:52:00.002-07:00</published><updated>2021-09-29T07:52:46.792-07:00</updated><title type='text'>Fedora 에서 이맥스 빌드시 필요한 패키지들</title><content type='html'>&lt;p&gt;sudo dnf groupinstall -y &quot;C Development Tools and Libraries&quot;&lt;/p&gt;&lt;p&gt;sudo dnf install -y texinfo gtk3-devel libXpm-devel libjpeg-turbo-devel giflib-devel gnutls-devel ncurses-devel libcanberra-gtk3 PackageKit-gtk3-module&amp;nbsp;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://routitz.blogspot.com/feeds/6572712629848497269/comments/default' title='댓글'/><link rel='replies' type='text/html' href='http://routitz.blogspot.com/2021/09/fedora.html#comment-form' title='0개의 덧글'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5613791988833919078/posts/default/6572712629848497269'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5613791988833919078/posts/default/6572712629848497269'/><link rel='alternate' type='text/html' href='http://routitz.blogspot.com/2021/09/fedora.html' title='Fedora 에서 이맥스 빌드시 필요한 패키지들'/><author><name>one-shave-man</name><uri>http://www.blogger.com/profile/03069698161893010566</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5613791988833919078.post-7308645022790761399</id><published>2020-11-03T16:44:00.004-08:00</published><updated>2021-06-30T20:05:21.169-07:00</updated><title type='text'>패키지 설치용 elisp 스크립트</title><content type='html'>&lt;pre&gt;&lt;code&gt;
; list the packages you want
(setq package-list &#39;(cyberpunk-theme flycheck yasnippet magit go-mode
				     hl-todo lsp-mode lsp-ui company))

; list the repositories containing them
(setq package-archives &#39;((&quot;elpa&quot; . &quot;http://tromey.com/elpa/&quot;)
                         (&quot;gnu&quot; . &quot;http://elpa.gnu.org/packages/&quot;)
                         (&quot;melpa&quot; . &quot;https://melpa.org/packages/&quot;)))&lt;br /&gt;
; activate all the packages (in particular autoloads)
(package-initialize)

; fetch the list of packages available 
(unless package-archive-contents
  (package-refresh-contents))

; install the missing packages
(dolist (package package-list)
  (unless (package-installed-p package)
    (package-install package)))&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;이걸 *scratch* 에 붙이고 M-x eval-buffer 로 마무리.</content><link rel='replies' type='application/atom+xml' href='http://routitz.blogspot.com/feeds/7308645022790761399/comments/default' title='댓글'/><link rel='replies' type='text/html' href='http://routitz.blogspot.com/2020/11/elisp.html#comment-form' title='0개의 덧글'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5613791988833919078/posts/default/7308645022790761399'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5613791988833919078/posts/default/7308645022790761399'/><link rel='alternate' type='text/html' href='http://routitz.blogspot.com/2020/11/elisp.html' title='패키지 설치용 elisp 스크립트'/><author><name>one-shave-man</name><uri>http://www.blogger.com/profile/03069698161893010566</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5613791988833919078.post-7279795443961685248</id><published>2020-10-06T23:42:00.001-07:00</published><updated>2020-10-06T23:42:54.135-07:00</updated><title type='text'>Cent OS 8 도커 사용하기 전 firewalld 설정.</title><content type='html'>&lt;p&gt;&amp;nbsp;firewalld 백엔드가 Cent OS 8 에서는 nftables 이고 이것이 도커와 충돌. iptables 로 수정하자.&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://routitz.blogspot.com/feeds/7279795443961685248/comments/default' title='댓글'/><link rel='replies' type='text/html' href='http://routitz.blogspot.com/2020/10/cent-os-8-firewalld.html#comment-form' title='0개의 덧글'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5613791988833919078/posts/default/7279795443961685248'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5613791988833919078/posts/default/7279795443961685248'/><link rel='alternate' type='text/html' href='http://routitz.blogspot.com/2020/10/cent-os-8-firewalld.html' title='Cent OS 8 도커 사용하기 전 firewalld 설정.'/><author><name>one-shave-man</name><uri>http://www.blogger.com/profile/03069698161893010566</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5613791988833919078.post-4949337467638967703</id><published>2020-06-15T21:04:00.002-07:00</published><updated>2020-06-15T21:04:41.170-07:00</updated><title type='text'>ssh를 통한 X forwarding</title><content type='html'>서버 측에 다음 패키지 필요&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;mesa-libGL - 없으면 크래쉬&lt;/li&gt;
&lt;li&gt;mesa-libGLw - 없으면 swrast 에러&lt;/li&gt;
&lt;li&gt;xorg-x11-xauth&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
클라이언트 측에 다음 조치 필요&lt;/div&gt;
&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;.bashrc 에 `export DISPLAY=localhost:0.0` 추가&lt;/li&gt;
&lt;li&gt;`xauth generate $DISPLAY .` 실행.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://routitz.blogspot.com/feeds/4949337467638967703/comments/default' title='댓글'/><link rel='replies' type='text/html' href='http://routitz.blogspot.com/2020/06/ssh-x-forwarding.html#comment-form' title='0개의 덧글'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5613791988833919078/posts/default/4949337467638967703'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5613791988833919078/posts/default/4949337467638967703'/><link rel='alternate' type='text/html' href='http://routitz.blogspot.com/2020/06/ssh-x-forwarding.html' title='ssh를 통한 X forwarding'/><author><name>one-shave-man</name><uri>http://www.blogger.com/profile/03069698161893010566</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5613791988833919078.post-8871614985416265145</id><published>2020-05-26T23:49:00.003-07:00</published><updated>2021-06-20T19:28:45.122-07:00</updated><title type='text'>선호하는 이맥스 설정들</title><content type='html'>&lt;pre&gt;&lt;code&gt;
(setq default-input-method &quot;korean-hangul3&quot;)
(column-number-mode t)
(show-paren-mode t)&amp;nbsp;&amp;nbsp;&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code&gt;(setq read-process-output-max (* 16 1024 1024))&lt;br /&gt;(setq gc-cons-threshold most-positive-fixnum)&lt;br /&gt;&amp;nbsp;&lt;/code&gt;&lt;/pre&gt;
</content><link rel='replies' type='application/atom+xml' href='http://routitz.blogspot.com/feeds/8871614985416265145/comments/default' title='댓글'/><link rel='replies' type='text/html' href='http://routitz.blogspot.com/2020/05/blog-post.html#comment-form' title='0개의 덧글'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5613791988833919078/posts/default/8871614985416265145'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5613791988833919078/posts/default/8871614985416265145'/><link rel='alternate' type='text/html' href='http://routitz.blogspot.com/2020/05/blog-post.html' title='선호하는 이맥스 설정들'/><author><name>one-shave-man</name><uri>http://www.blogger.com/profile/03069698161893010566</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5613791988833919078.post-2779331725277703771</id><published>2020-04-17T00:59:00.002-07:00</published><updated>2020-04-17T00:59:46.916-07:00</updated><title type='text'>emacs dart-mode 설정 구문</title><content type='html'>(setq dart-server-format-on-save t)&lt;br /&gt;
(defun isr-dart-mode-hook ()&lt;br /&gt;
&amp;nbsp; (dart-server)&lt;br /&gt;
&amp;nbsp; (lsp)&lt;br /&gt;
&amp;nbsp; (local-set-key (kbd &quot;M-*&quot;) &#39;pop-tag-mark))&lt;br /&gt;
(add-hook &#39;dart-mode-hook &#39;isr-dart-mode-hook)&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://routitz.blogspot.com/feeds/2779331725277703771/comments/default' title='댓글'/><link rel='replies' type='text/html' href='http://routitz.blogspot.com/2020/04/emacs-dart-mode.html#comment-form' title='0개의 덧글'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5613791988833919078/posts/default/2779331725277703771'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5613791988833919078/posts/default/2779331725277703771'/><link rel='alternate' type='text/html' href='http://routitz.blogspot.com/2020/04/emacs-dart-mode.html' title='emacs dart-mode 설정 구문'/><author><name>one-shave-man</name><uri>http://www.blogger.com/profile/03069698161893010566</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5613791988833919078.post-6511426460406608417</id><published>2020-03-26T22:38:00.000-07:00</published><updated>2020-03-26T22:38:01.342-07:00</updated><title type='text'>gopls 이후의 emacs 설정</title><content type='html'>&lt;div class=&quot;tr_bq&quot;&gt;
gocode는 결국 gopls로 대체. gopls 시대의 emacs 설정은&lt;/div&gt;
&lt;br /&gt;
&lt;blockquote&gt;
(defun isr-go-mode-hook ()&lt;br /&gt;&amp;nbsp; (lsp-deferred)&lt;br /&gt;&amp;nbsp; (setq lsp-idle-delay 0.500)&lt;br /&gt;&amp;nbsp; (add-hook &#39;before-save-hook #&#39;lsp-format-buffer t t)&lt;br /&gt;&amp;nbsp; (add-hook &#39;before-save-hook #&#39;lsp-organize-imports t t)&lt;br /&gt;&amp;nbsp; (local-set-key (kbd &quot;M-*&quot;) &#39;pop-tag-mark)&lt;br /&gt;&amp;nbsp; (require &#39;yasnippet)&lt;br /&gt;&amp;nbsp; (yas-minor-mode)&lt;br /&gt;&lt;span style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;(hl-todo-mode))&lt;br /&gt;(add-hook &#39;go-mode-hook &#39;isr-go-mode-hook)&lt;/blockquote&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://routitz.blogspot.com/feeds/6511426460406608417/comments/default' title='댓글'/><link rel='replies' type='text/html' href='http://routitz.blogspot.com/2020/03/gopls-emacs.html#comment-form' title='0개의 덧글'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5613791988833919078/posts/default/6511426460406608417'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5613791988833919078/posts/default/6511426460406608417'/><link rel='alternate' type='text/html' href='http://routitz.blogspot.com/2020/03/gopls-emacs.html' title='gopls 이후의 emacs 설정'/><author><name>one-shave-man</name><uri>http://www.blogger.com/profile/03069698161893010566</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5613791988833919078.post-2464676259585956834</id><published>2019-10-09T09:01:00.005-07:00</published><updated>2021-04-03T19:01:48.300-07:00</updated><title type='text'>ssh 로컬 터널링 메모</title><content type='html'>-L port:host:hostport 형태로 쓸 때,&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;port - 로컬에서의 포트&lt;/li&gt;
&lt;li&gt;host - 이 터널링을 이용할 때 호스트가 접속할 주소&lt;/li&gt;
&lt;li&gt;hostport - 이 터널링을 이용할 때 호스트가 접속할 포트&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
ssh -L 80:127.0.0.1:8080 &lt;server address=&quot;&quot;&gt;&lt;/server&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
로 터널링을 성립시킨 후&lt;/div&gt;
&lt;div&gt;
localhost:80 으로 접속하면,&lt;/div&gt;
&lt;div&gt;
server address 로 접속한 서버가 127.0.0.1:8080으로 접속한다.&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://routitz.blogspot.com/feeds/2464676259585956834/comments/default' title='댓글'/><link rel='replies' type='text/html' href='http://routitz.blogspot.com/2019/10/ssh.html#comment-form' title='0개의 덧글'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5613791988833919078/posts/default/2464676259585956834'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5613791988833919078/posts/default/2464676259585956834'/><link rel='alternate' type='text/html' href='http://routitz.blogspot.com/2019/10/ssh.html' title='ssh 로컬 터널링 메모'/><author><name>one-shave-man</name><uri>http://www.blogger.com/profile/03069698161893010566</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5613791988833919078.post-1044985242932253691</id><published>2019-04-23T02:23:00.002-07:00</published><updated>2019-10-09T17:46:15.101-07:00</updated><title type='text'>emacs Go언어 세팅</title><content type='html'>저는 IDE를 싫어하는 사람은 전혀 아닌데, Go 언어는 CLI 툴이 잘 되어 있어서 emacs로 거의 IDE에 준하는 작업흐름을 세팅할 수가 있습니다. 저는 대략 다음의 기능을 세팅합니다.&lt;br /&gt;
&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;기본적인 신택스 하일라이팅&lt;/li&gt;
&lt;li&gt;코드 포매팅 (저장시에 gofmt 실행)&lt;/li&gt;
&lt;li&gt;Go to definition 점프&lt;/li&gt;
&lt;li&gt;실시간 linting&lt;/li&gt;
&lt;li&gt;자동완성&lt;/li&gt;
&lt;li&gt;심볼 하일라이팅&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;
go-mode 신택스 하일라이팅 + 코드 포매팅&lt;/h4&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
go-mode를 깔면 됩니다. 패키지를 깔기 위해서 .emacs 파일에 다음 구절이 포함되어야 합니다.&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;pre&gt;&lt;code&gt;(require &#39;package)
(add-to-list &#39;package-archives
             &#39;(&quot;melpa&quot; . &quot;https://melpa.org/packages/&quot;))&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
go-mode를 설치합니다. 설치한 후 저장시에 자동으로 gofmt가 설정되도록 go-mode-hook에 다음과 같은 내용을 포함되도록 합니다.&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;(defun isr-go-mode-hook ()
  ...
  ;; Call Gofmt before saving                                                    
  (add-hook &#39;before-save-hook &#39;gofmt-before-save)
  ... 
(add-hook &#39;go-mode-hook &#39;isr-go-mode-hook)&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
문서 마지막에 isr-go-mode-hook 전체가 드러나는 예제가 있습니다. 여기서 조각조각 COPY&amp;amp;PASTE 하느라 고생할 필요는 없습니다.&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;
Go to definition 점프, 심볼 하일라이팅, rename&lt;/h4&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
한동안 정의/선언 지점으로 점프하는 백엔드 툴로 godef가 인기 있었습니다. 그러나 지금은 훨씬 강력한 기능을 많이 가진 go-guru에서도 이 기능을 제공하므로 godef를 굳이 깔아야 할 이유는 없다고 생각합니다. 아래는 go-guru로 정의/선언지점으로 점프하는 기능을 설정하는 방법입니다.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
go get 으로 go-guru를 설치합니다. 하는 김에 다른 유용한 툴도 설치합니다.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;pre&gt;&lt;code&gt;go get -u golang.org/x/tools/cmd/...&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
emacs에서 go-guru, go-rename 패키지를 설치합니다. 다음의 단축기 설정을 .emacs 파일에 추가합니다. Alt+&#39;.&#39;로 이동, Alt+Shift+*로 되돌아오기입니다. 문서 마지막에 .emacs 파일 전체를 실을 것이므로 여기까지 읽고 따라할 필요는 없습니다.&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;(defun isr-go-mode-hook ()
  ...
  ;; Godef jump key binding                                                      
  (local-set-key (kbd &quot;M-.&quot;) &#39;go-guru-definition)
  (local-set-key (kbd &quot;M-*&quot;) &#39;pop-tag-mark))
  ;; highlight identifiers
  (go-guru-hl-identifier-mode))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;  ...
(add-hook &#39;go-mode-hook &#39;isr-go-mode-hook)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;
flycheck (실시간 문법 체크)&lt;/h4&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;pre&gt;&lt;code&gt;&lt;span id=&quot;docs-internal-guid-3bd65497-7fff-a234-83f5-b8bde29c9725&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;arial&amp;quot;; font-size: 11pt; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;golangci-lint 를 설치합니다.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;&lt;span style=&quot;font-family: &amp;quot;arial&amp;quot;; font-size: 11pt; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;go get -u github.com/golangci/golangci-lint/cmd/golangci-lint
&lt;/pre&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
emacs의 flycheck-golangcli-lint 를 package-install 로 설치합니다. 그 후 아래의 내용을 .emacs에 추가합니다. 역시 아직 따라하지 않아도 됩니다.&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;(defun isr-go-mode-hook ()
  ...
  ;; flycheck
  (flycheck-mode)
  ...
(add-hook &#39;go-mode-hook &#39;isr-go-mode-hook)&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;
&lt;/h4&gt;
&lt;h4&gt;
compnay-go (자동완성 기능)&lt;/h4&gt;
&lt;div&gt;
&lt;br /&gt;
백엔드로 gocode를 사용하므로 설치합니다.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;pre&gt;go get -u github.com/nsf/gocode&lt;/pre&gt;
&lt;/div&gt;
&lt;br /&gt;
이맥스에서 package-install로 company-go 플러그인을 설치합니다. .emacs에 추가합니다.&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;(defun isr-go-mode-hook ()
  ...
  (require &#39;company)
  (require &#39;company-go)
  (set (make-local-variable &#39;company-backends) &#39;(company-go))
  (company-mode)
  ...
(add-hook &#39;go-mode-hook &#39;isr-go-mode-hook)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;/pre&gt;
전체 .emacs 파일을 모으면 다음과 같습니다.

&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;(require &#39;package)
(add-to-list &#39;package-archives
             &#39;(&quot;melpa&quot; . &quot;https://www.melpa.org/packages/&quot;))

(defun isr-go-mode-hook ()
  ;; flycheck
  (flycheck-mode)

  ;; Call Gofmt before saving                                                    
  (add-hook &#39;before-save-hook &#39;gofmt-before-save)

  ;; Godef jump key binding                                                      
  (local-set-key (kbd &quot;M-.&quot;) &#39;go-guru-definition)
  (local-set-key (kbd &quot;M-*&quot;) &#39;pop-tag-mark)

  ;; company-go
  (require &#39;company)
  (require &#39;company-go)
  (set (make-local-variable &#39;company-backends) &#39;(company-go))
  (company-mode)

  ;; highlight identifiers
  (go-guru-hl-identifier-mode))
(add-hook &#39;go-mode-hook &#39;isr-go-mode-hook)&lt;/code&gt;&lt;/pre&gt;
</content><link rel='replies' type='application/atom+xml' href='http://routitz.blogspot.com/feeds/1044985242932253691/comments/default' title='댓글'/><link rel='replies' type='text/html' href='http://routitz.blogspot.com/2019/04/emacs-go.html#comment-form' title='0개의 덧글'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5613791988833919078/posts/default/1044985242932253691'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5613791988833919078/posts/default/1044985242932253691'/><link rel='alternate' type='text/html' href='http://routitz.blogspot.com/2019/04/emacs-go.html' title='emacs Go언어 세팅'/><author><name>one-shave-man</name><uri>http://www.blogger.com/profile/03069698161893010566</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5613791988833919078.post-1282354182528476398</id><published>2019-01-17T16:53:00.002-08:00</published><updated>2019-01-17T16:59:53.852-08:00</updated><title type='text'>DART 언어 googleapis_auth 예제를 통해서 배운 것.</title><content type='html'>DART 언어 googleapis_auth 패키지 레포에서는 다음과 같은 사용 예제를 제시하고 있다.

&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;
import &quot;package:googleapis_auth/auth_browser.dart&quot;;

...

var id = new ClientId(&quot;....apps.googleusercontent.com&quot;, null);
var scopes = [...];

// Initialize the browser oauth2 flow functionality.
createImplicitBrowserFlow(id, scopes).then((BrowserOAuth2Flow flow) {
  flow.obtainAccessCredentialsViaUserConsent()
      .then((AccessCredentials credentials) {
    // Credentials are available in [credentials].
    ...
    flow.close();
  });
});
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
또는

&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;
import &quot;package:googleapis_auth/auth_browser.dart&quot;;

...

var id = new ClientId(&quot;....apps.googleusercontent.com&quot;, null);
var scopes = [...];

// Initialize the browser oauth2 flow functionality.
createImplicitBrowserFlow(id, scopes).then((BrowserOAuth2Flow flow) {
  flow.clientViaUserConsent().then((AuthClient client) {
    // Authenticated and auto refreshing client is available in [client].
    ...
    client.close();
    flow.close();
  });
});
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
그러면서 &lt;code&gt;obtainAccessCredentialsViaUserConsent&lt;/code&gt;, &lt;code&gt;clientViaUserConsent&lt;/code&gt; 를 호출할 때는 브라우저의 팝업 방지기능에 걸리지 않도록 event handler에서만 호출할 것을 권하는데, 나는 아래와 같은 코드로 왜 팝업 방지기능에 걸리는지 한참을 헤맸었다.&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;
&amp;lt;material-button (trigger)=&amp;quot;onClick&amp;quot;&amp;gt;Click me&amp;lt;/material-button&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;
void onClick() {
  createImplicitBrowserFlow(id, scopes).then((BrowserOAuth2Flow flow) {
    flow.clientViaUserConsent().then((AuthClient client) {
      // Authenticated and auto refreshing client is available in [client].
      ...
      client.close();
      flow.close();
    });
  });
}
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
분명히 onClick 함수 내부에서&amp;nbsp;&lt;code&gt;clientViaUserConsent&lt;/code&gt;&amp;nbsp;이 호출되는데 무엇이 문제인가? 꽤 오래 고민하다가 stackoverflow에 나와 같은데서 헤매던 사람의 질문에 대한 답을 보고 겨우 깨달았는데, 중간에 .then 문법이 끼어있다는 점이었다. async 메소드가 호출되었으니 then 이하 구절이 onClick과 같은 시점에 호출된다는 보장이 없었던 것.&lt;br /&gt;
&lt;br /&gt;
굳이 적는 이유는 이것이 만약에 async 메소드가 아니라 콜백구조였으면 아마 헤매지 않고&amp;nbsp; event handler에서 호출되지 않았다는 사실을 알았을 것이라는 점 때문이다. 내가 익숙한 방식이 낡아갈 때가 있고, 이 사건은 그걸 보여주는 것이었기 때문. 돌아가는 코드는 다음과 같은 방식이다.&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;BrowserOAuth2Flow browserOAuth2Flow = null;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;// angulardart 컴퍼넌트의 lifecycle에 따라 호출되는 메소드.&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;@override
void ngOnInit() {
  // Initialize the browser oauth2 flow functionality.
  createImplicitBrowserFlow(id, scopes).then((BrowserOAuth2Flow flow) {
    browserOAuth2Flow = flow;
  });
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;void onClick() {&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;  if (browserOAuth2Flow == null) {
    return;
  }
  browserOAuth2Flow
      .obtainAccessCredentialsViaUserConsent()
      .then((AccessCredentials credentials) {
    // Credentials are available in [credentials].
    browserOAuth2Flow.close();
    browserOAuth2Flow = null;
  });
}
&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;
&lt;code&gt;&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://routitz.blogspot.com/feeds/1282354182528476398/comments/default' title='댓글'/><link rel='replies' type='text/html' href='http://routitz.blogspot.com/2019/01/dart-googleapisauth.html#comment-form' title='0개의 덧글'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5613791988833919078/posts/default/1282354182528476398'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5613791988833919078/posts/default/1282354182528476398'/><link rel='alternate' type='text/html' href='http://routitz.blogspot.com/2019/01/dart-googleapisauth.html' title='DART 언어 googleapis_auth 예제를 통해서 배운 것.'/><author><name>one-shave-man</name><uri>http://www.blogger.com/profile/03069698161893010566</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5613791988833919078.post-715706426372444540</id><published>2018-07-13T08:22:00.001-07:00</published><updated>2018-07-13T08:22:03.357-07:00</updated><title type='text'>2018년 7월 13일자 devstack Quick Start 문서의 문제점.</title><content type='html'>&lt;a href=&quot;https://docs.openstack.org/devstack/latest/&quot;&gt;https://docs.openstack.org/devstack/latest/&lt;/a&gt;&amp;nbsp;문서의 설명에서 local.conf 파일은 HOST_IP 를 누락. localhost로 쓰면 안 되고 127.0.0.1로 써줘야 함.</content><link rel='replies' type='application/atom+xml' href='http://routitz.blogspot.com/feeds/715706426372444540/comments/default' title='댓글'/><link rel='replies' type='text/html' href='http://routitz.blogspot.com/2018/07/2018-7-13-devstack-quick-start.html#comment-form' title='0개의 덧글'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5613791988833919078/posts/default/715706426372444540'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5613791988833919078/posts/default/715706426372444540'/><link rel='alternate' type='text/html' href='http://routitz.blogspot.com/2018/07/2018-7-13-devstack-quick-start.html' title='2018년 7월 13일자 devstack Quick Start 문서의 문제점.'/><author><name>one-shave-man</name><uri>http://www.blogger.com/profile/03069698161893010566</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5613791988833919078.post-7839623834251196196</id><published>2018-06-19T04:45:00.001-07:00</published><updated>2018-06-19T05:18:54.778-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="algebraic data type"/><category scheme="http://www.blogger.com/atom/ns#" term="Programming"/><category scheme="http://www.blogger.com/atom/ns#" term="programming language"/><category scheme="http://www.blogger.com/atom/ns#" term="sum type"/><category scheme="http://www.blogger.com/atom/ns#" term="대수적 자료형"/><category scheme="http://www.blogger.com/atom/ns#" term="프로그래밍"/><category scheme="http://www.blogger.com/atom/ns#" term="프로그래밍 언어"/><title type='text'>대수적 자료형 - Algebraic Data Type </title><content type='html'>대수적 자료형(Algebraic Data Type)은 제가 &#39;모던한&#39; 언어에서 가장 지원되기를 기대하는 아이디어입니다.&lt;br /&gt;
&lt;br /&gt;
저의 근본없는 러프한 지식으로 말하자면 ADT는 결국 product type 과 sum type 을 제공한다는 의미입니다. 그런데 product type은 모던한 언어든 아니든 실용적으로 사용되는 언어는 결국 다 제공하는 셈이라서, 어떤 언어가 ADT를 제공하는가라는 문제는 사실상 어떤 언어가 sum type을 제공하는가라는 문제와 거의 같은 문제가 됩니다.&lt;br /&gt;
&lt;br /&gt;
product type은 결국 (타입이 정해진) tuple이나 record 타입입니다. 이들이 cartesian product와 유사하다는 의미에서 product type 이라는 명칭을 가지고 있습니다. 어떤 키와 타입이 대응되는 합성된 타입이죠. 다음의 예를 봅시다.&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;(int, string, double)&lt;/li&gt;
&lt;li&gt;{age:int, name:string, weight:double}&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;
(17, 김바보, 67.0), (21, 박천재, 55.0)은 모두 1에 속합니다. 그리고 index가 0이면 int형일 것이고, index가 1이면 string, index가 2이면 double형입니다. 튜플의 인덱스와 타입이 대응되서 정해져 있죠.&lt;/div&gt;
&lt;div&gt;
{age:17, name:김바보, weight:67.0}, {age:21, name:박천재, weight:55.0} 역시 age, name, weight라는 키에 따라서 정해진 타입이 정해져 있습니다.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;
C/C++/C#의 struct, C++/JAVA/C#의 클래스 등등 딱히 모던하다는 평을 받지 않는 언어로 프로그래밍을 할 때에도 product type을 활용하는 것은 어렵지 않습니다.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
문제는 sum type입니다. 제대로 된 sum type을 지원하지 않는 언어가 많았고, 지금도 저는 어떤 언어들이 sum type을 지원하는 방식은 마음에 들지 않습니다.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
그러면 어떤 sum이냐? 디지털을 다루는 사람들에게, 어떤 경우에 sum은 or를 의미하죠. sum type도 마찬가지입니다. SumTypeA 가 Type1 + Type2 라면, 타입이 SumTypeA인 변수는 Type1, Type2 둘 중의 하나가 될 수 있습니다.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
한편 sum type 을 지원하는 언어는 거의 반드시 타입 스위치에 해당하는 기능을 함께 제공됩니다. 예를 들면 switch-case 문에서 SumTypeA 변수의 타입으로 case를 나눈다면 Type1과 Type2인 경우를 모두 처리하도록 강제하는 식입니다.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
한편 이 글을 읽기 전 sum type을 모르던 분이 여기까지 읽고 enum 타입을 떠올리셨다면 올바른 방향을 잡으신 겁니다. enum은 sum type의 특수한 형태죠. 그럼 더 일반적인(general한) sum type은 무엇을 할 수 있느냐? 이진트리구조를 다음과 같이 나타낼 수 있습니다.&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;type Tree =&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&amp;nbsp; | Leaf&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&amp;nbsp; | Node of value: int * left: Tree * right: Tree&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
위의 언어는 F#이고 저는 F#을 할 줄 모르고 위키에서 퍼 온 예제입니다. :-) 위의 타입으로 실제 변수를 만들어서 할당하는 코드는 아래와 같다고 합니다.&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;let tree = Node(5, Node(1, Leaf, Leaf), Node(3, Leaf, Node(4, Leaf, Leaf)))&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
F#은 모릅니다만 Node (int, Tree, Tree) 를 최상단으로 놓고 시작해서 Tree 자리에 Node (int, Tree, Tree) 와 Leaf 중에 하나를 택해 치환하는 방식으로 확장되었다는 점은 알아볼 수 있겠습니다. 위의 F# 코드는 아래의 트리를 묘사하는 것이지요.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;img alt=&quot;The tree produced by the above constructors&quot; src=&quot;https://upload.wikimedia.org/wikipedia/commons/thumb/7/73/Tagged_union_tree.svg/200px-Tagged_union_tree.svg.png&quot; /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
그럼 sum type이 없을 때와 비교해서 위의 코드가 무엇이 나은가?&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
자바로 같은 일을 하는 코드를 짠다면 Tree라는 자료구조를 보여주는 타입은 등장하지 않는 경우가 보통일 겁니다. (저는 사실 그렇게 할 수 있는 방법을 잘 모르겠습니다.) Tree라는 이름을 클래스 이름으로 쓸 수는 있는데, 실제로 그 클래스가 나타내는 것은 트리가 아니라 노드일 겁니다.&lt;br /&gt;
&lt;br /&gt;
자바에서 노드가 트리가 되는 과정은 타입 자체에 나타나지 않습니다. 따로 자료구조를 공부하거나, 아니면 예제코드를 보면서 이해해야 합니다. 그런데 그 예제코드는 어떤 형태일까요?&lt;br /&gt;
&lt;br /&gt;
위의 F# 코드는 declarative합니다. 타입 선언이니까요. 그리고 recursive한 타입이죠. 위의 재귀적 타입을 expand 하는 것은 훈련되지 않았을 때 쉽기만 한 일은 아닙니다만, 그 문턱을 넘을 수 있다면 타입 자체에 자료형이 이미 설명되어 있습니다.&lt;br /&gt;
&lt;br /&gt;
그러나 자바 코드라면 operation일 겁니다. right와 left에 null이나 아니면 다른 노드를 assign하는 &#39;동작&#39;이 들어갑니다. 그 과정을 머리로 굴리면서 이해해야 하는 것이죠.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
BNF로 정의된 문법의 파서를 만드는 경우라면 어떨까요? sum type은 abstract syntax를 만드는 데 큰 도움이 된다고 합니다. BNF의 | 기호를 처리하기에 sum type만한 것이 있을 것 같지는 않군요. 아래는 하스켈 코드라고 합니다.&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;data Expression = Number Int&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; | Add Expression Expression&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; | Minus Expression Expression&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; | Mult Expression Expression&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; | Divide Expression Expression&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
모든 경우의 수를 처리했는지 여부를 컴파일러가 도와주므로, AST를 처리하는 과정 역시 비지터 패턴 코드보다 훨씬 즐거울 겁니다.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
다만 저는 kotlin과 scala의 sealed type 형태로 구현된 sum type은 좋아하지 않습니다.&amp;nbsp; 이 두 언어의 sum type은 결국 A는 A1 또는 A2라는 관계를 상속을 통한 polymorphism으로 처리합니다. 원래의 sum type에는 없었던, 공동의 부모를 가져야 한다는 불필요한 제약이 생기는 거죠. :-/ sum type의 제한된 형태인 enum을 확장시키는 방향으로 접근해서 생기는 한계가 아닐까 싶은데 그런 식으로 구현한 이유는 잘 모르겠습니다. JVM의 한계일까요? :-(&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://routitz.blogspot.com/feeds/7839623834251196196/comments/default' title='댓글'/><link rel='replies' type='text/html' href='http://routitz.blogspot.com/2018/06/algebraic-data-type.html#comment-form' title='0개의 덧글'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5613791988833919078/posts/default/7839623834251196196'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5613791988833919078/posts/default/7839623834251196196'/><link rel='alternate' type='text/html' href='http://routitz.blogspot.com/2018/06/algebraic-data-type.html' title='대수적 자료형 - Algebraic Data Type '/><author><name>one-shave-man</name><uri>http://www.blogger.com/profile/03069698161893010566</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5613791988833919078.post-449345029466336896</id><published>2018-05-04T15:56:00.002-07:00</published><updated>2018-05-04T15:57:20.718-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="구글"/><title type='text'>Google IO 2018에서 몇 가지 키워드별 행사 개수</title><content type='html'>&lt;table&gt;
  &lt;tbody&gt;
&lt;tr&gt;
    &lt;td&gt;클라우드&lt;/td&gt;
    &lt;td&gt;33&lt;/td&gt;
  &lt;/tr&gt;
&lt;tr&gt;
    &lt;td&gt;Flutter&lt;/td&gt;
    &lt;td&gt;11&lt;/td&gt;
  &lt;/tr&gt;
&lt;tr&gt;
    &lt;td&gt;머신러닝&lt;/td&gt;
    &lt;td&gt;26&lt;/td&gt;
  &lt;/tr&gt;
&lt;tr&gt;
    &lt;td&gt;안드로이드&amp;amp;플레이&lt;/td&gt;
    &lt;td&gt;50개 이상&lt;/td&gt;
  &lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
&lt;div&gt;
이렇게 보면 Flutter에 뭐 있나 싶기도 하지만 이제 베타에 불과한 Flutter가 19개의 (그 중 하나는 misc) 필터링 키워드 중 하나에 올랐다는 사실만 해도 의욕적인 행보라고 생각됩니다.&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://routitz.blogspot.com/feeds/449345029466336896/comments/default' title='댓글'/><link rel='replies' type='text/html' href='http://routitz.blogspot.com/2018/05/google-io-2018.html#comment-form' title='0개의 덧글'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5613791988833919078/posts/default/449345029466336896'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5613791988833919078/posts/default/449345029466336896'/><link rel='alternate' type='text/html' href='http://routitz.blogspot.com/2018/05/google-io-2018.html' title='Google IO 2018에서 몇 가지 키워드별 행사 개수'/><author><name>one-shave-man</name><uri>http://www.blogger.com/profile/03069698161893010566</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total><georss:featurename>대한민국</georss:featurename><georss:point>35.907757 127.76692200000002</georss:point><georss:box>29.322492499999996 117.43977350000003 42.4930215 138.09407050000002</georss:box></entry><entry><id>tag:blogger.com,1999:blog-5613791988833919078.post-3064220561386819514</id><published>2018-04-27T05:32:00.000-07:00</published><updated>2018-04-27T05:32:07.023-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="android"/><category scheme="http://www.blogger.com/atom/ns#" term="Dart"/><category scheme="http://www.blogger.com/atom/ns#" term="개발"/><category scheme="http://www.blogger.com/atom/ns#" term="구글"/><category scheme="http://www.blogger.com/atom/ns#" term="웹프로그래밍"/><title type='text'>Flutter는 커다란 한 수</title><content type='html'>최근 Dart와 Typescript 중에 하나를 선택하려고 깊은 고심을 하다가 결국 TS를 골랐습니다. 일단 저는 상당히 친 구글 성향인데, 그럼에도 불구하고 한 가지 프레임웍이 없었다면 고민 자체를 하지 않고 TS를 선택했을 겁니다. 그 프레임웍이 Flutter죠.&lt;br /&gt;
&lt;br /&gt;
Flutter는 다트로 한 번 프로그래밍해서 Android와 iOS용 앱을 모두 빌드할 수 있는 프레임웍입니다. 웹앱과 두 가지 모바일 앱을 언어 하나로 모두 개발할 수 있다는 점이 큰 장점으로 다가왔지만, 결국 당장 필요한 웹앱개발의 여건에 TS가 너무나 압도적이라는 판단을 내렸습니다.&lt;br /&gt;
&lt;br /&gt;
Flutter는 리눅스 환경에서는 데스크탑 앱으로도 빌드할 수 있으며 Fuchsia도 Flutter로 UX 작업을 한다고 하니, 구글이 바라보는 Dart는 모든 환경의 클라이언트를 작성하는 언어일 수도 있겠다 싶습니다. 그 목적이 이미 달성되었다면 Dart도 꽤나 매력적인 언어였을 수 있겠다 싶습니다.&lt;br /&gt;
&lt;br /&gt;
문제는 아직 그 때가 아니라는 점이죠 :-/</content><link rel='replies' type='application/atom+xml' href='http://routitz.blogspot.com/feeds/3064220561386819514/comments/default' title='댓글'/><link rel='replies' type='text/html' href='http://routitz.blogspot.com/2018/04/flutter.html#comment-form' title='0개의 덧글'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5613791988833919078/posts/default/3064220561386819514'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5613791988833919078/posts/default/3064220561386819514'/><link rel='alternate' type='text/html' href='http://routitz.blogspot.com/2018/04/flutter.html' title='Flutter는 커다란 한 수'/><author><name>one-shave-man</name><uri>http://www.blogger.com/profile/03069698161893010566</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5613791988833919078.post-3395403370551005145</id><published>2018-04-24T07:22:00.003-07:00</published><updated>2018-04-24T07:23:43.491-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="잡담"/><title type='text'>개인 프로젝트를 하지 못하는 이유</title><content type='html'>개인프로젝트는 결국 &#39;내가 쓰고 싶어서&#39; 라는 동기가 필요.&lt;br /&gt;
&lt;br /&gt;
내가 쓰려면 결국 웹, 데탑앱 또는 모바일인데 나는 데탑을 주로 리눅스를 쓰므로 저기서 데탑은 리눅스 환경.&lt;br /&gt;
&lt;br /&gt;
또 한 가지는, 개인프로젝트는 돈 받고 하는 것이 아니므로 열받는 것이 없어야 함. 열받는 것이 없음이라 함은 아래의 조건 중에 걸리는 것이 없거나 적어야 한다는 의미.&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;언어 자체가 괜찮을 것&lt;/li&gt;
&lt;li&gt;IDE 나 언어의 툴이 왠만큼 갖추어져 있을 것&lt;/li&gt;
&lt;li&gt;IDE 와 코드의 정적분석툴이 잘 갖추어지려면 결국 정적타입 언어일 수밖에 없음&lt;/li&gt;
&lt;li&gt;문서를 포함한 프레임웍이 갖추어져 있을 것&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
이래저래 적어도 몇 군데는 꼭 걸림.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;vala - 언어는 나쁘지 않은데 IDE 가 없음&lt;/li&gt;
&lt;li&gt;C - 2018년에 응용앱 짜는 데 C... 논할 가치가 없음&lt;/li&gt;
&lt;li&gt;C++ - 언어 자체를 싫어함. 스펙 두꺼운 언어를 제일 싫어함&lt;/li&gt;
&lt;li&gt;JavaScript - 정적타입이 아니고.. JavaScript horrible language 가 자동완성으로 뜸&lt;/li&gt;
&lt;li&gt;Dart - 진짜 다른 점 다 괜찮은데 망한 언어&lt;/li&gt;
&lt;li&gt;Go - 언어는 괜찮은데 GUI 프레임웍이 없음&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
결국 개인프로젝트는 못 하는 걸로.. 이 상태가 몇 년 째&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://routitz.blogspot.com/feeds/3395403370551005145/comments/default' title='댓글'/><link rel='replies' type='text/html' href='http://routitz.blogspot.com/2018/04/blog-post.html#comment-form' title='0개의 덧글'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5613791988833919078/posts/default/3395403370551005145'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5613791988833919078/posts/default/3395403370551005145'/><link rel='alternate' type='text/html' href='http://routitz.blogspot.com/2018/04/blog-post.html' title='개인 프로젝트를 하지 못하는 이유'/><author><name>one-shave-man</name><uri>http://www.blogger.com/profile/03069698161893010566</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total><georss:featurename>대한민국</georss:featurename><georss:point>35.907757 127.76692200000002</georss:point><georss:box>29.322492499999996 117.43977350000003 42.4930215 138.09407050000002</georss:box></entry><entry><id>tag:blogger.com,1999:blog-5613791988833919078.post-4932227331007242214</id><published>2018-04-24T01:33:00.003-07:00</published><updated>2018-04-24T01:33:26.378-07:00</updated><title type='text'>DART 언어</title><content type='html'>angular component, flutter 는 매력적. 언어 하나를 배워서 웹앱과 준 네이티브 모바일 앱을 만들 수 있다는 것은 큰 장점.&lt;br /&gt;
&lt;br /&gt;
그러나 무슨 짓을 해도 떠오르지 않는 인기가 문제인데..&lt;br /&gt;
&lt;br /&gt;
일단 개인프로젝트에 써보려는 중.</content><link rel='replies' type='application/atom+xml' href='http://routitz.blogspot.com/feeds/4932227331007242214/comments/default' title='댓글'/><link rel='replies' type='text/html' href='http://routitz.blogspot.com/2018/04/dart.html#comment-form' title='0개의 덧글'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5613791988833919078/posts/default/4932227331007242214'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5613791988833919078/posts/default/4932227331007242214'/><link rel='alternate' type='text/html' href='http://routitz.blogspot.com/2018/04/dart.html' title='DART 언어'/><author><name>one-shave-man</name><uri>http://www.blogger.com/profile/03069698161893010566</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5613791988833919078.post-672513506644020851</id><published>2018-04-11T03:56:00.002-07:00</published><updated>2018-04-24T01:34:23.004-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="C"/><category scheme="http://www.blogger.com/atom/ns#" term="개발"/><title type='text'>GCC와 Clang의 RAII</title><content type='html'>GLib 코딩을 하다가 g_autoptr() 이라는 매크로가 보이길래, C로 또 무슨 흑마술을 부렸나 살펴봤더니 RAII (&lt;a href=&quot;https://en.wikipedia.org/wiki/Resource_acquisition_is_initialization&quot;&gt;Resource acquisition is initialization&lt;/a&gt;) 기법을 가능하게 하는 확장이 생겼습니다. cleanup 이라는 이름의 확장입니다. 다음과 같은 형태로 쓸 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;void clean_up(int *final_value)
{
  printf(&quot;Cleaning up\n&quot;);
  printf(&quot;Final value: %d\n&quot;,*final_value);

}

int main(int argc, char **argv)
{
  /* declare cleanup attribute along with initiliazation
     Without the cleanup attribute, this is equivalent 
     to:
     int avar = 1;
  */
  
  int avar __attribute__ ((__cleanup__(clean_up))) = 1;
  avar = 5;

  return 0;
}
&lt;/pre&gt;
다음에는 간단한 ref count 시스템을 만들어봐야겠군요 :-)</content><link rel='replies' type='application/atom+xml' href='http://routitz.blogspot.com/feeds/672513506644020851/comments/default' title='댓글'/><link rel='replies' type='text/html' href='http://routitz.blogspot.com/2018/04/gcc-clang-raii.html#comment-form' title='0개의 덧글'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5613791988833919078/posts/default/672513506644020851'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5613791988833919078/posts/default/672513506644020851'/><link rel='alternate' type='text/html' href='http://routitz.blogspot.com/2018/04/gcc-clang-raii.html' title='GCC와 Clang의 RAII'/><author><name>one-shave-man</name><uri>http://www.blogger.com/profile/03069698161893010566</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5613791988833919078.post-4103905906189388827</id><published>2016-04-26T06:03:00.001-07:00</published><updated>2016-04-26T06:06:26.894-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Programming"/><category scheme="http://www.blogger.com/atom/ns#" term="TDD"/><title type='text'>Mocks Aren&#39;t Stubs</title><content type='html'>&lt;br /&gt;
&lt;br /&gt;
마틴 파울러의 Mocks Aren&#39;t Stubs라는 글 소개. 이전에 사내에서 메일로 보냈던 글&lt;br /&gt;
-----------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;
Mocks aren&#39;t stubs 라는 제목의 마틴 파울러의 에세이를 요약해보았습니다.&lt;br /&gt;
&lt;a href=&quot;http://martinfowler.com/articles/mocksArentStubs.html&quot;&gt;http://martinfowler.com/articles/mocksArentStubs.html&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
마틴 파울러는 이 에세이에서 테스트 목적으로 진짜 객체 대신에 사용하는 객체들을 부르는 이름으로 Gerard Meszaros 가 사용한 용어를 따라 &quot;테스트 더블&quot;을 사용합니다. &quot;스턴트 더블&quot;을 응용한 이름입니다.&lt;br /&gt;
&lt;br /&gt;
테스트 더블의 대표적인 사례로 다음을 들고 있고 각각을 다음과 같이 설명합니니다.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;dummy - 전달은 되지만 실제로는 사용되지 않는 객체. 보통은 함수 파라메터를 채우는 때 사용됩니다.&lt;/li&gt;
&lt;li&gt;fake - 실제로 동작하는 구현을 포함하고 있지만 지름길들을 이용하고 있고 상업적 용도로 사용할만한 구현은 아닌 것. 메모리 DB를 예로 들고 있습니다.&lt;/li&gt;
&lt;li&gt;stub - 테스트 도중에 예상되는 값을 반환할 수 있도록 만들어져서 다른 결과값은 주지 못하는 객체입니다.&lt;/li&gt;
&lt;li&gt;mock - 이 에세이에서 중점적으로 설명하고 있는 대상입니다. &quot;제목은 mock은 stub이 아니다&quot; 이지만 실제로는 mock과 mock이 아닌 것으로 나눠서 설명하는 형태에 가깝습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;br /&gt;
다른 세 가지의 test double과 비교해서 mock은 확연하게 구분되는 특성이 있는데, 그것은 state를 예측할뿐만 아니라 behavior도 예측한다는 것입니다. 테스트 도중에 email을 보내는 내용을 포함하는 클래스를 test double로 대체한 다음의 코드에서 이것을 볼 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
아래는 stub을 이용할 때의 테스트 코드입니다. 주문을 받고 창고에 재고를 확인하고, 부족한 경우에 이메일을 발송하는 과정을 테스트하는 코드입니다. 자바로 작성되어 있습니다.&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;
class OrderStateTester...
  public void testOrderSendsMailIfUnfilled() {
    Order order = new Order(TALISKER, 51);
    MailServiceStub mailer = new MailServiceStub();
    order.setMailer(mailer);
    order.fill(warehouse);
    assertEquals(1, mailer.numberSent());
  }

...

}&lt;/code&gt;&lt;/pre&gt;
MailService 클래스의 numberSent를 호출해서. 내부의 값, state를 확인합니다. 반면에 mock을 이용하는 테스트는 다음과 같습니다.



&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;
class OrderInteractionTester...
  public void testOrderSendsMailIfUnfilled() {
    Order order = new Order(TALISKER, 51);
    Mock warehouse = mock(Warehouse.class);
    Mock mailer = mock(MailService.class);
    order.setMailer((MailService) mailer.proxy());

    mailer.expects(once()).method(&quot;send&quot;);
    warehouse.expects(once()).method(&quot;hasInventory&quot;)
      .withAnyArguments()
      .will(returnValue(false));

    order.fill((Warehouse) warehouse.proxy());
  }

...

}&lt;/code&gt;&lt;/pre&gt;
Mock을 이용할 때는 mailer.expects(once()).method(&quot;send&quot;) 라는 코드를 통하여, 상태값이 아니라 send라는 메소드가 호출되는 동작을 예상하고 이것의 일치 여부를 확인하는 것을 볼 수 있습니다.



이렇게 state의 값이 아니라 behavior를 예상하는 mock 객체의 활용은 BDD(Behavior Driven Development)로 이어집니다.





더 자세한 내용을 알고 싶으시면 서두에 첨부한 마틴 파울러의 에세이를 직접 읽어보시면 좋을 것으로 생각됩니다. 감사합니다.&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://routitz.blogspot.com/feeds/4103905906189388827/comments/default' title='댓글'/><link rel='replies' type='text/html' href='http://routitz.blogspot.com/2016/04/mocks-arent-stubs.html#comment-form' title='0개의 덧글'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5613791988833919078/posts/default/4103905906189388827'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5613791988833919078/posts/default/4103905906189388827'/><link rel='alternate' type='text/html' href='http://routitz.blogspot.com/2016/04/mocks-arent-stubs.html' title='Mocks Aren&#39;t Stubs'/><author><name>one-shave-man</name><uri>http://www.blogger.com/profile/03069698161893010566</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5613791988833919078.post-2163652669698828826</id><published>2016-04-19T04:51:00.001-07:00</published><updated>2016-04-26T06:07:09.171-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Communicating Sequential Processes"/><category scheme="http://www.blogger.com/atom/ns#" term="CSP"/><category scheme="http://www.blogger.com/atom/ns#" term="Programming"/><title type='text'>CSP란 무엇인가?</title><content type='html'>&lt;div&gt;
Communicating Sequential Processes 가 무엇인가? 무엇때문에 내가 관심을 가지고 있고 무엇을 기대하고 있는가에 대한 간단한 소개.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;a href=&quot;https://en.wikipedia.org/wiki/Communicating_sequential_processes&quot;&gt;위키피디아&lt;/a&gt;에서는 CSP를 다음과 같이 소개하고 있다.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
In computer science, communicating sequential processes (CSP) is a formal language for describing patterns of interaction in concurrent systems. It is a member of the family of mathematical theories of concurrency known as process algebras, or process calculi, based on message passing via channels.&lt;/blockquote&gt;
&lt;br /&gt;
bullet item으로 만들어보면,&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;formal language&lt;/li&gt;
&lt;li&gt;describing patterns of interaction in concurrent systems.&lt;/li&gt;
&lt;li&gt;process algebras, process calcui&lt;/li&gt;
&lt;li&gt;based on message passing via channels.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
CSP 로 기술할 수 있는 세계는 동시성을 가진 object 들이 message passing 방식으로 커뮤니케이션하는 세계이다. CSP는 이러한 상황을 formal language 로 묘사할 수 있게 해준다.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
다른 한편으로는 이것은 process algebra 를 가능하게 한다. 어떤 시스템에서 데드락이 발생한다/하지 않는다와 같은 판정을 수식으로 풀어서 증명할 수 있게 해주는 도구가 된다.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
만약에 CSP에 충실한 언어가 있다면, 동시성이 발생하는 어떤 시스템을 CSP로 기술하고, 거기서부터 시작해서 수학적으로 문제가 발생할 소지가 있는지를 검증한 후, 이것을 프로그래밍 코드로 전환할 수 있을 것이다. Go, OCAML 등이&amp;nbsp;CSP에 강한 영향을 받은 언어로 wikipedia에 이름을 올리고 있다.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
이러한 접근이 흥미롭게 들린다면 이 책은 읽어볼만한 가치가 있을 것이다.&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://routitz.blogspot.com/feeds/2163652669698828826/comments/default' title='댓글'/><link rel='replies' type='text/html' href='http://routitz.blogspot.com/2016/04/csp.html#comment-form' title='0개의 덧글'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5613791988833919078/posts/default/2163652669698828826'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5613791988833919078/posts/default/2163652669698828826'/><link rel='alternate' type='text/html' href='http://routitz.blogspot.com/2016/04/csp.html' title='CSP란 무엇인가?'/><author><name>one-shave-man</name><uri>http://www.blogger.com/profile/03069698161893010566</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5613791988833919078.post-5956157379853318768</id><published>2016-04-18T23:22:00.002-07:00</published><updated>2016-04-26T06:06:52.031-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Communicating Sequential Processes"/><category scheme="http://www.blogger.com/atom/ns#" term="CSP"/><category scheme="http://www.blogger.com/atom/ns#" term="Programming"/><title type='text'>종종 CSP(Communicating Sequential Process)에 대한 글을 올리도록 하겠습니다.</title><content type='html'>공부를 열심히 하기 위한 동기부여로 공약을 내거는 방법을 택했습니다. 열심히 해보겠습니다.</content><link rel='replies' type='application/atom+xml' href='http://routitz.blogspot.com/feeds/5956157379853318768/comments/default' title='댓글'/><link rel='replies' type='text/html' href='http://routitz.blogspot.com/2016/04/cspcommunicating-sequential-process.html#comment-form' title='0개의 덧글'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5613791988833919078/posts/default/5956157379853318768'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5613791988833919078/posts/default/5956157379853318768'/><link rel='alternate' type='text/html' href='http://routitz.blogspot.com/2016/04/cspcommunicating-sequential-process.html' title='종종 CSP(Communicating Sequential Process)에 대한 글을 올리도록 하겠습니다.'/><author><name>one-shave-man</name><uri>http://www.blogger.com/profile/03069698161893010566</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5613791988833919078.post-6337178595412696076</id><published>2015-06-26T03:46:00.002-07:00</published><updated>2015-06-26T03:50:21.814-07:00</updated><title type='text'>초심자의 첫번째 언어</title><content type='html'>코딩 초심자의 첫 번째 언어로는 크게 두 가지 의견이 대립한다고 생각한다. 첫 번째는 C이고, 다른 하나는 해당 시기의 패러다임을 대표하는 적당한 하이레벨 언어이다. 이 둘은 각각 다른 전제를 깔고 있다.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
C를 첫 번째 언어로 가르치자는 주장은 컴퓨터가 결국 상당히 오랜 기간동안 노이만 머신이나 그와 유사한 형태의 기계일 것이라는 가정을 깔고 있다.&lt;br /&gt;
&lt;br /&gt;
C의 로우레벨함에 진저리를 내는 사람도 많지만, 어쨌거나 C는 어셈블러 코딩을 피하기 위한 언어로 일정 정도의 추상화를 제공하기 위해서 등장한 언어였고 등장할 당시에는 어셈블러에 비해 30%의 오버헤드를 떠안은 상태로 성공적인 OS 프로그래밍을 할 수 없으리라고 여겨지기도 했다.&lt;br /&gt;
&lt;br /&gt;
그렇다면 C는 구체적인 CPU 아키텍쳐를 감추고 무엇을 공통요소로 추출해서 무엇으로 추상화하는가? 나는 그것이 결국 노이만 머신이라고 생각한다. C언어를 통해서 바라본 컴퓨터는 각 리소스가 메모리 주소로서 접근되고 그것을 처리하는 장치가 있는 장치이다.&lt;br /&gt;
&lt;br /&gt;
이 가정이 C언어를 첫 언어로 가르치자는 주장을 정당화하는지 여부를 평가하자면 크게 두 가지를 평가해야 한다고 본다. 한 가지는 이 가정이 현실에 부합하는가, 그리고 다른 한 가지는 그것이 사실이라면 유의미한가.&lt;br /&gt;
&lt;br /&gt;
나는 가정이 현실에 부합한다고 본다. 굳이 C언어를 가르쳐야 하느냐는 의문과 함께 cs101 언어로 자바, 파이썬 등이 채택되는 동안, 여전히 우리의 컴퓨터는 노이만 머신에 기반한 구조를 가지고 있다.&lt;br /&gt;
&lt;br /&gt;
문제는 이 사실이 유의미하느냐는 문제이다. &quot;컴퓨터는 노이만 머신에 기반한 구조를 가지고 있고 C언어는 이에 가깝다. 그런데 그래서 그게 뭐?&quot; 라는 질문은 첫 번째 질문에 대한 대답보다 확신에 차서 대답하기는 힘들다.&lt;br /&gt;
&lt;br /&gt;
컴퓨터의 동작 원리를 이해하기 위해서 C언어를 가르쳐야 한다면 정말로 그것으로 설명이 되는가? C언어를 배운다고 해서 아키텍쳐와 OS 과목에서 가르치는 원리들 - 메모리 로컬리티와 작업 내용이 캐쉬 위에 올라가느냐 또는 분기 예측의 성공과 실패 여부가 속도에 미치는 영향, 가상 메모리와 페이징 및 메모리의 파편화, 쓰래슁 등을 이해할 수 있는가? 이런 로우레벨한 문제를 고려한 코드를 짜는 데 C언어로 코딩을 배우는 것이 도움이 되는가? 실상 생각해보면 별 도움이 되지 않는다. C언어로 메모리를 수동관리해가면서 코드를 짜는 것은, 로우레벨한 문제의 상당히 한정된 일부를 다뤄보는 데 그칠 뿐이다.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
두 번째 입장, 적절한 하이레벨 언어로 코딩을 가르치자는 입장은 computational thinking 이라고 부르는 어떤 정신을 심어주는 것이 핵심적인 문제이고 로우레벨한 문제는 이것을 가능하게 하는 수단이지 그 자체가 목적이 아니라는 입장이라고 요약하고자 한다. 또한 위에서 언급한대로, 실상 로우레벨한 문제는 그 자체로 배워야 할 거리들을 형성하고 있어서, &quot;노이만 머신으로 추상화한 언어&quot;인 C언어에서는 이미 다룰 수 없는 부분을 많이 가지고 있다. 그건 C언어로 코딩을 배운다고 해결될 문제가 아니라, 그 자체로 따로 배워야 할 문제이다.&lt;br /&gt;
&lt;br /&gt;
이런 주장에 대해서 내가 가진 의구심은, 지금까지 관찰되어온 바에 의하면 코드를 다른 어떤 것으로 추상화한 것보다는 노이만 머신으로 추상화한 것이 더 오랫동안 유효했다는 점이다. lisp의 역사는 사실은 C보다도 길고, 각종 사물에 대한 메타포로 코딩하는 OOP에 대한 열광도 이제 조금은 식은 이 시점에, 자바같은 극단적으로 명사(noun)적인 사고를 강요하는 언어가 장기적으로 도움이 되었을까, 함수형 패러다임은 과연 컴퓨터가 노이만 머신에서 멀어질 때까지 유효할까 등에 의문을 가지게 된다.&lt;br /&gt;
&lt;br /&gt;
여전히 컴퓨터는 노이만 머신에 가까운 구조로 되어 있고, 이 사실은 적어도 어떤 영역에서 작업을 하는 사람들에게는 중요하다. 위에 언급한 &#39;어차피 따로 배워야 하는 로우레벨한 영역에 대한 지식들&#39;도 사실 노이만 구조를 이해할 때 더 쉽게 이해할 수 있다.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
이 둘 사이에서 나는 어떤 강한 의견을 가지고 있지는 않고 양자를 다 부분 긍정하면서 관전할 뿐이다.&lt;br /&gt;
&lt;br /&gt;
다만 이런 관점에서, 첫 번째 언어로 무엇을 택해야 한다는 것은 없지만 받아들일 수 없는 언어들은 있다.&lt;br /&gt;
&lt;br /&gt;
C++은 추상화되지도 않았고 딱히 노이만 머신으로 추상화하는 언어도 아니어서 둘 모두에 속하지 않고, js를 가르친다면 차라리 함수의 first class citizen 특성을 부각시켜서 가르치는 게 맞지 로우레벨 접근 안 되는 C로 가르치는 것은 반대이다.&lt;br /&gt;
&lt;br /&gt;
결국 전형적인 내 입장이 되고 만다. 꼭 이것이어야 한다는 것은 없다, 이것은 용납 불가능하다는 목록은 있다.</content><link rel='replies' type='application/atom+xml' href='http://routitz.blogspot.com/feeds/6337178595412696076/comments/default' title='댓글'/><link rel='replies' type='text/html' href='http://routitz.blogspot.com/2015/06/blog-post.html#comment-form' title='0개의 덧글'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5613791988833919078/posts/default/6337178595412696076'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5613791988833919078/posts/default/6337178595412696076'/><link rel='alternate' type='text/html' href='http://routitz.blogspot.com/2015/06/blog-post.html' title='초심자의 첫번째 언어'/><author><name>one-shave-man</name><uri>http://www.blogger.com/profile/03069698161893010566</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5613791988833919078.post-4557366587642890</id><published>2015-02-01T23:48:00.003-08:00</published><updated>2018-04-24T01:33:56.855-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="C"/><category scheme="http://www.blogger.com/atom/ns#" term="C++"/><category scheme="http://www.blogger.com/atom/ns#" term="개발"/><category scheme="http://www.blogger.com/atom/ns#" term="빌드툴"/><title type='text'>리눅스상 C/C++ 빌드툴 정리.</title><content type='html'>&quot;빌드툴이 무엇이다&quot; 라는 것까지는 알고 있는 사람들을 대상으로 리눅스 환경에서 고려될만한 빌드툴들을 가벼운 마음으로 경험상 비교한 것.&lt;br /&gt;
&lt;br /&gt;
크게 보면 다음 세 가지 카테고리로 먼저 분류를 하게 된다.&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;직접 cc 명령어로 컴파일하고 링크함. 예제파일 이상의 수준에서 쓸 일 없음.&lt;/li&gt;
&lt;li&gt;Makefile을 작성하고 make 명령어로 1을 수행함.&lt;/li&gt;
&lt;li&gt;Makefile을 만들어주는 프로그램(예-autotools)을 이용해서 2→1을 수행함.&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://www.blogger.com/blogger.g?blogID=5613791988833919078&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYwHhNAxYWXFNK9gv-sr2s44WG7bU9hW0gJJC_A1i1DmrEsFnlGzicc1KusB2_vQM9KTB-g2OV1FnpxJ6plTktOF__4FQzAngRr50rRZFSyHNUyzejS7gRwMqBmF3zOnETiAZx6WqcxYxT/s1600/build-fig.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;207&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYwHhNAxYWXFNK9gv-sr2s44WG7bU9hW0gJJC_A1i1DmrEsFnlGzicc1KusB2_vQM9KTB-g2OV1FnpxJ6plTktOF__4FQzAngRr50rRZFSyHNUyzejS7gRwMqBmF3zOnETiAZx6WqcxYxT/s1600/build-fig.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
여기서 1은 대체할 툴이 어쩌고 할 여지가 없고,&lt;br /&gt;
2에서 make 대안으로 언급될만한 것은 ninja,&lt;br /&gt;
3에서 autotools의 대안으로 언급될만한 것은 cmake, 그리고 내 경우에는 gyp, gn 등&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ninja와 make를 비교하면 가장 중요한 차이는 make는 스스로 빌드툴 역할을 하는 상황을 상정하지만 ninja는 하지 않는다는 것이다. make의 경우에 make 자체가 빌드 시스템의 프론트엔드인 경우, 다시 말해서 Makefile을 인간이 직접 작성하는 것을 전제하고 만들어져서 소스가 되는 파일을 눈으로 읽어가면서 작업하는 것이 그래도 할만하고 조건부 빌드같은 기능도 필요한 것으로 간주되어 있다.&lt;br /&gt;
&lt;br /&gt;
반면에 ninja의 경우에는 정말로 빌드를 위한 의존관계 정리만으로 할 일을 최소화하고 있다. 다시 말해서 autotools나 cmake의 백앤드로 작동하기 위한 것이지 스스로 빌드툴 역할을 할 생각은 없다는 것이다. 컨디셔널 빌드? 각종 프로그램적 커스텀? 그건 다 cmake같은 툴에서 ninja 파일을 생성하는 시점에 할 일이다. ninja는 그저 기계적으로 빠르게 의존관계를 처리해서 빌드만 하면 된다. 그리하여 ninja의 리소스파일은 유닉스 텍스트 파일이지만 사람 눈으로 읽기에 친절하게 하려는 목표를 가지고 있지 않다.&amp;nbsp;그리고 실제로 make와 속도의 차이가 난다고 한다.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
그 뒷 단계의 autotools/cmake 등을 비교하면..&lt;br /&gt;
&lt;br /&gt;
autotools는 첫번째 난관은 진정 제대로 쓰려면 m4라는 언어 하나를 더 배워야 한다는 점이다. 개인적으로 &quot;순수하게 declarative한 언어의 예시&quot;로 언급하는 이상으로는 이 언어를 활용하지 못하고 있다.&lt;br /&gt;
&lt;br /&gt;
두번째로는 autoconf-autoreconf와 automake의 이원화된 시스템이라는 점.&lt;br /&gt;
&lt;br /&gt;
세 번째는 첫번째와 두번째의 시너지가 일으키는 복잡성.&lt;br /&gt;
&lt;br /&gt;
마지막으로는 빌드 관리툴이라기보다는 GNU 시스템의 타볼 패키지를 생성하는 도구에 가깝다는 점이다. 다시 말해서 autotools를 기반으로 한 소스코드 디렉토리는 다양한 환경을 지원하는 프로젝트의 소스코드라기보다는 GNU운영체제의 배포용 패키지에 가깝다. GNU 운영체제가 나름 다양한 타겟 아키텍쳐를 지원하지만 근본적으로 GNU 밖에서 쓰기에 적절하지 않다. 윈도우 환경에서 빌드하는 데 악명이 높다.&lt;br /&gt;
&lt;br /&gt;
cmake는 그냥 무난하고 대세스러운 느낌. 특별히 설명할 말을 모르겠다. 특히 지금처럼 잘 알지도 못하는 상황에서는.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
지금 무슨 프로젝트를 시작하게 된다면 cmake/ninja가 내 선택이 될 것 같다.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
가벼운 인상비평들.&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://routitz.blogspot.com/feeds/4557366587642890/comments/default' title='댓글'/><link rel='replies' type='text/html' href='http://routitz.blogspot.com/2015/02/cc.html#comment-form' title='0개의 덧글'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5613791988833919078/posts/default/4557366587642890'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5613791988833919078/posts/default/4557366587642890'/><link rel='alternate' type='text/html' href='http://routitz.blogspot.com/2015/02/cc.html' title='리눅스상 C/C++ 빌드툴 정리.'/><author><name>one-shave-man</name><uri>http://www.blogger.com/profile/03069698161893010566</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYwHhNAxYWXFNK9gv-sr2s44WG7bU9hW0gJJC_A1i1DmrEsFnlGzicc1KusB2_vQM9KTB-g2OV1FnpxJ6plTktOF__4FQzAngRr50rRZFSyHNUyzejS7gRwMqBmF3zOnETiAZx6WqcxYxT/s72-c/build-fig.png" height="72" width="72"/><thr:total>0</thr:total></entry></feed>