<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.9.5">Jekyll</generator><link href="http://www.yboyacigil.com/feed.xml" rel="self" type="application/atom+xml" /><link href="http://www.yboyacigil.com/" rel="alternate" type="text/html" /><updated>2024-07-17T06:46:27+00:00</updated><id>http://www.yboyacigil.com/feed.xml</id><title type="html">yboyacigil.com</title><subtitle>An amazing website.</subtitle><author><name>Yusuf Boyacıgil</name></author><entry><title type="html">Building microservices in NodeJS at full extent</title><link href="http://www.yboyacigil.com/english/nodejs/microservices/building-microservices-in-nodejs/" rel="alternate" type="text/html" title="Building microservices in NodeJS at full extent" /><published>2019-01-23T21:00:00+00:00</published><updated>2019-01-23T21:00:00+00:00</updated><id>http://www.yboyacigil.com/english/nodejs/microservices/building-microservices-in-nodejs</id><content type="html" xml:base="http://www.yboyacigil.com/english/nodejs/microservices/building-microservices-in-nodejs/"><![CDATA[<p>In this post, I will share my experiences in building a microservice in NodeJS using a lovely backend framework <a href="https://docs.nestjs.com/">NestJs</a> also including how to do configuration, logging, testing of the service, finally showing how it can be build as being installed as a system service.</p>

<p>I am a core Java/Scala backend developer and I would like to experiment new programming languages and frameworks where I see a fit to overcome issues that make the life easier compared to solutions that I am used to apply. Plus it gives you  better understanding of alternative ways to get things done.</p>

<p>One of the issues I dealt with recently was one of Spring/Java + Tomcat project taking a few minutes to startup that really needed to be fastened up. I took the chance to implement it in Node to see how fast it would be. (Happened to be a few secs!) It came with its own perils though where I had to implement some complementary Java services again. At the end, that was a nice experiment that worth trying.</p>

<p>Let’s dive into the details. Below you fill find sections each explains how I implemented the solution.</p>

<h2 id="nestjs">NestJS</h2>

<p>If you want to develop a microservice in Node, the obvious path is to use plain vanilla Javascript with the great <a href="https://expressjs.com">ExpressJS</a>. I started with that. There are bunch of boilerplate templates to start a microservice project. And adding transpilers such as Babel you can use the new EcmaScript features in your project. After some experimeting, I came across with a nice framework that handles bunch of things, the most important: “Dependency Injection”. That would be a good fit for people like me who worked with frameworks like Spring, Play for some long time. So I decided to make a switch to Nest.</p>

<p>Here is an excerpt from NestJS introduction:</p>

<blockquote>
  <p>Nest is a framework for building efficient, scalable Node.js server-side applications. It uses progressive JavaScript, is built with TypeScript (preserves compatibility with pure JavaScript) and combines elements of OOP (Object Oriented  Programming), FP (Functional Programming), and FRP (Functional Reactive Programming).</p>
</blockquote>

<p>That is a good premise. The more I worked with it, the more I liked it. Unlike express, nest is an opionated one. It is written in TypeScript which brings type checking. It has dependency injection and gives you the option to clearly define components of your service.</p>

<p>A typical Nest application has modules which basically provides and exposes classes, interfaces, services, controllers, etc. to itself or other modules. There’s a nice <code class="language-plaintext highlighter-rouge">nest-cli</code> which eliminates boilerplate to create a project and components as you go.</p>

<p>I started to develop complementary Java services as Nest services. Those are mostly clients of other microservices such as accessing external configuration, geo ip location, session, etc. To be able to use other microservices in a non-blocking, reactive mode, nest comes with an HttpService which depends on Axios/RxJs.</p>

<p>Below is an example of how to implement a service (e.g. session service client):</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="p">{</span> <span class="nx">Injectable</span><span class="p">,</span> <span class="nx">HttpService</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">@nestjs/common</span><span class="dl">'</span><span class="p">;</span>
<span class="k">import</span> <span class="p">{</span> <span class="nx">PropertiesService</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">../properties/properties.service</span><span class="dl">'</span><span class="p">;</span>
<span class="k">import</span> <span class="p">{</span> <span class="nx">LoggerService</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">../logger/logger.service</span><span class="dl">'</span><span class="p">;</span>
<span class="k">import</span> <span class="p">{</span> <span class="nx">Observable</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">rxjs</span><span class="dl">'</span><span class="p">;</span>
<span class="k">import</span> <span class="p">{</span> <span class="nx">AxiosResponse</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">axios</span><span class="dl">'</span><span class="p">;</span>

<span class="nx">type</span> <span class="nx">Nullable</span><span class="o">&lt;</span><span class="nx">T</span><span class="o">&gt;</span> <span class="o">=</span> <span class="nx">T</span> <span class="o">|</span> <span class="kc">null</span><span class="p">;</span>

<span class="k">export</span> <span class="kr">interface</span> <span class="nx">Session</span> <span class="p">{</span>
  <span class="nx">readonly</span> <span class="nx">sessionId</span><span class="p">:</span> <span class="nx">string</span><span class="p">;</span>
  <span class="nx">readonly</span> <span class="nx">playerId</span><span class="p">:</span> <span class="nx">number</span><span class="p">;</span>
  <span class="nx">readonly</span> <span class="nx">inactivityTimeout</span><span class="p">:</span> <span class="nx">number</span><span class="p">;</span>
<span class="p">}</span>

<span class="p">@</span><span class="nd">Injectable</span><span class="p">()</span>
<span class="k">export</span> <span class="kd">class</span> <span class="nx">SessionService</span> <span class="p">{</span>
  <span class="kd">constructor</span><span class="p">(</span><span class="kr">private</span> <span class="nx">readonly</span> <span class="nx">http</span><span class="p">:</span> <span class="nx">HttpService</span><span class="p">,</span> <span class="kr">private</span> <span class="nx">readonly</span> <span class="nx">properties</span><span class="p">:</span> <span class="nx">PropertiesService</span><span class="p">,</span> <span class="kr">private</span> <span class="nx">readonly</span> <span class="nx">logger</span><span class="p">:</span> <span class="nx">LoggerService</span><span class="p">)</span> <span class="p">{}</span>

  <span class="k">async</span> <span class="kd">get</span><span class="p">(</span><span class="nx">sessionId</span><span class="p">:</span> <span class="nx">string</span><span class="p">):</span> <span class="nb">Promise</span><span class="o">&lt;</span><span class="nx">Nullable</span><span class="o">&lt;</span><span class="nx">Session</span><span class="o">&gt;&gt;</span> <span class="p">{</span>
    <span class="k">this</span><span class="p">.</span><span class="nx">logger</span><span class="p">.</span><span class="nx">debug</span><span class="p">(</span><span class="s2">`Will get session by: </span><span class="p">${</span><span class="nx">sessionId</span><span class="p">}</span><span class="s2">`</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">sessionId</span><span class="p">)</span> <span class="p">{</span>
      <span class="nb">Promise</span><span class="p">.</span><span class="nx">reject</span><span class="p">(</span><span class="k">new</span> <span class="nb">Error</span><span class="p">(</span><span class="dl">'</span><span class="s1">Invalid session id</span><span class="dl">'</span><span class="p">));</span>
    <span class="p">}</span>

    <span class="kd">const</span> <span class="na">baseUri</span><span class="p">:</span> <span class="nx">string</span> <span class="o">=</span> <span class="k">await</span> <span class="k">this</span><span class="p">.</span><span class="nx">properties</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="dl">'</span><span class="s1">SYSTEM/SESSION_SERVICE/ENDPOINT</span><span class="dl">'</span><span class="p">,</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="dl">''</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">baseUri</span><span class="p">)</span> <span class="p">{</span>
      <span class="nb">Promise</span><span class="p">.</span><span class="nx">reject</span><span class="p">(</span><span class="k">new</span> <span class="nb">Error</span><span class="p">(</span><span class="dl">'</span><span class="s1">No baseUri for session service</span><span class="dl">'</span><span class="p">));</span>
    <span class="p">}</span>

    <span class="kd">const</span> <span class="na">response</span><span class="p">:</span> <span class="nx">Observable</span><span class="o">&lt;</span><span class="nx">AxiosResponse</span><span class="o">&lt;</span><span class="nx">Session</span><span class="o">&gt;&gt;</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">http</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="s2">`</span><span class="p">${</span><span class="nx">baseUri</span><span class="p">}</span><span class="s2">/sessions/</span><span class="p">${</span><span class="nx">sessionId</span><span class="p">}</span><span class="s2">`</span><span class="p">);</span>
    <span class="k">return</span> <span class="nx">response</span><span class="p">.</span><span class="nx">toPromise</span><span class="p">()</span>
      <span class="p">.</span><span class="nx">then</span><span class="p">(</span><span class="nx">axiosResponse</span> <span class="o">=&gt;</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="nx">axiosResponse</span><span class="p">.</span><span class="nx">status</span> <span class="o">===</span> <span class="mi">200</span> <span class="o">&amp;&amp;</span> <span class="nx">axiosResponse</span><span class="p">.</span><span class="nx">data</span><span class="p">)</span> <span class="p">{</span>
          <span class="kd">const</span> <span class="na">session</span><span class="p">:</span> <span class="nx">Session</span> <span class="o">=</span> <span class="nx">axiosResponse</span><span class="p">.</span><span class="nx">data</span><span class="p">;</span>
          <span class="k">this</span><span class="p">.</span><span class="nx">logger</span><span class="p">.</span><span class="nx">debug</span><span class="p">(</span><span class="s2">`Session =&gt; </span><span class="p">${</span><span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">session</span><span class="p">)}</span><span class="s2">`</span><span class="p">);</span>
          <span class="k">return</span> <span class="nx">session</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="k">this</span><span class="p">.</span><span class="nx">logger</span><span class="p">.</span><span class="nx">debug</span><span class="p">(</span><span class="s2">`Response status is not ok. Session =&gt; null`</span><span class="p">);</span>
        <span class="k">return</span> <span class="kc">null</span><span class="p">;</span>
      <span class="p">})</span>
      <span class="p">.</span><span class="k">catch</span><span class="p">(</span><span class="nx">reason</span> <span class="o">=&gt;</span> <span class="p">{</span>
        <span class="k">this</span><span class="p">.</span><span class="nx">logger</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="s2">`Error in getting session. Session =&gt; null. (</span><span class="p">${</span><span class="nx">reason</span><span class="p">}</span><span class="s2">)`</span><span class="p">);</span>
        <span class="k">return</span> <span class="kc">null</span><span class="p">;</span>
      <span class="p">});</span>
  <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="configuration">Configuration</h2>

<p>As for the configuration of the service, the npm package <a href="https://www.npmjs.com/package/dotenv">dotenv</a> was what I chose. First it would allow you to have different sets of configurations for different environments (i.e. development, test, production) that can be controlled using env variable <code class="language-plaintext highlighter-rouge">NODE_ENV</code>. Upon that using another npm package <a href="https://www.npmjs.com/package/joi">joi</a> you can validate configuration once you load it. Finally to go with Nest way, I created the service: <code class="language-plaintext highlighter-rouge">ConfigurationService</code> which I can inject it wherever needed.</p>

<p>Here is a configuration file for development:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">NODE_ENV</span><span class="o">=</span>development
<span class="nv">PORT</span><span class="o">=</span>3000
<span class="nv">ETCD_HOST</span><span class="o">=</span>localhost
<span class="nv">LOG_PATH</span><span class="o">=</span>./logs
<span class="nv">LOG_FILE</span><span class="o">=</span>application.log
<span class="nv">LOGSTASH_ENABLED</span><span class="o">=</span><span class="nb">false
</span><span class="nv">GEOIP_HOST</span><span class="o">=</span><span class="s2">"geoip:8080"</span>
</code></pre></div></div>

<p>and the code snippet from configuration service:</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">export</span> <span class="kr">interface</span> <span class="nx">EnvConfig</span> <span class="p">{</span>
  <span class="p">[</span><span class="nx">key</span><span class="p">:</span> <span class="nx">string</span><span class="p">]:</span> <span class="nx">string</span><span class="p">;</span>
<span class="p">}</span>

<span class="p">@</span><span class="nd">Injectable</span><span class="p">()</span>
<span class="k">export</span> <span class="kd">class</span> <span class="nx">ConfigService</span> <span class="p">{</span>
  <span class="kr">private</span> <span class="nx">readonly</span> <span class="nx">envConfig</span><span class="p">:</span> <span class="nx">EnvConfig</span><span class="p">;</span>

  <span class="kd">constructor</span><span class="p">(</span><span class="nx">filePath</span><span class="p">:</span> <span class="nx">string</span><span class="p">)</span> <span class="p">{</span>
    <span class="kd">const</span> <span class="nx">config</span> <span class="o">=</span> <span class="nx">dotenv</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">fs</span><span class="p">.</span><span class="nx">readFileSync</span><span class="p">(</span><span class="nx">filePath</span><span class="p">));</span>
    <span class="k">this</span><span class="p">.</span><span class="nx">envConfig</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">validateInput</span><span class="p">(</span><span class="nx">config</span><span class="p">);</span>
  <span class="p">}</span>

  <span class="c1">// ...</span>
<span class="p">}</span>
</code></pre></div></div>

<p>and here is how you can validate your config file:</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="kr">private</span> <span class="nx">validateInput</span><span class="p">(</span><span class="nx">envConfig</span><span class="p">:</span> <span class="nx">EnvConfig</span><span class="p">):</span> <span class="nx">EnvConfig</span> <span class="p">{</span>
    <span class="kd">const</span> <span class="nx">envVarsSchema</span><span class="p">:</span> <span class="nx">Joi</span><span class="p">.</span><span class="nx">ObjectSchema</span> <span class="o">=</span> <span class="nx">Joi</span><span class="p">.</span><span class="nx">object</span><span class="p">({</span>
      <span class="na">NODE_ENV</span><span class="p">:</span> <span class="nx">Joi</span><span class="p">.</span><span class="nx">string</span><span class="p">()</span>
        <span class="p">.</span><span class="nx">valid</span><span class="p">([</span><span class="dl">'</span><span class="s1">development</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">production</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">test</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">provision</span><span class="dl">'</span><span class="p">])</span>
        <span class="p">.</span><span class="k">default</span><span class="p">(</span><span class="dl">'</span><span class="s1">development</span><span class="dl">'</span><span class="p">),</span>
      <span class="na">PORT</span><span class="p">:</span> <span class="nx">Joi</span><span class="p">.</span><span class="nx">number</span><span class="p">().</span><span class="k">default</span><span class="p">(</span><span class="mi">3000</span><span class="p">),</span>
      <span class="na">ETCD_HOST</span><span class="p">:</span> <span class="nx">Joi</span><span class="p">.</span><span class="nx">string</span><span class="p">().</span><span class="nx">required</span><span class="p">(),</span>
      <span class="na">ETCD_PORT</span><span class="p">:</span> <span class="nx">Joi</span><span class="p">.</span><span class="nx">number</span><span class="p">().</span><span class="k">default</span><span class="p">(</span><span class="mi">4001</span><span class="p">),</span>
      <span class="na">LOG_PATH</span><span class="p">:</span> <span class="nx">Joi</span><span class="p">.</span><span class="nx">string</span><span class="p">().</span><span class="nx">required</span><span class="p">(),</span>
      <span class="na">LOG_FILE</span><span class="p">:</span> <span class="nx">Joi</span><span class="p">.</span><span class="nx">string</span><span class="p">().</span><span class="nx">required</span><span class="p">(),</span>
      <span class="na">LOGSTASH_ENABLED</span><span class="p">:</span> <span class="nx">Joi</span><span class="p">.</span><span class="nx">boolean</span><span class="p">().</span><span class="k">default</span><span class="p">(</span><span class="kc">false</span><span class="p">),</span>
      <span class="na">LOGSTASH_HOST</span><span class="p">:</span> <span class="nx">Joi</span><span class="p">.</span><span class="nx">string</span><span class="p">(),</span>
      <span class="na">LOGSTASH_PORT</span><span class="p">:</span> <span class="nx">Joi</span><span class="p">.</span><span class="nx">number</span><span class="p">(),</span>
      <span class="na">GEOIP_HOST</span><span class="p">:</span> <span class="nx">Joi</span><span class="p">.</span><span class="nx">string</span><span class="p">(),</span>
    <span class="p">});</span>

    <span class="kd">const</span> <span class="p">{</span> <span class="nx">error</span><span class="p">,</span> <span class="na">value</span><span class="p">:</span> <span class="nx">validatedEnvConfig</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">Joi</span><span class="p">.</span><span class="nx">validate</span><span class="p">(</span>
      <span class="nx">envConfig</span><span class="p">,</span>
      <span class="nx">envVarsSchema</span><span class="p">,</span>
    <span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="nx">error</span><span class="p">)</span> <span class="p">{</span>
      <span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span><span class="p">(</span><span class="s2">`Config validation error: </span><span class="p">${</span><span class="nx">error</span><span class="p">.</span><span class="nx">message</span><span class="p">}</span><span class="s2">`</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="nx">validatedEnvConfig</span><span class="p">;</span>
  <span class="p">}</span>
</code></pre></div></div>

<h2 id="logging">Logging</h2>

<p>For logging, the number one npm package is <a href="https://www.npmjs.com/package/winston">winston</a>, I started to use it as well. I had a couple of requirements for logging:</p>
<ul>
  <li>I should be able to log incoming requests and outgoing responses with the payload,</li>
  <li>I should be able to send logs to our ELK,</li>
  <li>I should be able inject logging service into others where I need to log something.</li>
</ul>

<p>I was able to handle all with winston. But on sending logs to ELK, using an npm package <a href="https://www.npmjs.com/package/winston-logstash">winston-logstash</a> which provides a new <code class="language-plaintext highlighter-rouge">Transporter</code> that you can configure to which logstash instance logs should be shipped to.</p>

<p>Then, I came across <a href="https://www.npmjs.com/package/log4js">log4js</a>. As a loyal user of <code class="language-plaintext highlighter-rouge">log4j</code>, I jumped in to that and learning that with the addition of another package <a href="https://www.npmjs.com/package/log4js-logstash-tcp">logjs-logstash-tcp</a> I implemented my LoggerService as:</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">@</span><span class="nd">Injectable</span><span class="p">()</span>
<span class="k">export</span> <span class="kd">class</span> <span class="nx">LoggerService</span> <span class="kr">implements</span> <span class="nx">NestLoggerService</span> <span class="p">{</span>
  <span class="kr">private</span> <span class="nx">readonly</span> <span class="nx">log4jsLogger</span><span class="p">:</span> <span class="nx">Logger</span><span class="p">;</span>

  <span class="kd">constructor</span><span class="p">(</span><span class="kr">private</span> <span class="nx">readonly</span> <span class="nx">config</span><span class="p">:</span> <span class="nx">ConfigService</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">this</span><span class="p">.</span><span class="nx">log4jsLogger</span> <span class="o">=</span> <span class="nx">getLogger</span><span class="p">();</span>

    <span class="kd">const</span> <span class="nx">log4jsConfig</span><span class="p">:</span> <span class="nx">Configuration</span> <span class="o">=</span> <span class="p">{</span>
      <span class="na">appenders</span><span class="p">:</span> <span class="p">{</span>
        <span class="na">access</span><span class="p">:</span> <span class="p">{</span>
          <span class="na">type</span><span class="p">:</span> <span class="dl">'</span><span class="s1">dateFile</span><span class="dl">'</span><span class="p">,</span>
          <span class="na">filename</span><span class="p">:</span> <span class="s2">`</span><span class="p">${</span><span class="k">this</span><span class="p">.</span><span class="nx">config</span><span class="p">.</span><span class="nx">getLogPath</span><span class="p">()}</span><span class="s2">/access.log`</span><span class="p">,</span>
          <span class="na">pattern</span><span class="p">:</span> <span class="dl">'</span><span class="s1">-yyyy-MM-dd</span><span class="dl">'</span><span class="p">,</span>
          <span class="na">category</span><span class="p">:</span> <span class="dl">'</span><span class="s1">http</span><span class="dl">'</span><span class="p">,</span>
        <span class="p">},</span>
        <span class="na">app</span><span class="p">:</span> <span class="p">{</span>
          <span class="na">type</span><span class="p">:</span> <span class="dl">'</span><span class="s1">file</span><span class="dl">'</span><span class="p">,</span>
          <span class="na">filename</span><span class="p">:</span> <span class="s2">`</span><span class="p">${</span><span class="k">this</span><span class="p">.</span><span class="nx">config</span><span class="p">.</span><span class="nx">getLogPath</span><span class="p">()}</span><span class="s2">/</span><span class="p">${</span><span class="k">this</span><span class="p">.</span><span class="nx">config</span><span class="p">.</span><span class="nx">getLogFile</span><span class="p">()}</span><span class="s2">`</span><span class="p">,</span>
          <span class="na">maxLogSize</span><span class="p">:</span> <span class="mi">5242880</span><span class="p">,</span>
          <span class="na">numBackups</span><span class="p">:</span> <span class="mi">5</span><span class="p">,</span>
        <span class="p">},</span>
        <span class="na">errorFile</span><span class="p">:</span> <span class="p">{</span>
          <span class="na">type</span><span class="p">:</span> <span class="dl">'</span><span class="s1">file</span><span class="dl">'</span><span class="p">,</span>
          <span class="na">filename</span><span class="p">:</span> <span class="s2">`</span><span class="p">${</span><span class="k">this</span><span class="p">.</span><span class="nx">config</span><span class="p">.</span><span class="nx">getLogPath</span><span class="p">()}</span><span class="s2">/error.log`</span><span class="p">,</span>
        <span class="p">},</span>
        <span class="na">errors</span><span class="p">:</span> <span class="p">{</span>
          <span class="na">type</span><span class="p">:</span> <span class="dl">'</span><span class="s1">logLevelFilter</span><span class="dl">'</span><span class="p">,</span>
          <span class="na">level</span><span class="p">:</span> <span class="dl">'</span><span class="s1">ERROR</span><span class="dl">'</span><span class="p">,</span>
          <span class="na">appender</span><span class="p">:</span> <span class="dl">'</span><span class="s1">errorFile</span><span class="dl">'</span><span class="p">,</span>
        <span class="p">},</span>
      <span class="p">},</span>
      <span class="na">categories</span><span class="p">:</span> <span class="p">{</span>
        <span class="na">default</span><span class="p">:</span> <span class="p">{</span> <span class="na">appenders</span><span class="p">:</span> <span class="p">[</span><span class="dl">'</span><span class="s1">app</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">errors</span><span class="dl">'</span><span class="p">],</span> <span class="na">level</span><span class="p">:</span> <span class="dl">'</span><span class="s1">INFO</span><span class="dl">'</span><span class="p">},</span>
        <span class="na">http</span><span class="p">:</span> <span class="p">{</span><span class="na">appenders</span><span class="p">:</span> <span class="p">[</span><span class="dl">'</span><span class="s1">access</span><span class="dl">'</span><span class="p">],</span> <span class="na">level</span><span class="p">:</span> <span class="dl">'</span><span class="s1">INFO</span><span class="dl">'</span><span class="p">},</span>
      <span class="p">},</span>
    <span class="p">};</span>

    <span class="k">if</span> <span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">config</span><span class="p">.</span><span class="nx">isLogstashEnabled</span><span class="p">())</span> <span class="p">{</span>
      <span class="nx">log4jsConfig</span><span class="p">.</span><span class="nx">appenders</span><span class="p">.</span><span class="nx">logstash</span> <span class="o">=</span> <span class="p">{</span>
        <span class="na">type</span><span class="p">:</span> <span class="dl">'</span><span class="s1">log4js-logstash-tcp</span><span class="dl">'</span><span class="p">,</span>
        <span class="na">category</span><span class="p">:</span> <span class="dl">'</span><span class="s1">default</span><span class="dl">'</span><span class="p">,</span>
        <span class="na">host</span><span class="p">:</span> <span class="k">this</span><span class="p">.</span><span class="nx">config</span><span class="p">.</span><span class="nx">getLogstashHost</span><span class="p">(),</span>
        <span class="na">port</span><span class="p">:</span> <span class="k">this</span><span class="p">.</span><span class="nx">config</span><span class="p">.</span><span class="nx">getLogstashPort</span><span class="p">(),</span>
        <span class="na">fields</span><span class="p">:</span> <span class="p">{</span>
          <span class="na">source</span><span class="p">:</span> <span class="dl">'</span><span class="s1">co-game-loader</span><span class="dl">'</span><span class="p">,</span>
          <span class="na">environment</span><span class="p">:</span> <span class="nx">os</span><span class="p">.</span><span class="nx">hostname</span><span class="p">(),</span>
          <span class="na">group</span><span class="p">:</span> <span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">NODE_ENV</span><span class="p">,</span>
        <span class="p">},</span>
      <span class="p">};</span>
      <span class="nx">log4jsConfig</span><span class="p">.</span><span class="nx">categories</span><span class="p">.</span><span class="k">default</span><span class="p">.</span><span class="nx">appenders</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="dl">'</span><span class="s1">logstash</span><span class="dl">'</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">if</span> <span class="p">(</span><span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">NODE_ENV</span> <span class="o">!==</span> <span class="dl">'</span><span class="s1">production</span><span class="dl">'</span><span class="p">)</span> <span class="p">{</span>
      <span class="nx">log4jsConfig</span><span class="p">.</span><span class="nx">appenders</span><span class="p">.</span><span class="nx">console</span> <span class="o">=</span> <span class="p">{</span>
        <span class="na">type</span><span class="p">:</span> <span class="dl">'</span><span class="s1">console</span><span class="dl">'</span><span class="p">,</span>
      <span class="p">};</span>

      <span class="nx">log4jsConfig</span><span class="p">.</span><span class="nx">categories</span><span class="p">.</span><span class="k">default</span><span class="p">.</span><span class="nx">appenders</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="dl">'</span><span class="s1">console</span><span class="dl">'</span><span class="p">);</span>
      <span class="nx">log4jsConfig</span><span class="p">.</span><span class="nx">categories</span><span class="p">.</span><span class="k">default</span><span class="p">.</span><span class="nx">level</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">DEBUG</span><span class="dl">'</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="nx">configure</span><span class="p">(</span><span class="nx">log4jsConfig</span><span class="p">);</span>
  <span class="p">}</span>
</code></pre></div></div>

<p>Here I need to mention a two things:</p>

<p>One, you can extend <code class="language-plaintext highlighter-rouge">NestLoggerService</code> to be able to write the logging service. By doing that Nest was able to be use it for its logging needs. You can add your logger on bootstrapping the Nest application like:</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">async</span> <span class="kd">function</span> <span class="nx">bootstrap</span><span class="p">()</span> <span class="p">{</span>
  <span class="kd">const</span> <span class="nx">app</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">NestFactory</span><span class="p">.</span><span class="nx">create</span><span class="p">(</span><span class="nx">AppModule</span><span class="p">,</span> <span class="p">{</span> <span class="na">logger</span><span class="p">:</span> <span class="kc">false</span> <span class="p">});</span>
  <span class="nx">app</span><span class="p">.</span><span class="nx">useLogger</span><span class="p">(</span><span class="nx">app</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="nx">LoggerService</span><span class="p">));</span>
  <span class="c1">// ...</span>
<span class="p">}</span>
<span class="nx">bootstrap</span><span class="p">();</span>
</code></pre></div></div>

<p>Then, you can configure <code class="language-plaintext highlighter-rouge">log4js</code> in a .js file over which a typical <code class="language-plaintext highlighter-rouge">log4j</code> user prefers to do in a config file. Doing so gives you the flexibility to customize logging depending on envrionment variables or your service configuration. See for instance how to send logs to logstash as well conditionally:</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">config</span><span class="p">.</span><span class="nx">isLogstashEnabled</span><span class="p">())</span> <span class="p">{</span>
  <span class="nx">log4jsConfig</span><span class="p">.</span><span class="nx">appenders</span><span class="p">.</span><span class="nx">logstash</span> <span class="o">=</span> <span class="p">{</span>
    <span class="na">type</span><span class="p">:</span> <span class="dl">'</span><span class="s1">log4js-logstash-tcp</span><span class="dl">'</span><span class="p">,</span>
    <span class="na">category</span><span class="p">:</span> <span class="dl">'</span><span class="s1">default</span><span class="dl">'</span><span class="p">,</span>
    <span class="na">host</span><span class="p">:</span> <span class="k">this</span><span class="p">.</span><span class="nx">config</span><span class="p">.</span><span class="nx">getLogstashHost</span><span class="p">(),</span>
    <span class="na">port</span><span class="p">:</span> <span class="k">this</span><span class="p">.</span><span class="nx">config</span><span class="p">.</span><span class="nx">getLogstashPort</span><span class="p">(),</span>
    <span class="na">fields</span><span class="p">:</span> <span class="p">{</span>
      <span class="na">source</span><span class="p">:</span> <span class="dl">'</span><span class="s1">co-game-loader</span><span class="dl">'</span><span class="p">,</span>
      <span class="na">environment</span><span class="p">:</span> <span class="nx">os</span><span class="p">.</span><span class="nx">hostname</span><span class="p">(),</span>
      <span class="na">group</span><span class="p">:</span> <span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">NODE_ENV</span><span class="p">,</span>
    <span class="p">},</span>
  <span class="p">};</span>
  <span class="nx">log4jsConfig</span><span class="p">.</span><span class="nx">categories</span><span class="p">.</span><span class="k">default</span><span class="p">.</span><span class="nx">appenders</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="dl">'</span><span class="s1">logstash</span><span class="dl">'</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>or how to enable console logging for environments other than <code class="language-plaintext highlighter-rouge">production</code>:</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="p">(</span><span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">NODE_ENV</span> <span class="o">!==</span> <span class="dl">'</span><span class="s1">production</span><span class="dl">'</span><span class="p">)</span> <span class="p">{</span>
  <span class="nx">log4jsConfig</span><span class="p">.</span><span class="nx">appenders</span><span class="p">.</span><span class="nx">console</span> <span class="o">=</span> <span class="p">{</span>
    <span class="na">type</span><span class="p">:</span> <span class="dl">'</span><span class="s1">console</span><span class="dl">'</span><span class="p">,</span>
  <span class="p">};</span>

  <span class="nx">log4jsConfig</span><span class="p">.</span><span class="nx">categories</span><span class="p">.</span><span class="k">default</span><span class="p">.</span><span class="nx">appenders</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="dl">'</span><span class="s1">console</span><span class="dl">'</span><span class="p">);</span>
  <span class="nx">log4jsConfig</span><span class="p">.</span><span class="nx">categories</span><span class="p">.</span><span class="k">default</span><span class="p">.</span><span class="nx">level</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">DEBUG</span><span class="dl">'</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="testing">Testing</h2>

<p>As Nest comes with a very good testing framework <a href="https://jestjs.io/">Jest</a>, I did not search for more and just tried to stick with it. When you create a Nest component via <code class="language-plaintext highlighter-rouge">nest-cli</code>, there you have the initial code to write the tests for that component. With a little read and try-and-fail, I was able to write tests for all the services, classes, I created. It helped a lot especially finding errors I made during implementation. I will not go into the details of how to write tests using Jest. I just want to share an example here to give you the feel of a simple test:</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">describe</span><span class="p">(</span><span class="dl">'</span><span class="s1">SessionService</span><span class="dl">'</span><span class="p">,</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="p">{</span>
  <span class="kd">let</span> <span class="na">service</span><span class="p">:</span> <span class="nx">SessionService</span><span class="p">;</span>
  <span class="kd">let</span> <span class="na">logger</span><span class="p">:</span> <span class="nx">LoggerService</span><span class="p">;</span>
  <span class="kd">let</span> <span class="na">properties</span><span class="p">:</span> <span class="nx">PropertiesService</span><span class="p">;</span>
  <span class="kd">let</span> <span class="na">http</span><span class="p">:</span> <span class="nx">HttpService</span><span class="p">;</span>

  <span class="nx">beforeAll</span><span class="p">(</span><span class="k">async</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="p">{</span>
    <span class="kd">const</span> <span class="na">module</span><span class="p">:</span> <span class="nx">TestingModule</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">Test</span><span class="p">.</span><span class="nx">createTestingModule</span><span class="p">({</span>
      <span class="na">imports</span><span class="p">:</span> <span class="p">[</span><span class="nx">HttpModule</span><span class="p">,</span> <span class="nx">PropertiesModule</span><span class="p">,</span> <span class="nx">LoggerModule</span><span class="p">],</span>
      <span class="na">providers</span><span class="p">:</span> <span class="p">[</span><span class="nx">SessionService</span><span class="p">],</span>
    <span class="p">}).</span><span class="nx">compile</span><span class="p">();</span>
    <span class="nx">http</span> <span class="o">=</span> <span class="nx">module</span><span class="p">.</span><span class="kd">get</span><span class="o">&lt;</span><span class="nx">HttpService</span><span class="o">&gt;</span><span class="p">(</span><span class="nx">HttpService</span><span class="p">);</span>
    <span class="nx">properties</span> <span class="o">=</span> <span class="nx">module</span><span class="p">.</span><span class="kd">get</span><span class="o">&lt;</span><span class="nx">PropertiesService</span><span class="o">&gt;</span><span class="p">(</span><span class="nx">PropertiesService</span><span class="p">);</span>
    <span class="nx">logger</span> <span class="o">=</span> <span class="nx">module</span><span class="p">.</span><span class="kd">get</span><span class="o">&lt;</span><span class="nx">LoggerService</span><span class="o">&gt;</span><span class="p">(</span><span class="nx">LoggerService</span><span class="p">);</span>
    <span class="nx">service</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">SessionService</span><span class="p">(</span><span class="nx">http</span><span class="p">,</span> <span class="nx">properties</span><span class="p">,</span> <span class="nx">logger</span><span class="p">);</span>

    <span class="nx">jest</span><span class="p">.</span><span class="nx">spyOn</span><span class="p">(</span><span class="nx">logger</span><span class="p">,</span> <span class="dl">'</span><span class="s1">debug</span><span class="dl">'</span><span class="p">).</span><span class="nx">mockImplementation</span><span class="p">((</span><span class="na">message</span><span class="p">:</span> <span class="nx">any</span><span class="p">,</span> <span class="nx">context</span><span class="p">?:</span> <span class="nx">string</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">message</span><span class="p">));</span>
  <span class="p">});</span>

  <span class="nx">it</span><span class="p">(</span><span class="dl">'</span><span class="s1">should be defined</span><span class="dl">'</span><span class="p">,</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="p">{</span>
    <span class="nx">expect</span><span class="p">(</span><span class="nx">service</span><span class="p">).</span><span class="nx">toBeDefined</span><span class="p">();</span>
  <span class="p">});</span>

  <span class="nx">it</span><span class="p">(</span><span class="dl">'</span><span class="s1">should return EMPTY when session service request responds with status code NOT OK</span><span class="dl">'</span><span class="p">,</span> <span class="k">async</span> <span class="p">(</span><span class="nx">done</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
    <span class="kd">const</span> <span class="nx">mockGet</span> <span class="o">=</span> <span class="nx">jest</span><span class="p">.</span><span class="nx">spyOn</span><span class="p">(</span><span class="nx">properties</span><span class="p">,</span> <span class="dl">'</span><span class="s1">get</span><span class="dl">'</span><span class="p">).</span><span class="nx">mockImplementation</span><span class="p">((</span><span class="na">key</span><span class="p">:</span> <span class="nx">string</span><span class="p">,</span> <span class="na">defaultSupplier</span><span class="p">:</span> <span class="nx">any</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="nb">Promise</span><span class="p">.</span><span class="nx">resolve</span><span class="p">(</span><span class="dl">'</span><span class="s1">http://session-service-host</span><span class="dl">'</span><span class="p">));</span>
    <span class="nx">jest</span><span class="p">.</span><span class="nx">spyOn</span><span class="p">(</span><span class="nx">http</span><span class="p">,</span> <span class="dl">'</span><span class="s1">get</span><span class="dl">'</span><span class="p">).</span><span class="nx">mockImplementation</span><span class="p">(()</span> <span class="o">=&gt;</span> <span class="k">of</span><span class="p">({</span><span class="na">status</span><span class="p">:</span> <span class="mi">500</span><span class="p">}));</span>

    <span class="k">await</span> <span class="nx">expect</span><span class="p">(</span><span class="nx">service</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="dl">'</span><span class="s1">session-id</span><span class="dl">'</span><span class="p">)).</span><span class="nx">resolves</span><span class="p">.</span><span class="nx">toEqual</span><span class="p">(</span><span class="kc">null</span><span class="p">);</span>

    <span class="nx">expect</span><span class="p">(</span><span class="nx">mockGet</span><span class="p">).</span><span class="nx">toBeCalledWith</span><span class="p">(</span><span class="dl">'</span><span class="s1">SYSTEM/SESSION_SERVICE/ENDPOINT</span><span class="dl">'</span><span class="p">,</span> <span class="nx">expect</span><span class="p">.</span><span class="nx">any</span><span class="p">(</span><span class="nb">Function</span><span class="p">));</span>

    <span class="nx">done</span><span class="p">();</span>
  <span class="p">});</span>

  <span class="nx">it</span><span class="p">(</span><span class="dl">'</span><span class="s1">should return SESSION when session service request responds with status OK and session</span><span class="dl">'</span><span class="p">,</span> <span class="k">async</span> <span class="p">(</span><span class="nx">done</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
    <span class="kd">const</span> <span class="nx">mockGet</span> <span class="o">=</span> <span class="nx">jest</span><span class="p">.</span><span class="nx">spyOn</span><span class="p">(</span><span class="nx">properties</span><span class="p">,</span> <span class="dl">'</span><span class="s1">get</span><span class="dl">'</span><span class="p">).</span><span class="nx">mockImplementation</span><span class="p">((</span><span class="na">key</span><span class="p">:</span> <span class="nx">string</span><span class="p">,</span> <span class="na">defaultSupplier</span><span class="p">:</span> <span class="nx">any</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="nb">Promise</span><span class="p">.</span><span class="nx">resolve</span><span class="p">(</span><span class="dl">'</span><span class="s1">http://session-service-host</span><span class="dl">'</span><span class="p">));</span>
    <span class="kd">const</span> <span class="nx">expectedSession</span> <span class="o">=</span> <span class="p">{</span><span class="na">sessionId</span><span class="p">:</span> <span class="dl">'</span><span class="s1">sessionId</span><span class="dl">'</span><span class="p">,</span> <span class="na">playerId</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="na">inactivityTimeout</span><span class="p">:</span> <span class="mi">10</span><span class="p">}</span>
    <span class="nx">jest</span><span class="p">.</span><span class="nx">spyOn</span><span class="p">(</span><span class="nx">http</span><span class="p">,</span> <span class="dl">'</span><span class="s1">get</span><span class="dl">'</span><span class="p">).</span><span class="nx">mockImplementation</span><span class="p">(()</span> <span class="o">=&gt;</span> <span class="k">of</span><span class="p">({</span><span class="na">status</span><span class="p">:</span> <span class="mi">200</span><span class="p">,</span> <span class="na">data</span><span class="p">:</span> <span class="nx">expectedSession</span><span class="p">}));</span>

    <span class="k">await</span> <span class="nx">expect</span><span class="p">(</span><span class="nx">service</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="dl">'</span><span class="s1">session-id</span><span class="dl">'</span><span class="p">)).</span><span class="nx">resolves</span><span class="p">.</span><span class="nx">toEqual</span><span class="p">(</span><span class="nx">expectedSession</span><span class="p">);</span>

    <span class="nx">expect</span><span class="p">(</span><span class="nx">mockGet</span><span class="p">).</span><span class="nx">toBeCalledWith</span><span class="p">(</span><span class="dl">'</span><span class="s1">SYSTEM/SESSION_SERVICE/ENDPOINT</span><span class="dl">'</span><span class="p">,</span> <span class="nx">expect</span><span class="p">.</span><span class="nx">any</span><span class="p">(</span><span class="nb">Function</span><span class="p">));</span>

    <span class="nx">done</span><span class="p">();</span>
  <span class="p">});</span>
<span class="p">});</span>
</code></pre></div></div>

<p>Jest requires you write tests in BDD style. Before all, I had to create a test module and bring dependant modules into my test scope. Then I created mocks for defining test behaviours of dependant services.</p>

<h2 id="debian-packaging">Debian Packaging</h2>

<p>As I see it, typical deployment of a Node service is either docker or checking out the source from a repo and running it node (e.g. <code class="language-plaintext highlighter-rouge">node server.js</code>). In my case, those were not the options and since the original source code (in TypeScript) needs to be compiled into plain vanilla Javascript that Node can understand and I needed to create a deb(ian) package. Here another npm package <a href="https://www.npmjs.com/package/node-deb">node-deb</a> helped. With <code class="language-plaintext highlighter-rouge">node-deb</code> you can create packages that can be installed as a system service on a target machine.</p>

<p>To be able use <code class="language-plaintext highlighter-rouge">node-deb</code> and control how the package will be created. First I needed to add instructions to <code class="language-plaintext highlighter-rouge">package.json</code>:</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">"devDependencies"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"node-deb"</span><span class="p">:</span><span class="w"> </span><span class="s2">"^0.10.7"</span><span class="w">
  </span><span class="p">}</span><span class="err">,</span><span class="w">

 </span><span class="nl">"node_deb"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"init"</span><span class="p">:</span><span class="w"> </span><span class="s2">"none"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"dependencies"</span><span class="p">:</span><span class="w"> </span><span class="s2">"base-passwd, adduser (&gt;= 3.11), nodejs"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"entrypoints"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"cli"</span><span class="p">:</span><span class="w"> </span><span class="s2">"dist/main.js"</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>where I basically defined the entry point and dependent debian packages and added <code class="language-plaintext highlighter-rouge">npm run</code> scripts like:</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="w">  </span><span class="p">{</span><span class="w">
    </span><span class="nl">"predeb:test"</span><span class="p">:</span><span class="w"> </span><span class="s2">"rimraf dist &amp;&amp; tsc"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"deb:test"</span><span class="p">:</span><span class="w"> </span><span class="s2">"./node_modules/node-deb/node-deb --no-default-package-dependencies --template-default-variables deb/env-test -- test.env dist/"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"predeb:prod"</span><span class="p">:</span><span class="w"> </span><span class="s2">"rimraf dist &amp;&amp; tsc"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"deb:prod"</span><span class="p">:</span><span class="w"> </span><span class="s2">"./node_modules/node-deb/node-deb --no-default-package-dependencies --template-default-variables deb/env-production -- production.env dist/"</span><span class="w">
  </span><span class="p">}</span><span class="err">,</span><span class="w">
</span></code></pre></div></div>

<p>to build the deb package for test and production targets. And to introduce environment variables (<code class="language-plaintext highlighter-rouge">NODE_ENV</code> in my case) to the service, I needed to tell node-deb the template. Here is the <code class="language-plaintext highlighter-rouge">production.env</code> template:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># This file was autogenerated by node-deb </span>
<span class="c">#</span>
<span class="c"># Configuration for the  daemon</span>
<span class="c">#</span>
<span class="nv">NODE_ENV</span><span class="o">=</span><span class="s2">"production"</span>
</code></pre></div></div>

<p>With this setup, I was able to build the deb package even in Jenkins and to push it to an internal repo, where target server machines can pull and (re)deploy the service automatically with the help of puppet.</p>

<h2 id="final-words">Final words</h2>

<p>I hope that I will help to the adventurers of Node by at least giving useful insights how to write a microservices in Node.</p>]]></content><author><name>Yusuf Boyacıgil</name></author><category term="english" /><category term="nodejs" /><category term="microservices" /><summary type="html"><![CDATA[In this post, I will share my experiences in building a microservice in NodeJS using a lovely backend framework NestJs also including how to do configuration, logging, testing of the service, finally showing how it can be build as being installed as a system service.]]></summary></entry><entry><title type="html">How to Implement a Wallet Server using SpringBoot with Akka</title><link href="http://www.yboyacigil.com/english/springboot/akka/how-to-implement-a-wallet-server-using-springboot-with-akka/" rel="alternate" type="text/html" title="How to Implement a Wallet Server using SpringBoot with Akka" /><published>2018-11-03T12:15:15+00:00</published><updated>2018-11-03T12:15:15+00:00</updated><id>http://www.yboyacigil.com/english/springboot/akka/how-to-implement-a-wallet-server-using-springboot-with-akka</id><content type="html" xml:base="http://www.yboyacigil.com/english/springboot/akka/how-to-implement-a-wallet-server-using-springboot-with-akka/"><![CDATA[<p>In this post, I will share how to use SpringBoot together with Akka framework to build a reactive rest service (a wallet server) and also demonstrate how the polyglot approach can be applied to your project for writing tests using a very nice testing framework Spock in Groovy programming language.</p>

<p>SpringBoot and Akka are two powerful frameworks both have their own strengths and can be used alone to develop microservices. You can argue both has some pros and cons. Although it mostly depends on the taste of the developer, I love SpringBoot a lot when it comes to building microservices quickly with the help of huge support for integrations with almost any service you may need. Akka on the otherhand has a very solid actor model for developing concurrent and distributed applications but, imho compared to spring, it lacks easy dependency injection; designing REST endpoints with AkkaHttp is not straight forward and integrations with services are limited.</p>

<p>Let’s jump into solution how I made use of SpringBoot and Akka together. To give some background, let me explain my case a little: In a typical online casino setup, a casino operator hosts games of a provider on its portal. There is a two way integration between online casino and game provider services to be able to launch game and to be able to process money transactions on player’s account for bets and winnings. A wallet server is a service on casino side that provides a set of REST endpoints which handles money transaction on a player’s wallet during game play.</p>

<p>SpringBoot fits nicely on setting up endpoints, injecting dependencies, processing database transactions, etc. and Akka is a great fit to model each players interaction with his wallet as an actor per game play and to supervise all players’ game play sessions.</p>

<p>Below you can find specific implementation sections with example code snippets.</p>

<h2 id="springboot-jax-rs">SpringBoot JAX-RS</h2>

<p>JAX-RS is a well-defined standart for developing REST endpoints and you can use JAX-RS with SpringBoot. All you need to do is to bring right dependencies into the scope.</p>

<div class="language-groovy highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">dependencies</span> <span class="o">{</span>

    <span class="n">testCompile</span> <span class="s1">'junit:junit'</span>

    <span class="c1">// Spring</span>
    <span class="n">compile</span> <span class="s1">'org.springframework.boot:spring-boot-starter-jersey'</span>
    <span class="n">testCompile</span> <span class="s1">'org.springframework.boot:spring-boot-starter-test'</span>
    
<span class="o">}</span>
</code></pre></div></div>

<p>I chose JAX-RS over Spring MVC, I believe, JAX-RS has better model than Spring MVC. But using it, brings a small overhead that is you need to configure it manually which is fairly easy as a Spring configuration class:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@Configuration</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">JerseyConfig</span>  <span class="kd">extends</span> <span class="nc">ResourceConfig</span> <span class="o">{</span>

    <span class="kd">public</span> <span class="nf">JerseyConfig</span><span class="o">()</span> <span class="o">{</span>
        <span class="n">packages</span><span class="o">(</span><span class="s">"com.yboyacigil.experiments.springboot.akka.walletserver.endpoints"</span><span class="o">);</span>

        <span class="n">register</span><span class="o">(</span><span class="nc">LoggingFeature</span><span class="o">.</span><span class="na">class</span><span class="o">);</span>
        <span class="n">property</span><span class="o">(</span><span class="nc">LoggingFeature</span><span class="o">.</span><span class="na">LOGGING_FEATURE_LOGGER_LEVEL_SERVER</span><span class="o">,</span> <span class="s">"INFO"</span><span class="o">);</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<h2 id="akka">Akka</h2>

<p>As mentioned above, I created one actor to handle all requests of a player during game play. Since actors have one mailbox for messages and messages are processed in order, that makes it more suitable in processing bets &amp; winnings in the order it has received. Simply named it <code class="language-plaintext highlighter-rouge">GamePlayActor</code> as follows:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@Component</span>
<span class="nd">@Scope</span><span class="o">(</span><span class="s">"prototype"</span><span class="o">)</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">GamePlayActor</span> <span class="kd">extends</span> <span class="nc">AbstractLoggingActor</span> <span class="o">{</span>

    <span class="kd">private</span> <span class="nc">AccountingService</span> <span class="n">accountingService</span><span class="o">;</span>

    <span class="kd">public</span> <span class="nf">GamePlayActor</span><span class="o">(</span><span class="nc">AccountingService</span> <span class="n">accountingService</span><span class="o">)</span> <span class="o">{</span>
        <span class="k">this</span><span class="o">.</span><span class="na">accountingService</span> <span class="o">=</span> <span class="n">accountingService</span><span class="o">;</span>
    <span class="o">}</span>

    <span class="nd">@Override</span>
    <span class="kd">public</span> <span class="nc">Receive</span> <span class="nf">createReceive</span><span class="o">()</span> <span class="o">{</span>
        <span class="k">return</span> <span class="nf">receiveBuilder</span><span class="o">()</span>
            <span class="o">.</span><span class="na">match</span><span class="o">(</span><span class="nc">GetCurrency</span><span class="o">.</span><span class="na">class</span><span class="o">,</span> <span class="k">this</span><span class="o">::</span><span class="n">receiveGetCurrency</span><span class="o">)</span>
            <span class="o">.</span><span class="na">match</span><span class="o">(</span><span class="nc">GetBalance</span><span class="o">.</span><span class="na">class</span><span class="o">,</span> <span class="k">this</span><span class="o">::</span><span class="n">receiveGetBalance</span><span class="o">)</span>
            <span class="o">.</span><span class="na">matchAny</span><span class="o">(</span><span class="n">o</span> <span class="o">-&gt;</span> <span class="n">log</span><span class="o">().</span><span class="na">info</span><span class="o">(</span><span class="s">"Received unknown message: {}"</span><span class="o">,</span> <span class="n">o</span><span class="o">))</span>
            <span class="o">.</span><span class="na">build</span><span class="o">();</span>
    <span class="o">}</span>

  <span class="c1">// rest is omitted</span>
<span class="o">}</span>
</code></pre></div></div>

<p>As you notice, the actor is defined as a Spring component with <code class="language-plaintext highlighter-rouge">prototype</code> scope that is a necessity for actor system andSpring can inject all dependencies that it needs.</p>

<p>We need one more thing which is an extension for actor system that can produce actor instances with their dependencies.</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">akka.actor.Extension</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">akka.actor.Props</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">org.springframework.context.ApplicationContext</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">org.springframework.stereotype.Component</span><span class="o">;</span>

<span class="nd">@Component</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">SpringExtension</span> <span class="kd">implements</span> <span class="nc">Extension</span> <span class="o">{</span>

    <span class="kd">private</span> <span class="nc">ApplicationContext</span> <span class="n">applicationContext</span><span class="o">;</span>

    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">initialize</span><span class="o">(</span><span class="nc">ApplicationContext</span> <span class="n">applicationContext</span><span class="o">)</span> <span class="o">{</span>
        <span class="k">this</span><span class="o">.</span><span class="na">applicationContext</span> <span class="o">=</span> <span class="n">applicationContext</span><span class="o">;</span>
    <span class="o">}</span>

    <span class="kd">public</span> <span class="nc">Props</span> <span class="nf">props</span><span class="o">(</span><span class="nc">String</span> <span class="n">actorBeanName</span><span class="o">)</span> <span class="o">{</span>
        <span class="k">return</span> <span class="nc">Props</span><span class="o">.</span><span class="na">create</span><span class="o">(</span><span class="nc">SpringActorProducer</span><span class="o">.</span><span class="na">class</span><span class="o">,</span> <span class="n">applicationContext</span><span class="o">,</span> <span class="n">actorBeanName</span><span class="o">);</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>where <code class="language-plaintext highlighter-rouge">SpringActorProducer</code> is a factory class for creating actor instances as Spring beans:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">akka.actor.Actor</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">akka.actor.IndirectActorProducer</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">org.springframework.context.ApplicationContext</span><span class="o">;</span>

<span class="kd">public</span> <span class="kd">class</span> <span class="nc">SpringActorProducer</span> <span class="kd">implements</span> <span class="nc">IndirectActorProducer</span> <span class="o">{</span>

    <span class="kd">private</span> <span class="kd">final</span> <span class="nc">ApplicationContext</span> <span class="n">applicationContext</span><span class="o">;</span>
    <span class="kd">private</span> <span class="kd">final</span> <span class="nc">String</span> <span class="n">actorBeanName</span><span class="o">;</span>

    <span class="kd">public</span> <span class="nf">SpringActorProducer</span><span class="o">(</span><span class="nc">ApplicationContext</span> <span class="n">applicationContext</span><span class="o">,</span>
        <span class="nc">String</span> <span class="n">actorBeanName</span><span class="o">)</span> <span class="o">{</span>
        <span class="k">this</span><span class="o">.</span><span class="na">applicationContext</span> <span class="o">=</span> <span class="n">applicationContext</span><span class="o">;</span>
        <span class="k">this</span><span class="o">.</span><span class="na">actorBeanName</span> <span class="o">=</span> <span class="n">actorBeanName</span><span class="o">;</span>
    <span class="o">}</span>

    <span class="nd">@Override</span>
    <span class="kd">public</span> <span class="nc">Actor</span> <span class="nf">produce</span><span class="o">()</span> <span class="o">{</span>
        <span class="k">return</span> <span class="o">(</span><span class="nc">Actor</span><span class="o">)</span> <span class="n">applicationContext</span><span class="o">.</span><span class="na">getBean</span><span class="o">(</span><span class="n">actorBeanName</span><span class="o">);</span>
    <span class="o">}</span>

    <span class="nd">@SuppressWarnings</span><span class="o">(</span><span class="s">"unchecked"</span><span class="o">)</span>
    <span class="nd">@Override</span>
    <span class="kd">public</span> <span class="nc">Class</span><span class="o">&lt;?</span> <span class="kd">extends</span> <span class="nc">Actor</span><span class="o">&gt;</span> <span class="nf">actorClass</span><span class="o">()</span> <span class="o">{</span>
        <span class="k">return</span> <span class="o">(</span><span class="nc">Class</span><span class="o">&lt;?</span> <span class="kd">extends</span> <span class="nc">Actor</span><span class="o">&gt;)</span> <span class="n">applicationContext</span><span class="o">.</span><span class="na">getType</span><span class="o">(</span><span class="n">actorBeanName</span><span class="o">);</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<h2 id="reactivity">Reactivity</h2>

<p>Akka actor are by design reactive. To complete the picture, you can use JAX-RS <code class="language-plaintext highlighter-rouge">AsyncResponse</code> in your endpoint:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@GET</span>
<span class="nd">@Path</span><span class="o">(</span><span class="s">"/players/{pid}/account/balance"</span><span class="o">)</span>
<span class="nd">@Produces</span><span class="o">(</span><span class="nc">MediaType</span><span class="o">.</span><span class="na">APPLICATION_JSON</span><span class="o">)</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">getBalance</span><span class="o">(</span><span class="nd">@Suspended</span> <span class="kd">final</span> <span class="nc">AsyncResponse</span> <span class="n">asyncResponse</span><span class="o">,</span> <span class="nd">@PathParam</span><span class="o">(</span><span class="s">"pid"</span><span class="o">)</span> <span class="nc">Long</span> <span class="n">pid</span><span class="o">)</span> <span class="o">{</span>

  <span class="nc">GetBalance</span> <span class="n">getBalance</span> <span class="o">=</span> <span class="nc">GetBalance</span><span class="o">.</span><span class="na">builder</span><span class="o">()</span>
    <span class="o">.</span><span class="na">pid</span><span class="o">(</span><span class="n">pid</span><span class="o">)</span>
    <span class="o">.</span><span class="na">gameCode</span><span class="o">(</span><span class="s">"not-important-atm"</span><span class="o">)</span>
    <span class="o">.</span><span class="na">build</span><span class="o">();</span>

  <span class="n">askForResult</span><span class="o">(</span><span class="n">asyncResponse</span><span class="o">,</span> <span class="n">getBalance</span><span class="o">);</span>
<span class="o">}</span>

<span class="nd">@SuppressWarnings</span><span class="o">(</span><span class="s">"unchecked"</span><span class="o">)</span>
<span class="kd">private</span> <span class="kt">void</span> <span class="nf">askForResult</span><span class="o">(</span><span class="kd">final</span> <span class="nc">AsyncResponse</span> <span class="n">asyncResponse</span><span class="o">,</span> <span class="nc">GameMessage</span> <span class="n">gameMessage</span><span class="o">)</span> <span class="o">{</span>
    <span class="nc">Future</span><span class="o">&lt;</span><span class="nc">Object</span><span class="o">&gt;</span> <span class="n">result</span> <span class="o">=</span> <span class="nc">Patterns</span><span class="o">.</span><span class="na">ask</span><span class="o">(</span><span class="n">gamePlaySupervisor</span><span class="o">,</span> <span class="n">gameMessage</span><span class="o">,</span> <span class="mi">1000L</span><span class="o">);</span>

    <span class="nc">FutureConverters</span><span class="o">.</span><span class="na">toJava</span><span class="o">(</span><span class="n">result</span><span class="o">).</span><span class="na">toCompletableFuture</span><span class="o">()</span>
        <span class="o">.</span><span class="na">thenApply</span><span class="o">(</span><span class="n">o</span> <span class="o">-&gt;</span> <span class="o">{</span>
            <span class="k">if</span> <span class="o">(</span><span class="n">o</span> <span class="k">instanceof</span> <span class="nc">Optional</span><span class="o">&lt;?&gt;)</span> <span class="o">{</span>
                <span class="nc">Optional</span><span class="o">&lt;</span><span class="nc">Currency</span><span class="o">&gt;</span> <span class="n">optionalCurrency</span> <span class="o">=</span> <span class="o">(</span><span class="nc">Optional</span><span class="o">&lt;</span><span class="nc">Currency</span><span class="o">&gt;)</span> <span class="n">o</span><span class="o">;</span>
                <span class="k">if</span> <span class="o">(</span><span class="n">optionalCurrency</span><span class="o">.</span><span class="na">isPresent</span><span class="o">())</span> <span class="o">{</span>
                    <span class="n">log</span><span class="o">.</span><span class="na">debug</span><span class="o">(</span><span class="s">"Returning currency result: {}"</span><span class="o">,</span> <span class="n">o</span><span class="o">);</span>
                    <span class="k">return</span> <span class="n">asyncResponse</span><span class="o">.</span><span class="na">resume</span><span class="o">(</span><span class="nc">Response</span><span class="o">.</span><span class="na">ok</span><span class="o">().</span><span class="na">entity</span><span class="o">(((</span><span class="nc">Optional</span><span class="o">&lt;</span><span class="nc">Currency</span><span class="o">&gt;)</span> <span class="n">o</span><span class="o">).</span><span class="na">get</span><span class="o">()).</span><span class="na">build</span><span class="o">());</span>
                <span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
                    <span class="k">throw</span> <span class="k">new</span> <span class="nf">NotFoundException</span><span class="o">(</span><span class="s">"No player/currency found"</span><span class="o">);</span>
                <span class="o">}</span>
            <span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
                <span class="n">log</span><span class="o">.</span><span class="na">warn</span><span class="o">(</span><span class="s">"Unexpected result: {}"</span><span class="o">,</span> <span class="n">o</span><span class="o">);</span>
                <span class="k">throw</span> <span class="k">new</span> <span class="nf">InternalServerErrorException</span><span class="o">(</span><span class="s">"Unexpected result"</span><span class="o">);</span>
            <span class="o">}</span>
        <span class="o">})</span>
        <span class="o">.</span><span class="na">exceptionally</span><span class="o">(</span><span class="nl">asyncResponse:</span><span class="o">:</span><span class="n">resume</span><span class="o">);</span>
<span class="o">}</span>
</code></pre></div></div>

<p>where you ask for response from an actor, the result is a scala <code class="language-plaintext highlighter-rouge">Future</code> which is needed to be converted to a java <code class="language-plaintext highlighter-rouge">CompleteableFuture</code> to create responses back to callers asynchronously.</p>

<h2 id="polyglot-approach">Polyglot Approach</h2>

<p>Finally, I want to show how you can use multiple languages in your project. You can take advantage of different programming languages on areas on your project where it makes a good fit. For my case, I used Spock that has nice syntax to better describe your tests. Spock is written in Groovy and uses language features to make it possible.</p>

<p>To use Groovy in your project just enable plugin:</p>

<div class="language-groovy highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">plugins</span> <span class="o">{</span>
    <span class="n">id</span> <span class="s1">'java'</span>
    <span class="n">id</span> <span class="s1">'groovy'</span>

<span class="o">}</span>
</code></pre></div></div>

<p>and for Spock bring these in to compile and test scopes:</p>

<div class="language-groovy highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">dependencies</span> <span class="o">{</span>
    
    <span class="c1">// Spock</span>
    <span class="n">compile</span> <span class="s1">'org.codehaus.groovy:groovy-all:2.4.10'</span>
    <span class="n">testCompile</span> <span class="s1">'org.spockframework:spock-core:1.1-groovy-2.4'</span>
    <span class="n">testCompile</span> <span class="s1">'org.spockframework:spock-spring:1.1-groovy-2.4'</span>
    
<span class="o">}</span>
</code></pre></div></div>

<p>Then you can write integration tests like:</p>

<div class="language-groovy highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">def</span> <span class="s2">".../currency should return ok for an existing player info"</span><span class="o">()</span> <span class="o">{</span>
    <span class="nl">given:</span>
        <span class="kt">def</span> <span class="n">pid</span> <span class="o">=</span> <span class="mi">1L</span>
        <span class="kt">def</span> <span class="n">url</span> <span class="o">=</span> <span class="s2">"/walletserver/players/${pid}/account/currency"</span>
        <span class="kt">def</span> <span class="n">isoCurrencyCode</span> <span class="o">=</span> <span class="s2">"SEK"</span>
        <span class="kt">def</span> <span class="n">playerInfo</span> <span class="o">=</span> <span class="n">AccountingService</span><span class="o">.</span><span class="na">PlayerInfo</span><span class="o">.</span><span class="na">builder</span><span class="o">()</span>
        <span class="o">.</span><span class="na">pid</span><span class="o">(</span><span class="n">pid</span><span class="o">)</span>
        <span class="o">.</span><span class="na">isoCurrencyCode</span><span class="o">(</span><span class="n">isoCurrencyCode</span><span class="o">)</span>
        <span class="o">.</span><span class="na">build</span><span class="o">()</span>
        <span class="mi">1</span> <span class="o">*</span> <span class="n">accountingService</span><span class="o">.</span><span class="na">getPlayerInfo</span><span class="o">(</span><span class="n">pid</span><span class="o">)</span> <span class="o">&gt;&gt;</span> <span class="n">Optional</span><span class="o">.</span><span class="na">of</span><span class="o">(</span><span class="n">playerInfo</span><span class="o">)</span>

    <span class="nl">when:</span>
        <span class="kt">def</span> <span class="n">entity</span> <span class="o">=</span>
                <span class="n">restTemplate</span><span class="o">.</span><span class="na">getForEntity</span><span class="o">(</span><span class="n">url</span><span class="o">,</span> <span class="n">Currency</span><span class="o">.</span><span class="na">class</span><span class="o">)</span>

    <span class="nl">then:</span>
        <span class="n">entity</span><span class="o">.</span><span class="na">statusCode</span> <span class="o">==</span> <span class="n">HttpStatus</span><span class="o">.</span><span class="na">OK</span>
        <span class="n">entity</span><span class="o">.</span><span class="na">body</span><span class="o">.</span><span class="na">pid</span> <span class="o">==</span> <span class="n">pid</span>
        <span class="n">entity</span><span class="o">.</span><span class="na">body</span><span class="o">.</span><span class="na">isoCurrencyCode</span> <span class="o">==</span> <span class="n">isoCurrencyCode</span>
<span class="o">}</span>
</code></pre></div></div>

<p>In Spock, you can use interpolated strings as the test fixture names and the <code class="language-plaintext highlighter-rouge">given</code>, <code class="language-plaintext highlighter-rouge">when</code>, <code class="language-plaintext highlighter-rouge">then</code>
labels nicely express the intent how you want to test.</p>

<p>If you are interested more on the complete solution, source code can be found on <a href="https://github.com/yboyacigil/springboot-akka-walletserver">Github</a></p>]]></content><author><name>Yusuf Boyacıgil</name></author><category term="english" /><category term="springboot" /><category term="akka" /><summary type="html"><![CDATA[In this post, I will share how to use SpringBoot together with Akka framework to build a reactive rest service (a wallet server) and also demonstrate how the polyglot approach can be applied to your project for writing tests using a very nice testing framework Spock in Groovy programming language.]]></summary></entry><entry><title type="html">How to Use Machine Learning to Recommend Games Based on Player Preference</title><link href="http://www.yboyacigil.com/english/machine-learning/how-to-use-ai-for-recommending-games/" rel="alternate" type="text/html" title="How to Use Machine Learning to Recommend Games Based on Player Preference" /><published>2018-09-05T13:47:00+00:00</published><updated>2018-09-05T13:47:00+00:00</updated><id>http://www.yboyacigil.com/english/machine-learning/how-to-use-ai-for-recommending-games</id><content type="html" xml:base="http://www.yboyacigil.com/english/machine-learning/how-to-use-ai-for-recommending-games/"><![CDATA[<p>In this post, I will show how to use machine learning to recommend games for a player based on his/her preference. This can be a used to personalize the display order of games if there are plenty of games hence creates engagement and early conversion by placing games that a player prefers to see on top.</p>

<p>The core enabler of the solution is <a href="http://predictionio.apache.org">Apache PredictionIO</a> which is an open source machine learning server built on top of a state-of-the-art open source stack for developers and data scientists to create predictive engines for any machine learning task.</p>

<p>You can <a href="https://predictionio.apache.org/install/">install</a> Apache PredictionIO on your machine as a full machine learning stack, bundled with Apache Spark, MLlib, HBase, Spray and Elasticsearch, which simplifies and accelerates scalable machine learning infrastructure management.</p>

<p>Using customizable templates, building and deploying a predictive engine is super easy.</p>

<p>As for my solution, I used a template for ranking 
products and adapted to my use case: In an online casino, a player is offered a ton of casino games and my aim is to be able to list relevant games to the player.</p>

<p>Once I train my model, I would be able to list games even if the player is a newly registered or I would rank games of a specific category of games thanks to the machine learning algorithm (<a href="https://spark.apache.org/docs/2.0.0/api/java/org/apache/spark/mllib/recommendation/ALS.html">ALS</a>) behind.</p>

<h2 id="defining-model--collecting-data">Defining Model &amp; Collecting Data</h2>
<p>Now let’s talk a little about the data to train the algorithm.</p>

<p>We have two entities and one event which are Game, Player and Play Event respectively. Game represents a casino game with its id. Player is the customer of the online casino playing casino games, again represented with its id and the Play Event simply defines a game being played by a player at a certain time.</p>

<p>In online casino system collecting this info is no brainer. The only concern is how to import the data into the system. PredictionIO comes with a data store called Event Server which is backed by RDBMS (PostgreSQL and MySQL supported) or Elastic Search, HBase. Importing data is easy you can either use REST API or SDKs offered in Python, PHP, Ruby and Java.</p>

<p>Using Python SDK, I imported my events writing the script <code class="language-plaintext highlighter-rouge">import_player_events.py</code>:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>python import_player_events.py <span class="nt">--access_key</span> &lt;your access key&gt;
</code></pre></div></div>

<p>where <code class="language-plaintext highlighter-rouge">access_key</code> is the key that is provided by PredictionIO for your predictive engine.</p>

<p>The important thing to note in here is that you need to define your model according to the algorithm you use for your engine.</p>

<h2 id="training-the-model">Training the Model</h2>

<p>Training is fairly easy with PredictionIO. All you need to run:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pio train
</code></pre></div></div>

<p>in your project folder.</p>

<h2 id="recommending-games">Recommending Games</h2>

<p>Once you trained your model and deployed your engine to PredictionIO you can retrieve recommended games by the query interface which is a REST endpoint of your engine. Later it can be utilized as a microservice integrated with the rest of your system.</p>

<p>Suppose you want to get recommended games for a given player. Just call the query endpoint with game ids like:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl <span class="nt">-H</span> <span class="s2">"Content-Type: application/json"</span> <span class="se">\</span>
<span class="nt">-d</span> <span class="s1">'{ "player": 136286, "games": [0, 1, 2, 3, 4]}'</span> <span class="se">\</span>
http://localhost:8000/queries.json
</code></pre></div></div>

<p>The games will be sorted out in the response like:</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"gameScores"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
    </span><span class="p">{</span><span class="w">
      </span><span class="nl">"game"</span><span class="p">:</span><span class="w"> </span><span class="mi">3</span><span class="p">,</span><span class="w">
      </span><span class="nl">"score"</span><span class="p">:</span><span class="w"> </span><span class="mf">0.9574813396659806</span><span class="w">
    </span><span class="p">},</span><span class="w">
    </span><span class="p">{</span><span class="w">
      </span><span class="nl">"game"</span><span class="p">:</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w">
      </span><span class="nl">"score"</span><span class="p">:</span><span class="w"> </span><span class="mf">0.0016224116521859396</span><span class="w">
    </span><span class="p">},</span><span class="w">
    </span><span class="p">{</span><span class="w">
      </span><span class="nl">"game"</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w">
      </span><span class="nl">"score"</span><span class="p">:</span><span class="w"> </span><span class="mf">0.0</span><span class="w">
    </span><span class="p">},</span><span class="w">
    </span><span class="p">{</span><span class="w">
      </span><span class="nl">"game"</span><span class="p">:</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span><span class="w">
      </span><span class="nl">"score"</span><span class="p">:</span><span class="w"> </span><span class="mf">0.0</span><span class="w">
    </span><span class="p">},</span><span class="w">
    </span><span class="p">{</span><span class="w">
      </span><span class="nl">"game"</span><span class="p">:</span><span class="w"> </span><span class="mi">4</span><span class="p">,</span><span class="w">
      </span><span class="nl">"score"</span><span class="p">:</span><span class="w"> </span><span class="mf">0.0</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">],</span><span class="w">
  </span><span class="nl">"isOriginal"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<p>The games with higher scores are the ones you can display them to that specific player.</p>

<p>Check the project out in <a href="https://github.com/yboyacigil/game-recommendation-engine">Github</a>.</p>]]></content><author><name>Yusuf Boyacıgil</name></author><category term="english" /><category term="machine-learning" /><summary type="html"><![CDATA[In this post, I will show how to use machine learning to recommend games for a player based on his/her preference. This can be a used to personalize the display order of games if there are plenty of games hence creates engagement and early conversion by placing games that a player prefers to see on top.]]></summary></entry><entry><title type="html">Oracle 12c Pattern Matching</title><link href="http://www.yboyacigil.com/turkish/oracle-12c-pattern-matching/" rel="alternate" type="text/html" title="Oracle 12c Pattern Matching" /><published>2014-10-20T14:16:01+00:00</published><updated>2014-10-20T14:16:01+00:00</updated><id>http://www.yboyacigil.com/turkish/oracle-12c-pattern-matching</id><content type="html" xml:base="http://www.yboyacigil.com/turkish/oracle-12c-pattern-matching/"><![CDATA[<p>Oracle Türkiye’nin geçen hafta düzenlediği Oracle 12c etkinliğinde, yeni sürüm ile ilgili birçok yenilik tanıtıldı. Bunlar arasında: Database As Service, Pluggable DB, In-Memory Option ve Pattern Matching daha çok dikkatimi çekti.</p>

<p>Database As Service 12c ile gelen bulut hizmetini verebilmek için olmazsa olmaz bir özellik olarak karşımıza çıkıyor. Veritabanını donanım, kurulum, yedekleme derdini düşünmeden basit bir hizmet satın almak da artık mümkün olabilir. Mesela bir Amazon Elastic Compute Cloud (EC2) servisi gibi internet üzerinde bir Oracle veri tabanı kiralayabiliriz. Etkinlikte daha çok private cloud’dan bahsedildi. İşin public tarafı ile ilgili ne tür opsiyonlar olduğundan çok bahsedilmedi.</p>

<p>Pluggable DB bir Oracle kurulumunda birbirinden tamamen bağımsız ve farklı şekilde yapılandırılabilen birden çok veritabanını çalıştırmayı mümkün kılacak bir teknoloji. Her bir veritabanı için ayrı kurulum olması zorunluluğu çok doğal değil. Yani ilişkisel veri tabanları konseptinde veritabanını da bir obje olarak düşünürsek, neden tek bir veritabanı engine’i aynı anda birden fazla veritabanına hizmet veremesin ki? Pluggable DB ile bu sorunun artık bir cevabı var.</p>

<p>In-Memory Option tablo, partition bazında tüm veya seçilen kolonları hafızaya alıp, veri tutarlılığını da koruyarak sorguları çok hızlı çalışmayı sağlayacak bir yenilik. Onu diğer cache çözümlerinden farklı kılan veriye her zaman en güncel hali ile erişimi sağlaması. Oracle’ın hafızasında (SGA) ayrı bir alan (Column Store) ayrılyor ve verinin en güncel halini “transaction commit” esnasında bu hafıza alanında da yazılıyor. Bu yeni hafıza alanında tablo satır bazlı değil kolon bazlı tutuluyor; böylelikle veriye erişim ve verinin hafızada kapladığı alanı optimum seviyeye çıkartılıyor. Netice itibariyle verinin analizine yönelik sorgularda doğru konfigurasyon yapılırsa sorgu hızında in-memory option’la 1000 kat ve belki daha fazla bir iyileşme yaşandığına dair örnek çalışmaların olduğu söyleniyor. Yalnız verinin devamlı güncellendiği (OLTP) durumda bu kadar hızlı sorgu performansı olmayacağı tabi ki eskisine oranla daha hızlı olacağını bekleyebiliriz.</p>

<p>Pattern Matching SQL dünyasında bir süredir beklenen veri üzerinde belli bir paterne uygun veriyi bulmayı kolaylaştıracak önemli bir özellik. Veriyi analiz ederken trend’leri belirlemek, anormal durumları tespit etmek, sahtekarlık/iç usulsüzlük tespiti tipik kullanım alanları arasında.</p>

<p>Aşağıda bunun nasıl kullanılabileceği ile ilgili bir sorgu örneğini görebiliriz.</p>

<script src="https://gist.github.com/d5397b96c4600815b863.js"> </script>

<p>Örnekte bir hesaptan para çekip (WTD) arada başka bir işlem olmaksızın parayı aynı hesaba geri yatıran (DEP) banka çalışanlarını tespit edecek bir sorgu verilmiştir. Banka çalışanının bir hesaptaki parayı zimmetine geçirip bir süre sonra aynı hesaba geri yatırması tespit edilmesi gereken şüpheli bir işlemdir.</p>

<p>Sql’in yapısına geçersek, SELECT ifadesinin sonuna MATCH_RECOGNIZE cümleciği koyarak başlıyoruz. Burada:</p>

<ul>
  <li>PARTITION BY EMP ve ORDER BY TSTAMP kayıtlara çalışan bazında ve tarih sırasına göre erişmek istediğimizi,</li>
  <li>MEASURES alt cümleciği sorgu sonucunda pattern’e uyan hangi kolonları listeleyeceğimizi,</li>
  <li>ONE ROW PER MATCH pattern’e uyan tüm eşleşmeler için sadece bir kayıt dönmesini,</li>
  <li>PATTERN bu sorguda kullanmak istediğimiz pattern’i yani önce para çekme (WITHDRAW) sonra en azından bir para yatırmayı (DEPOSIT),</li>
  <li>DEFINE ise para çekme ve yatırmanın ne demek olduğunu</li>
</ul>

<p>tanımlar.</p>

<p>Sorgunun kalan kısmında pattern’e uyan kayıtların aynı çalışan ve aynı hesap üzerinden yapılmış olması koşulunu içermektedir. Eşleşen kayıt sorgunun alt kısmında gösterilmiştir.</p>

<p>Örnekte de görüldüğü gibi MATCH_RECOGNIZE cümleciği ile okuması ve anlaşılması kolay sorgular yazabiliriz.</p>

<p>Oracle 12c veritabanı sistemi en azından bu yeni özelliği ile veri analizinde rakiplerinden bir adım öne çıkıyor.</p>]]></content><author><name>Yusuf Boyacıgil</name></author><category term="turkish" /><summary type="html"><![CDATA[Oracle Türkiye’nin geçen hafta düzenlediği Oracle 12c etkinliğinde, yeni sürüm ile ilgili birçok yenilik tanıtıldı. Bunlar arasında: Database As Service, Pluggable DB, In-Memory Option ve Pattern Matching daha çok dikkatimi çekti.]]></summary></entry><entry><title type="html">Apache Camel ile Veri Entegrasyonu</title><link href="http://www.yboyacigil.com/turkish/apache-camel-data-integration/" rel="alternate" type="text/html" title="Apache Camel ile Veri Entegrasyonu" /><published>2014-10-13T14:16:01+00:00</published><updated>2014-10-13T14:16:01+00:00</updated><id>http://www.yboyacigil.com/turkish/apache-camel-data-integration</id><content type="html" xml:base="http://www.yboyacigil.com/turkish/apache-camel-data-integration/"><![CDATA[<p>Finans/Bankacılık alanı başta olmak üzere, BT dünyasında veri işleme üzerine geliştirilen çözümlerin adreslemesi gereken temel sorun verinin nasıl kullanılabilir hale getirileceği, nasıl doğrulanıp dönüştürüleceği yani veri entegrasyonudur.</p>

<p>Veri entegrasyonu konusunda çözüm sağlayıcılar daha çok kendilerine has yöntemler sunuyorlar ki genellikle bu ilişkisel veri tabanları üzerinden verinin paylaşılması veya içeri alınması şeklinde gerçekleniyor.</p>

<p>Bu yaklaşım hızlı bir şekilde projelerin ilerlemesini sağlayabilir. Ancak potansiyel olarak bir takım dezavantajlar barındırıyor:</p>

<ol>
  <li>Alternatif kaynaklardan veri aktarmak için ek çözümler gerekir. Bu durum rekabet anlamında çözüm sağlayıcıya zorluk yaşatacaktır. Diğer kaynakları kullanmak için ek geliştirmeye ihtiyaç duyulacaktır.</li>
  <li>Hızlı (ve ucuz) çözümler tek bir müşteriye/duruma göre geliştirildiği için, entegrasyon alanı ile ilgili tüm durumları hesaba katarak geniş bir bakış açısıyla ele alamazlar. Bu yüzden beklenmedik sorunlarla her an karşılaşılabilir.</li>
  <li>Çözüm sağlayıcı kendi geliştirdiği yöntem ile ilgili tüm sorunları tek başına çözmek durumundadır.
Entegrasyon her yönüyle kompleks bir iştir. Kompleks problemlerle baş etmek için insan varoluşundan bu yana şablonları kullanagelmiştir. Tabi ki entegrasyon problemi için de bir takım <a href="http://www.eaipatterns.com/">entegrasyon şablonları</a> geliştirilmiştir.</li>
</ol>

<p><a href="http://camel.apache.org">Apache Camel</a> işte bu entegrasyon şablonlarını kullanarak, Java’da açık kaynaklı, neredeyse tüm entegrasyon ihtiyaçlarına cevap veren bir çözüm olarak kullanıma hazır olarak beklemektedir. Camel yukarıda bahsedilen sorunları basit bir şekilde adreslemektedir.</p>

<p>Camel veriyi hem tüketirken hem de üretirken farklı veri kaynakları ile birlikte bir arada kullanılabilir. Mesela HTTP client üzerinden toplanan bir veri dönüştürülüp doğrulandıktan sonra veritabanına yazılacak hale dönüştürülebilir. Camel ile böyle bir veri entegrasyonunu hiçbir geliştirme yapmadan gerçeklemek mümkündür. Aklınıza gelebilecek hemen hemen tüm veri entegrasyon noktaları uygun Camel bileşenleri (Camel Components) kullanılarak bağlanabilir.</p>

<p>Bunlardan bir kısmı:</p>

<ul>
  <li>File (Dosya)</li>
  <li>HTTP</li>
  <li>FTP</li>
  <li>JMS</li>
  <li>JDBC</li>
</ul>

<p>şeklinde sıralanabilir.</p>

<p>Bileşenler hem veri okurken (from) veya veriyi yazarken (to) kullanılabilir.</p>

<p>Camel bir Java kütüphanesi şeklinde mevcut uygulamalara eklenebildiği gibi, çok kullanılan Spring gibi framework’lerle de çalışabilecek şekilde tasarlanmıştır ve Spring’in XML konfigurasyon dosyasında veri entegrasyonu için gerekli konfigurasyon standart bileşenlerle hiç kod yazmadan yapılandırılabilir.</p>

<p>Camel veri çözümleri konusunda uygulama geliştiren çözüm üretecilerinin muhakkak değerlendirmeleri gereken önemli bir kaynaktır.</p>]]></content><author><name>Yusuf Boyacıgil</name></author><category term="turkish" /><summary type="html"><![CDATA[Finans/Bankacılık alanı başta olmak üzere, BT dünyasında veri işleme üzerine geliştirilen çözümlerin adreslemesi gereken temel sorun verinin nasıl kullanılabilir hale getirileceği, nasıl doğrulanıp dönüştürüleceği yani veri entegrasyonudur.]]></summary></entry><entry><title type="html">IntellijIdea 11 ile NodeJS Kullanımı</title><link href="http://www.yboyacigil.com/turkish/nodejs/intelljidea11-nodejs-setup/" rel="alternate" type="text/html" title="IntellijIdea 11 ile NodeJS Kullanımı" /><published>2013-10-13T14:16:01+00:00</published><updated>2013-10-13T14:16:01+00:00</updated><id>http://www.yboyacigil.com/turkish/nodejs/intelljidea11-nodejs-setup</id><content type="html" xml:base="http://www.yboyacigil.com/turkish/nodejs/intelljidea11-nodejs-setup/"><![CDATA[<p>Javascript ile geliştirme yapanlar için faydalı olacağını düşündüğüm bir çalışma ortamını sizlerle paylaşmak istiyorum.</p>

<p>Hazırladığım ortam IntelliJ IDEA 11 + <a href="http://plugins.jetbrains.com/plugin/?id=6098">NodeJS Plugin</a> ve <a href="http://nodejs.org">NodeJS</a> kurulularından oluşuyor.</p>

<p>IDEA javascript geliştirmek için piyasada olan en başarılı editor’lerden birini sağlıyor. Sadece kodu renklendirme, tamamlama değil bunun yanında JSHint’i de devreye alıp, javascript hatalarını ve doğru yazım kuralları konusunda da sizi uyarıyor.</p>

<p>NodeJS ile konunun ilintisi ise şuradan kaynaklanıyor: Javascript ile kodu yazarken herhangi bir kod parçasını   anında çalıştırıp sonucunu görebilmeniz için önemli bir araç. Bunu IDE içerisinden çıkmadan yapabilmek size çok hız kazandıracağı için NodeJS’i IDEA içerisinden çalıştırabilmeniz gerekir. Onun için de Node JS Plugin’ini kurmalısınız.</p>

<p><code class="language-plaintext highlighter-rouge">Path To Node</code> sizin makinenizdeki Node JS’in yerini ve Working Directory üzerinde çalıştığınız javascript dosyalarının olduğu yeri göstermeli. <code class="language-plaintext highlighter-rouge">Path to Node App JS File</code>‘ı girmediğiniz için size kızabilir ama dikkate almayın bunu. :)</p>

<p>Bundan sonra IDEA’da hazırladığımız Run/Debug Confguration’u olan  NodeJS Interactive Shell’i (yukarıda bu ismi vermiştik) çalıştırıp, Run penceresinde denemelerinizi yapabilirsiniz.</p>

<p>Burada bahsetmem gereken bir konu daha var. Eğer hazırladığınız kodu bir NodeJS modülü haline getirirseniz tüm kodu Node’a yükleyebilir üzerinde oynayabilirsiniz. Node modülü haline getirmek için yapmanız gereken export’ları tanımlamak olacaktır. Buna ilaveten aşağıdaki gibi reload fonksiyonunu da eklerseniz kodu değiştirdikten sonra yeniden yükleyebilecek duruma da geleceksiniz.</p>

<script src="https://gist.github.com/5965893.js"> </script>

<p>Umarım yukarıda hızlıca bahsettiğim konfigurasyon başkalarının da işine yarar.</p>]]></content><author><name>Yusuf Boyacıgil</name></author><category term="turkish" /><category term="nodejs" /><summary type="html"><![CDATA[Javascript ile geliştirme yapanlar için faydalı olacağını düşündüğüm bir çalışma ortamını sizlerle paylaşmak istiyorum.]]></summary></entry><entry><title type="html">Scala ‘lazy val’</title><link href="http://www.yboyacigil.com/turkish/scala/scala-lazy-val/" rel="alternate" type="text/html" title="Scala ‘lazy val’" /><published>2013-01-20T14:16:01+00:00</published><updated>2013-01-20T14:16:01+00:00</updated><id>http://www.yboyacigil.com/turkish/scala/scala-lazy-val</id><content type="html" xml:base="http://www.yboyacigil.com/turkish/scala/scala-lazy-val/"><![CDATA[<p>Scala’da değişken/argüman tanımlarken iki tane anahtar kelime var: <code class="language-plaintext highlighter-rouge">var</code> ve <code class="language-plaintext highlighter-rouge">val</code>. İlki için söylecek çok bir şey yok. Değişken tanımlamak için var’ı kullanmak durumundasın. Ama ikincisi aynı Java’daki <code class="language-plaintext highlighter-rouge">final</code> gibi sadece ilk seferinde bir değer atanmasını istediklerini tanımlamaya yarıyor. İkinci defa bir atama yapamıyorsun; aslında program içerisinde böyle sadece bir kere atama yapmaktan ziyade <code class="language-plaintext highlighter-rouge">val</code> ile tanımladıkların daha çok sonradan değerinin değiştirilmesini istemediğin değişkenler içindir.</p>

<script src="https://gist.github.com/5989762.js"> </script>

<p><code class="language-plaintext highlighter-rouge">var</code> ve <code class="language-plaintext highlighter-rouge">val</code>‘ı sadece değişkenleri tanımlarken değil aynı zamanda fonkisyon ve sınıf yapılandırıcıları (constructor) parametrelerini tanımlarken de kullanabilirsin. Bu durumda <code class="language-plaintext highlighter-rouge">var</code> ile tanımladığın parametreler fonksiyon ve yapılandırıcı içerisinde değiştirilebilirken, <code class="language-plaintext highlighter-rouge">val</code> ile tanımladıklarının sadece değerini okuyabilirsin.</p>

<p>Bunların yanında bir <code class="language-plaintext highlighter-rouge">lazy val</code> diye bir anahtar kelime daha var. Lazy isminden anlaşılabileceği veya programlamaya aşina olanlar için belli şimdi değil sonrayı çağrıştırıyor. Değişkenin değerini şimdi değil de sonra ata demek. Sonra ne zaman? İlk defa o değişkene kod çalışırken erişildiği zaman.</p>

<script src="https://gist.github.com/5989774.js"> </script>

<p>Yukarıda <code class="language-plaintext highlighter-rouge">y</code> değişkeni <code class="language-plaintext highlighter-rouge">lazy val</code> olarak tanımladık ve erişene kadar değer atamadığını görebiliyoruz. Yukarıdaki örneklerde atama yaparken <code class="language-plaintext highlighter-rouge">{ println("..."); ... }</code> dikkatinizi çekmiştir. Scala’da kod blokları <code class="language-plaintext highlighter-rouge">{...}</code> arasında tanımlanır ve atama yaparken de bir kod bloğu kullanabilirsiniz.</p>

<p><code class="language-plaintext highlighter-rouge">val</code> diye tanımladığımız değişkenler kod çalışırken en az bir kez yazılacak ve belki bir kere, on kere, yüz kere, bin kere okunacak belki de hiç okunmayacak(!). Madem okunmaya da bilir o zaman okunmayacak birşey okunana kadar atamazsak hafızayı daha az kullanmış oluruz. Onun için değişkeni <code class="language-plaintext highlighter-rouge">lazy val</code> ile tanımlayabiliriz. Bu yöntem hafıza kullanımı açısından faydalı olsa da cpu’yu normal bir atama gibi değil de daha fazla meşgul ediyor. Nedeni her erişimde en azından bir kez atama yapıldı mı yapılmadı mı diye kontrol etmek gerekiyor bir de ufak bir flag tutmak gerekir atandığını işaretlemek için. Bir de birden fazla thread bu değişkene erişebileceği için bu erişim kontrollü yapılması yani herhangi bir t anında sadece ve sadece bir thread’in erişmesi için gerekli senkronizasyonun işletilmesi gerekir.</p>

<p>Lazy’nin kullanılması gereken ilginç bir örnek vereyim:</p>

<script src="https://gist.github.com/5989772.js"> </script>

<p><code class="language-plaintext highlighter-rouge">B</code>‘yi ilk kullanmaya çalıştığımızda NPE’yi yeriz. ;) Ama <code class="language-plaintext highlighter-rouge">B</code>‘yi şu şekilde tanımlarsak sorun olmaz:</p>

<script src="https://gist.github.com/5989774.js"> </script>

<p>Bunun nedeni <code class="language-plaintext highlighter-rouge">A</code> sınıfındaki <code class="language-plaintext highlighter-rouge">x</code>‘i <code class="language-plaintext highlighter-rouge">B</code> objesinde <code class="language-plaintext highlighter-rouge">lazy</code> olarak değiştirdik. Artık <code class="language-plaintext highlighter-rouge">x</code>‘e ilk erişildiğinde değeri atanacak. İlk erişildiği nokta ise <code class="language-plaintext highlighter-rouge">A</code> sınıfının başlangıcı (initialization’ı). İlk örnekte,<code class="language-plaintext highlighter-rouge">x</code> daha tanımlanmadığı için yani <code class="language-plaintext highlighter-rouge">B</code> objesi hafızada daha oluşturulmadan <code class="language-plaintext highlighter-rouge">x</code>‘e atama yapılmayacağı için null olarak kalacağından <code class="language-plaintext highlighter-rouge">NPE</code> oluşur.</p>

<p>Son olarak lazy’nin bir de döngüsel (cyclic) bağımlılıklarda nasıl işe yaradığını görelim ve macerayı tamamlayalım. Aşağıda birbirine bağımlı sınıf tanımları var:</p>

<script src="https://gist.github.com/5989780.js"> </script>

<p><code class="language-plaintext highlighter-rouge">B</code> ve <code class="language-plaintext highlighter-rouge">C</code> sınıfları birbirine bağımlı. Bunların başlangıc kod bloklarında ki <code class="language-plaintext highlighter-rouge">val x = ...</code> kısmını <code class="language-plaintext highlighter-rouge">lazy val x = ...</code> şekline dönüştürmezsek <code class="language-plaintext highlighter-rouge">StackOverflowError</code> alırız. Lazy’yi bu örnekte olduğu gibi döngüsel bağımlılıklardan kaynaklanan durumları önlemek için de kullanabiliriz.</p>]]></content><author><name>Yusuf Boyacıgil</name></author><category term="turkish" /><category term="scala" /><summary type="html"><![CDATA[Scala’da değişken/argüman tanımlarken iki tane anahtar kelime var: var ve val. İlki için söylecek çok bir şey yok. Değişken tanımlamak için var’ı kullanmak durumundasın. Ama ikincisi aynı Java’daki final gibi sadece ilk seferinde bir değer atanmasını istediklerini tanımlamaya yarıyor. İkinci defa bir atama yapamıyorsun; aslında program içerisinde böyle sadece bir kere atama yapmaktan ziyade val ile tanımladıkların daha çok sonradan değerinin değiştirilmesini istemediğin değişkenler içindir.]]></summary></entry><entry><title type="html">Scala Nil, Nothing, Null</title><link href="http://www.yboyacigil.com/turkish/scala/scala-nil-nothing-null/" rel="alternate" type="text/html" title="Scala Nil, Nothing, Null" /><published>2013-01-09T14:16:01+00:00</published><updated>2013-01-09T14:16:01+00:00</updated><id>http://www.yboyacigil.com/turkish/scala/scala-nil-nothing-null</id><content type="html" xml:base="http://www.yboyacigil.com/turkish/scala/scala-nil-nothing-null/"><![CDATA[<p>Herşey aşağıdaki gibi bir fonksiyon/metodu anlamaya çalışırken gelişti:</p>

<script src="https://gist.github.com/5990000.js"> </script>

<p>Burada herhangi tipteki nesneyi n kere çoğatıp sonunda o tipte bir liste üreten bir fonkisyon tanımı var.</p>

<script src="https://gist.github.com/5990010.js"> </script>

<p>Yukarıda bu fonksiyonu String tipinde bir nesne ile çağırdığımız zaman elde ettiğimiz sonucu görüyoruz. ;)</p>

<p>Fonksiyon ne yapıyor? <code class="language-plaintext highlighter-rouge">n</code> 0 olana dek <code class="language-plaintext highlighter-rouge">x</code>‘i bir listenin başına ekliyor. <code class="language-plaintext highlighter-rouge">::</code> listeler için tanımlı ve <code class="language-plaintext highlighter-rouge">elm :: list</code> şeklinde kullanılan ve elemanı listenin başına eklemek için tanımlı bir operatördür. Yani:</p>

<script src="https://gist.github.com/5990013.js"> </script>

<p>En sondaki <code class="language-plaintext highlighter-rouge">Nil</code>‘e dikkat! <code class="language-plaintext highlighter-rouge">Nil</code> Java’cı biri için <code class="language-plaintext highlighter-rouge">null</code>‘sa haliyle bu NPE’ye neden olur diye düşündüm ilk olarak. Ama fonksiyon çalıştı. Nasıl? Demek ki <code class="language-plaintext highlighter-rouge">Nil</code> eşittir <code class="language-plaintext highlighter-rouge">null</code> doğru değil. Hadi diyelim Nil null değil. İyi de <code class="language-plaintext highlighter-rouge">::</code> operatörü nasıl çalışıyor? O zaman <code class="language-plaintext highlighter-rouge">type inference</code> diye geçen, derleyicinin burada akıllı bir şekilde Nil’in boş bir liste olacağını anlayıp ona göre bir düzenleme yaptığı geldi aklıma. Ama o da değilmiş!</p>

<p>Scala API dokümanına bakınca, Nil’in boş bir List’e olduğunu gördüm:</p>

<script src="https://gist.github.com/5990016.js"> </script>

<p><code class="language-plaintext highlighter-rouge">Nothing</code>?!! Nothing scala’da tanımlı tüm tiplerin alt tipiymiş. İyi de bu ne demek? Scala’da tüm tipler <code class="language-plaintext highlighter-rouge">scala.Any</code> tipinden geliyor. Java’daki <code class="language-plaintext highlighter-rouge">java.lang.Object</code> gibi. Any’nin iki direkt alt tipi var biri <code class="language-plaintext highlighter-rouge">scala.AnyVal</code> diğeri <code class="language-plaintext highlighter-rouge">scala.AnyRef</code>. İlki Java’daki int, double, float gibi sabit bir değer içeren tipleri, ikincisi de geri kalan diğer tüm tipleri ifade ediyor. <code class="language-plaintext highlighter-rouge">Nothing</code>‘in Any’den gelen diğer tüm tiplerin bir alt tipi olması demek Nothing herhangi tipe referans olarak kullanılabilir demek. Ne var ki Nothing tipinde bir nesne yaratmazsınız. Hiç/hiçlik bilinir ama gösterilemez yani ;)</p>

<p><code class="language-plaintext highlighter-rouge">List[Nothing]</code> de bu durumda herhangi bir tipteki boş liste demektir. Çünkü hem Nothing tüm tiplerin alt tipidir hem de Nothing tipinde bir nesne olamayacağında göre liste boş olmak zorundadır. Bu yüzden de <code class="language-plaintext highlighter-rouge">Nil</code>‘in <code class="language-plaintext highlighter-rouge">List[Nothing]</code> olarak ifade edilmesi ve <code class="language-plaintext highlighter-rouge">List[T]</code> yani <code class="language-plaintext highlighter-rouge">T</code> tipindeki herhangi bir boş liste olması mantıklı hale gelmiş olur.</p>

<script src="https://gist.github.com/5990019.js"> </script>

<p>Yukarıdaki örnekteki <code class="language-plaintext highlighter-rouge">f</code> fonksiyonuna dikkat! Bu metodu hiçbir zaman çağıramazsınız. Zira çağıracak hiçi hiçbir zaman yaratamayacaksınız!</p>

<p>Nothing Scala’da hiç bitmesini istemediğimiz fonksiyonların dönüş tipi olarak kullanılır. Bir fonksiyonun dönüş tipi Nothing ise ve Nothing diye bir nesne üretemeyeceğimize göre bu fonksiyon bu tipte hiçbir değer üretemeyeceği için bitemeyecektir!</p>

<p>Nothing ile ilgili bir başka şey <code class="language-plaintext highlighter-rouge">Null</code> tipinin Nothing’den türemesidir. Null scala’da tanımlı bir başka tiptir ve sadece ama sadece bir objesi (instance’ı) vardır o da null’dur. <code class="language-plaintext highlighter-rouge">null</code> Java’daki null’un aynısıdır hiçbir nesneye referans olmayan bir değeri ifade etmek için kullanılır.</p>

<p>“Nil, Nothing, Null… Bunlara ne gerek vardı?”, “Java’daki gibi null neyinize yetmedi de bunları uydurdunuz?” diyebilirsiniz. Bunlar programlama mantığı açısından bakıldığında hem olması gereken yapılar hem de programlamada düşülen bazı tuzakları önlemek, programcının işini kolaylaştırmak adına iyi bir programlama dilinde olması gereken özellikler.</p>]]></content><author><name>Yusuf Boyacıgil</name></author><category term="turkish" /><category term="scala" /><summary type="html"><![CDATA[Herşey aşağıdaki gibi bir fonksiyon/metodu anlamaya çalışırken gelişti:]]></summary></entry><entry><title type="html">Scala Programlama Dili</title><link href="http://www.yboyacigil.com/turkish/scala/scala-language/" rel="alternate" type="text/html" title="Scala Programlama Dili" /><published>2013-01-05T14:16:01+00:00</published><updated>2013-01-05T14:16:01+00:00</updated><id>http://www.yboyacigil.com/turkish/scala/scala-language</id><content type="html" xml:base="http://www.yboyacigil.com/turkish/scala/scala-language/"><![CDATA[<p>Zamanında bir kitap okumuştum. İsmi: <a href="http://pragprog.com/the-pragmatic-programmer">Pragmatic Programmer</a>. Kapağı da ilginçti. Marangozluktan biraz anlayan bilir kapağında bir rende resmi var. Benim babam marangozdu ben de onun yanında zamanında çıraklık yaptım. Bu resim kanımca programlama bir zanaattır mantığıyla konmuştur ve hakikaten de öyledir. Sanattır diyeni de vardır ama bana göre sanattan çok zanaattır o başka. Herkes babasının oğludur. Ben de bir nevi marangoz gibi zanaatkar insanım, öyle görüyorum kendimi. O bakımdan kitabın kapağıyla da o taraflara yapığı gönderme ayrıyeten anlamlıdır benim için.</p>

<p>Bu kitapta şöyle bir ögüt vardı: “Her sene yeni bir programlama dili öğren!”. Nitekim o öğütü tuttum ve o günden sonra yeni dilleri öğrenmeye çalıştım. Python, erlang, javascript, ruby, smalltalk dillerini çalıştım. Öğrendiğim kadar da unutmuşluğum vardır. Ama yeni bir dile çalışmaya başlayınca programlamaya bakışın, problemlere çözümde yaklaşımın gelişiyor. Aradaki farkları, benzerlikleri görüyorsun; daha yukarıdan bakabiliyorsun. Bu dillerin bir de kendine ait felsefeleri var; anlamaya çalışıyorsun oradan yeni şeyler kapıyorsun. Kesinlikle tavsiye ediyorum herkese. Şöyle bir geçmişe dönüp bakınca bak .net’e (döt net) neden ilgi duymamışım diye de kendime soruyorum şimdi?!! Microsoft’a zamanında gıcıklığımızdan (bugün bunun çok da anlamlı olmadığını anlıyorum) belki uzak kaldım micro$oft’un sunduklarına.</p>

<p>Yeni bir programlama dili öğrenmek kolaydır aslında. İki haftada alışır birşeyler yapamaya muktedir olursun. Ama o dile tam anlamıyla hakim olmak bir seneni alır. O yüzden yavaş yavaş bıkmadan usanmadan; acele etmeden ağır ağır gideceksin. Scala çalışıyorum. Bu seneki dilim bu.</p>

<p>Scala hibrit bir dil. Hibrit? Yani hem fonksiyonel hem de nesneye dönelik yani yönelik :) Scala’nın  daha ilginç yanı kendi derleyicisi var ama Java byte-code üretiyor. Yani JVM üzerinde çalışıyor. Java standart kütüphanesindeki sınıfları ve bilinen tüm Java kütüphanelerini direkt olarak kullanabiliyorsun. Yanında kendi kütüphanesi de var. Kendi kütüphanesi olması gerektiği gibi Java kütüphanesini tamamlıyor onu tekrarlamıyor.</p>

<p>Bugün linkedin, twitter ve foursquare gibi startup’ların kendi geliştirmeleri için kullanıyor olmasıyla  popüler de oldu. Bilinen programlama dilleri listesinde de çok kullanılmasına göre 34. sıraya kadar da yükselmiş ve yine JVM üzerinde geliştirilmiş kendinden eski başka dilleri (mesela: Clojure, Groovy) de geçmiş durumda. Bu açıdan bakıldığında da kötü bir seçim değil yani.</p>

<p>Son olarak Scala ile ilgili olarak fonksiyonel programalama dili olması ve Java’nın sevilmeyen açıklarını kapaması gibi iki konuya değinmek istiyorum.</p>

<h2 id="fonksiyonel-programlama">Fonksiyonel Programlama</h2>

<p>Fonksiyonel programlama aslında uzun zamandır var olan bir programlama stili ve son yıllarda daha çok konuşulmaya başladı. Matematikteki fonksiyon mantığının programlamaya uyarlanmasıdır aslında. Bu programlamanın doğasına da tam oturur. Program dediğin netice itibariyle bir girdiyi alıp onu işleyip bir çıktı üreten şeydir yani bir fonksiyondur. Bir programın tüm parçalarını bu şekilde ifade edebilirsin. Program dediğin bir fonksiyonlar bütünüdür. Scala ile pür fonksiyonel programlama yapmak mümkündür.</p>

<p>Fonksiyonel programlama deyince tabi literatürde geçen “high order functions”, “no state preservation”, “clojure functions” gibi konulara da ileride değiniriz.</p>

<p>Scala aynı zamanda nesneye yönelik programlama için de gerekli olan yapıları barındırır. Bu onu hibrit yapan özelliğidir. Java gibi nesnel programlamaya aşina birine de Scala bu özelliğiyle kapıyı açık tutsa da kanımca, Scala’nın mucitleri o kafadakileri de fonksiyonel programlamaya devşirmek istemiş olabilirler.</p>

<h2 id="javadaki-eksiklikler">Java’daki Eksiklikler</h2>
<p>Java’nın eksiklerini tamamlaması ile ilgili olarak da Java’da çokça şikayet edilen primitive tipleri ortadan kaldırmasıyla dikkate şayandır. Bu şunun için önemlidir: Scala’da herşey nesnedir yani primitive tip yoktur. Bu da primitive’i nesneye, nesneyi primitive dönüştürmek gibi ameli işleri ortadan kaldırdığı gibi aynı zamanda temizlik anlamında da hoştur.</p>

<p>Bir başka konu “operator overloading” diye bilinen C++’çıların Java’da en çok istediği ve belki bu yüzden de çokça eleştirdiği Java’da olmayan bu özelliği eklemiş olmalarıdır. Yani siz herhangi yarattığınız bir tip (sınıf/class) için mesela “+” operatörünü tanımlayabilirsiniz. Yalnız single-inheritance hala var ama o da aslında olmasının bir programlama diline hayır getirdiği oldukça tartışmalı bir konu zaten.</p>

<p>Java’da sıklıkla kullanılan anonymous class’ları da fonksiyonlara havale ederek daha az kod yazarak aynı işi yapabilmesi de bir anlamda sentaks olarak bir temizlik, kolaylık getiriyor.</p>

<p>Scala ile ilgili maceraları daha sonraki yazılara havale ederek burada bitiriyorum. Yeni yılın ilk yazısı olması itibariyle de okuyan herkese iyi seneler dilerim. :)</p>]]></content><author><name>Yusuf Boyacıgil</name></author><category term="turkish" /><category term="scala" /><summary type="html"><![CDATA[Zamanında bir kitap okumuştum. İsmi: Pragmatic Programmer. Kapağı da ilginçti. Marangozluktan biraz anlayan bilir kapağında bir rende resmi var. Benim babam marangozdu ben de onun yanında zamanında çıraklık yaptım. Bu resim kanımca programlama bir zanaattır mantığıyla konmuştur ve hakikaten de öyledir. Sanattır diyeni de vardır ama bana göre sanattan çok zanaattır o başka. Herkes babasının oğludur. Ben de bir nevi marangoz gibi zanaatkar insanım, öyle görüyorum kendimi. O bakımdan kitabın kapağıyla da o taraflara yapığı gönderme ayrıyeten anlamlıdır benim için.]]></summary></entry><entry><title type="html">Twitter Uygulaması Geliştirmek</title><link href="http://www.yboyacigil.com/turkish/twitter-app-dev/" rel="alternate" type="text/html" title="Twitter Uygulaması Geliştirmek" /><published>2012-08-05T14:16:01+00:00</published><updated>2012-08-05T14:16:01+00:00</updated><id>http://www.yboyacigil.com/turkish/twitter-app-dev</id><content type="html" xml:base="http://www.yboyacigil.com/turkish/twitter-app-dev/"><![CDATA[<p>Twitter’ı bilmeyen yoktur farkındayım ama “Twitter Uygulaması” isim tamlamasının ne olduğunu merak edecek birçok kişi çıkacaktır, eminim. O zaman ne demek istediğimi yavaş yavaş açmama izin verin.</p>

<p>Twitter sadece kişinin arkadaşları ve hatta tüm internet alemi ile her seferinde maksimum 140 harften oluşan mesajları paylaşabildiği sosyal bir ortam olması ötesinde; sağladığı alt yapı, ki kendisine “Application Programming Interface (API)” Türkçe olarak “Uygulama Programlama/Geliştirme Arayüzü” de denir, sayesinde kendi ekosistemini zenginleştirecek ek hizmetler geliştirilmesine izin vermektedir. Zaten akıllıca olanı da budur. Neden? Twitter ekosisteminde verilebilecek tüm hizmetleri kendisi yapamaz. Dolayısıyla başkalarının enerji ve yaratıcılığını kullanarak bir kazan-kazan durumu oluşturmak akıllıca bir davranış olur. Mesela, Microsoft’tan Windows işletim sistemi için yazılabilecek tüm programları sağlamasını bekler misiniz? Beklemeye beklersiniz de; Microsoft bunu yapmak ister mi? Konu anlaşıldı sanırım.</p>

<p>İyi de ne gibi uygulamalar geliştirilebilir? Twitter’ın web önyüzü dışında Windows, Mac için geliştirilmiş masaüstü uygulamalarını ilk çırpıda sayabiliriz. (bkz: <a href="http://www.techradar.com/news/internet/22-best-twitter-apps-for-2012-930383">22 best twitter app</a>) Veya web sitenize herhangi bir twitter kullanıcısını kabul edip, sitenizden twitter kullanıcısı adına mesela twit attırabilirsiniz. Onun da ötesinde Twitter’da var olan alt yapıyı zenginleştirecek uygulamalar geliştirilebilir. Örneğin bir süreliğine bazı takip ettiğiniz kişilerin twit’lerini  görmek istemeyebilirsiniz (bkz: <a href="http://twitter-doghouse.herokuapp.com/">Twitter-DogHouse</a>).</p>

<p>Örnekler uzatılabilir ama benim burada asıl anlatmak istediğim şey bir Twitter uygulamasını nasıl geliştireceğiniz konusunda bilgi vermek. Hadi başlayalım:</p>

<ol>
  <li>
    <p><strong>Yeni bir twitter hesabı açın</strong>: Geliştireceğiniz uygulama için bir twitter hesabı açmanız gerekir. Bu hesap, uygulamanızı twitter’a tanıtmak için gerekli olduğu gibi, aynı zamanda uygulamanızı kullanacak kişilerle yine twitter üzerinden haberleşmek imkanı tanıyacaktır. Bu kişiler uygulamanızı kullandıkları gibi twitter üzerinden sizin uygulamanızla ilgili bir takım güncel bilgileri paylaşmanızı sağlayabilir.</p>
  </li>
  <li>
    <p><strong>Uygulamanızı twitter’a kaydedin</strong>: Yeni açtığınız hesap ile giriş yaptıktan sonra uygulamanızı twitter ekosistemine ekleyin (bkz: <a href="https://dev.twitter.com/apps/new">yeni bir uygulama yaratmak</a>). Burada uygulama ile ilgili resim, açıklama, web adresi gibi bilgiler yanında uygulamanın twitter kullanıcısı adına twit atmak, twit’lerine ulaşmak, direkt mesaj atmak gibi neler yapmak isteyeceğini belirtiyorsunuz. Uygulamanızı kaydettikten sonra API’yi kullanmaya başlayabilmeniz için gerekli olan tüketici anahtarı ve şifresi (consumer key &amp; secret) veriliyor sistem tarafından.</p>
  </li>
  <li>
    <p><strong>Twitter API’sini öğrenin</strong>: Twitter API’si ile neler yapabileceğinizi  öğrenin (bkz: <a href="https://dev.twitter.com/console">Exploring the twitter API</a>). <a href="https://dev.twitter.com/docs">Dokümanları</a> karıştırın. Sizin öğrenme metodunuzu bilmem ama baştan sonra tüm dokümanları okumanızı tavsiye etmem. Herşeyi bir anda öğrenmeye kalkışmayın. Çabuk tükenirsiniz. Büyük resmi anlamaya çalışın, detaylara gerektiği zaman girersiniz. Üstelik herhangi bir konu kafanıza mı takıldı; hz. google’a sorun o sizi doğru yere yönlendirecektir. Sorunuzun cevabını bulamadığınız zaman <a href="http://www.stackoverflow.com/">stackoverflow</a> ve twitter dev gruplarına (bkz: <a href="https://groups.google.com/forum/?fromgroups#!forum/twitter-development-talk">Twitter Dev Talk</a>) sorun.</p>
  </li>
  <li>
    <p><strong>Twitter API’sini nasıl kullanacağınızı öğrenin</strong>: Uygulamanızı kullanacak olan twitter kullanıcıları adına API çağrıları yapmadan önce kullanıcıların size yetki vermesi gerekir. Twitter bunun için <a href="https://dev.twitter.com/docs/auth/oauth">OAuth</a> yetkilendirme mekanizmasını kullanmanızı şart koşuyor.</p>
  </li>
</ol>

<p>OAuth, Twitter gibi kullanıcıları adına işlem yaptıran platformlarda kullanılan güvenli ve standart bir yetkilendirme mekanizmasıdır. OAuth hiçbir şekilde kullanıcıların şifresini üçüncü partilerle paylaşmadığı için güvenlidir. OAuth standart olduğu için şimdiye kadar geliştirilmiş olan istemci  kütüphanelerini (client libraries) uygulamanızda kullanabilir ve destek alabilirsiniz.</p>

<p>Twitter’da OAuth ile kullanıcı adına işlem yapabilmeniz için:</p>

<ol>
  <li>Erişim için bir anahtar almanız,</li>
  <li>Tüm API çağrılarını aldığınız bu anahtar ile işaretlemeniz</li>
</ol>

<p>gerekecektir.</p>

<p>Bunlar ile ilgili teknik detaylar için bkz: <a href="https://dev.twitter.com/docs/auth/using-oauth">OAuth’u kullanmak</a>.</p>

<p>Tabi hepsinden önce Twitter ekosistemine nasıl bir servis hazırlayarak katkıda bulunacağınızı bilmeniz gerekir. Bu sizin hayal gücünüze ve Twitter API’si ile neler yapabileceğinizi bilmenize kalıyor.</p>]]></content><author><name>Yusuf Boyacıgil</name></author><category term="turkish" /><summary type="html"><![CDATA[Twitter’ı bilmeyen yoktur farkındayım ama “Twitter Uygulaması” isim tamlamasının ne olduğunu merak edecek birçok kişi çıkacaktır, eminim. O zaman ne demek istediğimi yavaş yavaş açmama izin verin.]]></summary></entry></feed>